about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md9
-rw-r--r--Makefile.in15
-rw-r--r--README.md14
-rwxr-xr-xconfigure8
-rw-r--r--mk/crates.mk6
-rw-r--r--mk/tests.mk1
-rw-r--r--src/bootstrap/build/cc.rs4
-rw-r--r--src/bootstrap/build/mod.rs8
-rw-r--r--src/bootstrap/build/sanity.rs4
-rw-r--r--src/build_helper/lib.rs12
-rw-r--r--src/doc/book/error-handling.md20
-rw-r--r--src/doc/book/functions.md2
-rw-r--r--src/doc/book/loops.md2
-rw-r--r--src/doc/book/no-stdlib.md24
-rw-r--r--src/doc/book/primitive-types.md2
-rw-r--r--src/doc/book/references-and-borrowing.md2
-rw-r--r--src/doc/book/slice-patterns.md6
-rw-r--r--src/doc/book/testing.md14
-rw-r--r--src/doc/book/variable-bindings.md18
-rw-r--r--src/doc/nomicon/safe-unsafe-meaning.md251
-rw-r--r--src/doc/reference.md5
-rw-r--r--src/doc/rust.css2
-rw-r--r--src/liballoc/rc.rs2
-rw-r--r--src/liballoc_jemalloc/build.rs32
-rw-r--r--src/liballoc_jemalloc/lib.rs11
-rw-r--r--src/libcollections/btree/map.rs512
-rw-r--r--src/libcollections/btree/set.rs4
-rw-r--r--src/libcollections/lib.rs2
-rw-r--r--src/libcollections/str.rs4
-rw-r--r--src/libcollectionstest/str.rs30
-rw-r--r--src/libcore/any.rs2
-rw-r--r--src/libcore/iter/iterator.rs3
-rw-r--r--src/libcore/iter/mod.rs185
-rw-r--r--src/libcore/iter_private.rs27
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/ops.rs12
-rw-r--r--src/libcore/slice.rs15
-rw-r--r--src/libcore/sync/atomic.rs6
-rw-r--r--src/libcoretest/iter.rs31
-rw-r--r--src/libflate/lib.rs10
-rw-r--r--src/libpanic_unwind/dwarf/eh.rs75
-rw-r--r--src/libpanic_unwind/dwarf/mod.rs30
-rw-r--r--src/libpanic_unwind/gcc.rs166
-rw-r--r--src/libpanic_unwind/lib.rs12
-rw-r--r--src/libpanic_unwind/seh.rs9
-rw-r--r--src/libpanic_unwind/seh64_gnu.rs41
-rw-r--r--src/libpanic_unwind/windows.rs12
-rw-r--r--src/librustc/cfg/construct.rs4
-rw-r--r--src/librustc/diagnostics.rs52
-rw-r--r--src/librustc/hir/def.rs24
-rw-r--r--src/librustc/hir/lowering.rs41
-rw-r--r--src/librustc/hir/mod.rs4
-rw-r--r--src/librustc/hir/pat_util.rs10
-rw-r--r--src/librustc/hir/print.rs44
-rw-r--r--src/librustc/infer/combine.rs6
-rw-r--r--src/librustc/infer/error_reporting.rs28
-rw-r--r--src/librustc/infer/freshen.rs9
-rw-r--r--src/librustc/infer/region_inference/mod.rs8
-rw-r--r--src/librustc/lib.rs3
-rw-r--r--src/librustc/middle/astconv_util.rs8
-rw-r--r--src/librustc/middle/dead.rs83
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs52
-rw-r--r--src/librustc/middle/intrinsicck.rs2
-rw-r--r--src/librustc/middle/liveness.rs12
-rw-r--r--src/librustc/middle/mem_categorization.rs154
-rw-r--r--src/librustc/middle/reachable.rs8
-rw-r--r--src/librustc/middle/resolve_lifetime.rs3
-rw-r--r--src/librustc/middle/stability.rs12
-rw-r--r--src/librustc/mir/cache.rs69
-rw-r--r--src/librustc/mir/repr.rs296
-rw-r--r--src/librustc/mir/tcx.rs21
-rw-r--r--src/librustc/mir/transform.rs73
-rw-r--r--src/librustc/mir/traversal.rs (renamed from src/librustc_mir/traversal.rs)25
-rw-r--r--src/librustc/mir/visit.rs102
-rw-r--r--src/librustc/session/config.rs8
-rw-r--r--src/librustc/session/mod.rs3
-rw-r--r--src/librustc/ty/flags.rs2
-rw-r--r--src/librustc/ty/fold.rs12
-rw-r--r--src/librustc/ty/layout.rs20
-rw-r--r--src/librustc/ty/mod.rs57
-rw-r--r--src/librustc/ty/sty.rs10
-rw-r--r--src/librustc/ty/subst.rs2
-rw-r--r--src/librustc/ty/util.rs2
-rw-r--r--src/librustc/util/common.rs12
-rw-r--r--src/librustc/util/ppaux.rs54
-rw-r--r--src/librustc_bitflags/lib.rs4
-rw-r--r--src/librustc_borrowck/Cargo.toml1
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs15
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs3
-rw-r--r--src/librustc_borrowck/borrowck/mir/abs_domain.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs18
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/impls.rs15
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/mod.rs16
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs15
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs100
-rw-r--r--src/librustc_borrowck/borrowck/mir/gather_moves.rs134
-rw-r--r--src/librustc_borrowck/borrowck/mir/mod.rs69
-rw-r--r--src/librustc_borrowck/borrowck/mir/patch.rs77
-rw-r--r--src/librustc_borrowck/diagnostics.rs105
-rw-r--r--src/librustc_borrowck/indexed_set.rs18
-rw-r--r--src/librustc_borrowck/lib.rs1
-rw-r--r--src/librustc_const_eval/check_match.rs303
-rw-r--r--src/librustc_const_eval/eval.rs64
-rw-r--r--src/librustc_const_math/is.rs11
-rw-r--r--src/librustc_const_math/us.rs11
-rw-r--r--src/librustc_data_structures/bitvec.rs16
-rw-r--r--src/librustc_data_structures/indexed_vec.rs228
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/tuple_slice.rs26
-rw-r--r--src/librustc_driver/driver.rs101
-rw-r--r--src/librustc_lint/bad_style.rs5
-rw-r--r--src/librustc_lint/builtin.rs33
-rw-r--r--src/librustc_lint/types.rs7
-rw-r--r--src/librustc_llvm/lib.rs15
-rw-r--r--src/librustc_metadata/astencode.rs7
-rw-r--r--src/librustc_metadata/creader.rs45
-rw-r--r--src/librustc_metadata/macro_import.rs75
-rw-r--r--src/librustc_metadata/tydecode.rs9
-rw-r--r--src/librustc_metadata/tyencode.rs3
-rw-r--r--src/librustc_mir/build/block.rs43
-rw-r--r--src/librustc_mir/build/cfg.rs36
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs12
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs24
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs6
-rw-r--r--src/librustc_mir/build/expr/into.rs53
-rw-r--r--src/librustc_mir/build/expr/stmt.rs13
-rw-r--r--src/librustc_mir/build/matches/mod.rs242
-rw-r--r--src/librustc_mir/build/matches/simplify.rs43
-rw-r--r--src/librustc_mir/build/matches/test.rs189
-rw-r--r--src/librustc_mir/build/matches/util.rs73
-rw-r--r--src/librustc_mir/build/misc.rs16
-rw-r--r--src/librustc_mir/build/mod.rs137
-rw-r--r--src/librustc_mir/build/scope.rs236
-rw-r--r--src/librustc_mir/graphviz.rs16
-rw-r--r--src/librustc_mir/hair/cx/expr.rs39
-rw-r--r--src/librustc_mir/hair/cx/mod.rs1
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs35
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/pretty.rs173
-rw-r--r--src/librustc_mir/transform/add_call_guards.rs40
-rw-r--r--src/librustc_mir/transform/dump_mir.rs60
-rw-r--r--src/librustc_mir/transform/mod.rs2
-rw-r--r--src/librustc_mir/transform/no_landing_pads.rs1
-rw-r--r--src/librustc_mir/transform/promote_consts.rs131
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs74
-rw-r--r--src/librustc_mir/transform/remove_dead_blocks.rs86
-rw-r--r--src/librustc_mir/transform/simplify_branches.rs66
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs346
-rw-r--r--src/librustc_mir/transform/type_check.rs42
-rw-r--r--src/librustc_passes/consts.rs24
-rw-r--r--src/librustc_plugin/Cargo.toml1
-rw-r--r--src/librustc_plugin/lib.rs1
-rw-r--r--src/librustc_privacy/diagnostics.rs10
-rw-r--r--src/librustc_privacy/lib.rs29
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs11
-rw-r--r--src/librustc_resolve/diagnostics.rs165
-rw-r--r--src/librustc_resolve/lib.rs847
-rw-r--r--src/librustc_resolve/resolve_imports.rs15
-rw-r--r--src/librustc_save_analysis/data.rs19
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs107
-rw-r--r--src/librustc_save_analysis/external_data.rs20
-rw-r--r--src/librustc_save_analysis/json_dumper.rs47
-rw-r--r--src/librustc_save_analysis/lib.rs19
-rw-r--r--src/librustc_save_analysis/span_utils.rs2
-rw-r--r--src/librustc_trans/Cargo.toml1
-rw-r--r--src/librustc_trans/_match.rs48
-rw-r--r--src/librustc_trans/abi.rs68
-rw-r--r--src/librustc_trans/back/archive.rs256
-rw-r--r--src/librustc_trans/back/link.rs12
-rw-r--r--src/librustc_trans/base.rs118
-rw-r--r--src/librustc_trans/callee.rs58
-rw-r--r--src/librustc_trans/closure.rs6
-rw-r--r--src/librustc_trans/common.rs12
-rw-r--r--src/librustc_trans/consts.rs14
-rw-r--r--src/librustc_trans/context.rs42
-rw-r--r--src/librustc_trans/controlflow.rs4
-rw-r--r--src/librustc_trans/debuginfo/create_scope_map.rs44
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs25
-rw-r--r--src/librustc_trans/debuginfo/mod.rs7
-rw-r--r--src/librustc_trans/debuginfo/namespace.rs2
-rw-r--r--src/librustc_trans/expr.rs12
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/meth.rs2
-rw-r--r--src/librustc_trans/mir/analyze.rs176
-rw-r--r--src/librustc_trans/mir/block.rs278
-rw-r--r--src/librustc_trans/mir/constant.rs102
-rw-r--r--src/librustc_trans/mir/lvalue.rs186
-rw-r--r--src/librustc_trans/mir/mod.rs244
-rw-r--r--src/librustc_trans/mir/operand.rs95
-rw-r--r--src/librustc_trans/mir/rvalue.rs26
-rw-r--r--src/librustc_trans/mir/statement.rs60
-rw-r--r--src/librustc_trans/monomorphize.rs11
-rw-r--r--src/librustc_typeck/astconv.rs30
-rw-r--r--src/librustc_typeck/check/_match.rs187
-rw-r--r--src/librustc_typeck/check/callee.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs110
-rw-r--r--src/librustc_typeck/check/regionck.rs14
-rw-r--r--src/librustc_typeck/collect.rs16
-rw-r--r--src/librustc_typeck/diagnostics.rs15
-rw-r--r--src/librustc_typeck/lib.rs10
-rw-r--r--src/librustc_typeck/variance/constraints.rs2
-rw-r--r--src/librustc_unicode/char.rs24
-rw-r--r--src/librustdoc/clean/inline.rs13
-rw-r--r--src/librustdoc/clean/mod.rs11
-rw-r--r--src/librustdoc/html/format.rs7
-rw-r--r--src/librustdoc/html/highlight.rs6
-rw-r--r--src/librustdoc/html/markdown.rs55
-rw-r--r--src/librustdoc/html/render.rs121
-rw-r--r--src/librustdoc/html/static/rustdoc.css6
-rw-r--r--src/librustdoc/test.rs26
-rw-r--r--src/librustdoc/visit_ast.rs10
-rw-r--r--src/libstd/build.rs3
-rw-r--r--src/libstd/collections/hash/map.rs13
-rw-r--r--src/libstd/collections/hash/table.rs345
-rw-r--r--src/libstd/collections/mod.rs6
-rw-r--r--src/libstd/fs.rs11
-rw-r--r--src/libstd/lib.rs12
-rw-r--r--src/libstd/net/ip.rs55
-rw-r--r--src/libstd/process.rs23
-rw-r--r--src/libstd/sync/mpsc/spsc_queue.rs13
-rw-r--r--src/libstd/sys/common/wtf8.rs8
-rw-r--r--src/libstd/sys/windows/c.rs1
-rw-r--r--src/libstd/sys/windows/fs.rs6
-rw-r--r--src/libstd/sys/windows/mod.rs1
-rw-r--r--src/libstd/thread/mod.rs29
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/attr.rs33
-rw-r--r--src/libsyntax/codemap.rs67
-rw-r--r--src/libsyntax/config.rs161
-rw-r--r--src/libsyntax/errors/emitter.rs10
-rw-r--r--src/libsyntax/errors/snippet/test.rs28
-rw-r--r--src/libsyntax/ext/base.rs51
-rw-r--r--src/libsyntax/ext/expand.rs167
-rw-r--r--src/libsyntax/ext/source_util.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs251
-rw-r--r--src/libsyntax/feature_gate.rs91
-rw-r--r--src/libsyntax/parse/lexer/comments.rs2
-rw-r--r--src/libsyntax/parse/lexer/mod.rs2
-rw-r--r--src/libsyntax/parse/mod.rs2
-rw-r--r--src/libsyntax/parse/parser.rs21
-rw-r--r--src/libsyntax/print/pprust.rs1751
-rw-r--r--src/libsyntax/std_inject.rs172
-rw-r--r--src/libsyntax/test.rs21
-rw-r--r--src/libsyntax/util/interner.rs10
-rw-r--r--src/libsyntax/util/parser_testing.rs2
-rw-r--r--src/libsyntax/util/small_vector.rs19
-rw-r--r--src/libsyntax/visit.rs6
-rw-r--r--src/libsyntax_ext/cfg.rs9
-rw-r--r--src/rtstartup/rsbegin.rs8
-rw-r--r--src/rtstartup/rsend.rs3
-rw-r--r--src/rustc/Cargo.lock3
-rw-r--r--src/rustllvm/ArchiveWrapper.cpp28
-rw-r--r--src/rustllvm/ExecutionEngineWrapper.cpp5
-rw-r--r--src/rustllvm/PassWrapper.cpp53
-rw-r--r--src/rustllvm/RustWrapper.cpp143
-rw-r--r--src/test/codegen-units/item-collection/generic-impl.rs2
-rw-r--r--src/test/codegen/issue-32031.rs33
-rw-r--r--src/test/codegen/issue-32364.rs24
-rw-r--r--src/test/codegen/loads.rs3
-rw-r--r--src/test/codegen/naked-functions.rs4
-rw-r--r--src/test/codegen/stores.rs16
-rw-r--r--src/test/codegen/zip.rs22
-rw-r--r--src/test/compile-fail-fulldeps/issue-18986.rs3
-rw-r--r--src/test/compile-fail-fulldeps/qquote.rs3
-rw-r--r--src/test/compile-fail/associated-const-private-impl.rs2
-rw-r--r--src/test/compile-fail/bad-format-args.rs22
-rw-r--r--src/test/compile-fail/blind-item-block-middle.rs2
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs8
-rw-r--r--src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs6
-rw-r--r--src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs2
-rw-r--r--src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs2
-rw-r--r--src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs15
-rw-r--r--src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs2
-rw-r--r--src/test/compile-fail/cfg-non-opt-expr.rs2
-rw-r--r--src/test/compile-fail/const-pattern-irrefutable.rs12
-rw-r--r--src/test/compile-fail/custom_attribute.rs7
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-2.rs4
-rw-r--r--src/test/compile-fail/enum-in-scope.rs2
-rw-r--r--src/test/compile-fail/enums-pats-not-idents.rs5
-rw-r--r--src/test/compile-fail/ifmt-bad-arg.rs4
-rw-r--r--src/test/compile-fail/issue-10200.rs2
-rw-r--r--src/test/compile-fail/issue-12369.rs8
-rw-r--r--src/test/compile-fail/issue-12567.rs12
-rw-r--r--src/test/compile-fail/issue-12863.rs2
-rw-r--r--src/test/compile-fail/issue-13482-2.rs6
-rw-r--r--src/test/compile-fail/issue-13482.rs6
-rw-r--r--src/test/compile-fail/issue-13727.rs22
-rw-r--r--src/test/compile-fail/issue-15381.rs4
-rw-r--r--src/test/compile-fail/issue-16149.rs2
-rw-r--r--src/test/compile-fail/issue-17405.rs3
-rw-r--r--src/test/compile-fail/issue-17718-const-privacy.rs4
-rw-r--r--src/test/compile-fail/issue-17718-patterns.rs4
-rw-r--r--src/test/compile-fail/issue-17933.rs2
-rw-r--r--src/test/compile-fail/issue-18819.rs1
-rw-r--r--src/test/compile-fail/issue-22434.rs18
-rw-r--r--src/test/compile-fail/issue-23122-1.rs22
-rw-r--r--src/test/compile-fail/issue-23122-2.rs22
-rw-r--r--src/test/compile-fail/issue-23716.rs12
-rw-r--r--src/test/compile-fail/issue-25579.rs27
-rw-r--r--src/test/compile-fail/issue-26459.rs3
-rw-r--r--src/test/compile-fail/issue-26548.rs3
-rw-r--r--src/test/compile-fail/issue-27033.rs4
-rw-r--r--src/test/compile-fail/issue-27815.rs6
-rw-r--r--src/test/compile-fail/issue-28992-empty.rs2
-rw-r--r--src/test/compile-fail/issue-30240.rs21
-rw-r--r--src/test/compile-fail/issue-3044.rs1
-rw-r--r--src/test/compile-fail/issue-30715.rs33
-rw-r--r--src/test/compile-fail/issue-32086.rs17
-rw-r--r--src/test/compile-fail/issue-32950.rs18
-rw-r--r--src/test/compile-fail/issue-33293.rs16
-rw-r--r--src/test/compile-fail/issue-34047.rs19
-rw-r--r--src/test/compile-fail/issue-34171.rs21
-rw-r--r--src/test/compile-fail/issue-34194.rs21
-rw-r--r--src/test/compile-fail/issue-34334.rs15
-rw-r--r--src/test/compile-fail/issue-4935.rs1
-rw-r--r--src/test/compile-fail/issue-5927.rs2
-rw-r--r--src/test/compile-fail/macro-backtrace-println.rs8
-rw-r--r--src/test/compile-fail/macro-follow.rs22
-rw-r--r--src/test/compile-fail/macro-use-scope.rs32
-rw-r--r--src/test/compile-fail/macros-nonfatal-errors.rs1
-rw-r--r--src/test/compile-fail/match-vec-mismatch-2.rs5
-rw-r--r--src/test/compile-fail/match-vec-mismatch.rs33
-rw-r--r--src/test/compile-fail/match-vec-unreachable.rs8
-rw-r--r--src/test/compile-fail/method-call-err-msg.rs3
-rw-r--r--src/test/compile-fail/method-resolvable-path-in-pattern.rs2
-rw-r--r--src/test/compile-fail/name-clash-nullary.rs5
-rw-r--r--src/test/compile-fail/nested-cfg-attrs.rs14
-rw-r--r--src/test/compile-fail/no-warn-on-field-replace-issue-34101.rs56
-rw-r--r--src/test/compile-fail/non-exhaustive-match-nested.rs10
-rw-r--r--src/test/compile-fail/non-exhaustive-match.rs22
-rw-r--r--src/test/compile-fail/non-exhaustive-pattern-witness.rs4
-rw-r--r--src/test/compile-fail/non-interger-atomic.rs8
-rw-r--r--src/test/compile-fail/not-enough-arguments.rs1
-rw-r--r--src/test/compile-fail/overloaded-calls-bad.rs8
-rw-r--r--src/test/compile-fail/pat-shadow-in-nested-binding.rs2
-rw-r--r--src/test/compile-fail/pat-slice-old-style.rs22
-rw-r--r--src/test/compile-fail/qualified-path-params.rs2
-rw-r--r--src/test/compile-fail/range_traits-1.rs93
-rw-r--r--src/test/compile-fail/range_traits-2.rs17
-rw-r--r--src/test/compile-fail/range_traits-3.rs17
-rw-r--r--src/test/compile-fail/range_traits-4.rs20
-rw-r--r--src/test/compile-fail/range_traits-5.rs20
-rw-r--r--src/test/compile-fail/range_traits-6.rs19
-rw-r--r--src/test/compile-fail/range_traits-7.rs20
-rw-r--r--src/test/compile-fail/static-mut-not-pat.rs4
-rw-r--r--src/test/compile-fail/trace_macros-gate.rs5
-rw-r--r--src/test/compile-fail/trait-impl-for-module.rs2
-rw-r--r--src/test/compile-fail/variadic-ffi-3.rs2
-rw-r--r--src/test/debuginfo/function-arg-initialization.rs8
-rw-r--r--src/test/debuginfo/function-prologue-stepping-no-stack-check.rs13
-rw-r--r--src/test/pretty/attr-variant-data.rs51
-rw-r--r--src/test/run-fail-fulldeps/qquote.rs4
-rw-r--r--src/test/run-fail/args-panic.rs8
-rw-r--r--src/test/run-fail/assert-eq-macro-panic.rs2
-rw-r--r--src/test/run-fail/binop-fail-3.rs4
-rw-r--r--src/test/run-fail/binop-panic.rs9
-rw-r--r--src/test/run-fail/bug-2470-bounds-check-overflow.rs4
-rw-r--r--src/test/run-fail/bug-811.rs12
-rw-r--r--src/test/run-fail/doublepanic.rs2
-rw-r--r--src/test/run-fail/explicit-panic-msg.rs4
-rw-r--r--src/test/run-fail/explicit-panic.rs4
-rw-r--r--src/test/run-fail/expr-fn-panic.rs8
-rw-r--r--src/test/run-fail/expr-if-panic-fn.rs17
-rw-r--r--src/test/run-fail/expr-if-panic.rs10
-rw-r--r--src/test/run-fail/expr-match-panic-fn.rs16
-rw-r--r--src/test/run-fail/expr-match-panic.rs7
-rw-r--r--src/test/run-fail/for-each-loop-panic.rs6
-rw-r--r--src/test/run-fail/if-check-panic.rs10
-rw-r--r--src/test/run-fail/if-cond-bot.rs10
-rw-r--r--src/test/run-fail/issue-12920.rs3
-rw-r--r--src/test/run-fail/issue-18576.rs2
-rw-r--r--src/test/run-fail/issue-20971.rs9
-rw-r--r--src/test/run-fail/issue-2444.rs10
-rw-r--r--src/test/run-fail/issue-28934.rs9
-rw-r--r--src/test/run-fail/issue-3029.rs2
-rw-r--r--src/test/run-fail/issue-6458-1.rs4
-rw-r--r--src/test/run-fail/issue-948.rs9
-rw-r--r--src/test/run-fail/match-bot-panic.rs8
-rw-r--r--src/test/run-fail/match-disc-bot.rs15
-rw-r--r--src/test/run-fail/match-wildcards.rs16
-rw-r--r--src/test/run-fail/meta-revision-bad.rs14
-rw-r--r--src/test/run-fail/meta-revision-ok.rs14
-rw-r--r--src/test/run-fail/mir_dynamic_drops_1.rs2
-rw-r--r--src/test/run-fail/mir_dynamic_drops_2.rs2
-rw-r--r--src/test/run-fail/mir_dynamic_drops_3.rs2
-rw-r--r--src/test/run-fail/panic-arg.rs8
-rw-r--r--src/test/run-fail/panic-macro-any.rs2
-rw-r--r--src/test/run-fail/panic-main.rs4
-rw-r--r--src/test/run-fail/panic-parens.rs14
-rw-r--r--src/test/run-fail/panic-task-name-none.rs7
-rw-r--r--src/test/run-fail/panic-task-name-owned.rs13
-rw-r--r--src/test/run-fail/panic.rs4
-rw-r--r--src/test/run-fail/result-get-panic.rs2
-rw-r--r--src/test/run-fail/rhs-type.rs6
-rw-r--r--src/test/run-fail/run-unexported-tests.rs6
-rw-r--r--src/test/run-fail/unimplemented-macro-panic.rs4
-rw-r--r--src/test/run-fail/unique-panic.rs4
-rw-r--r--src/test/run-fail/unreachable-macro-panic.rs4
-rw-r--r--src/test/run-fail/unreachable-static-msg.rs4
-rw-r--r--src/test/run-fail/unreachable.rs4
-rw-r--r--src/test/run-fail/unwind-interleaved.rs10
-rw-r--r--src/test/run-fail/unwind-rec.rs8
-rw-r--r--src/test/run-fail/unwind-rec2.rs9
-rw-r--r--src/test/run-fail/vec-overrun.rs2
-rw-r--r--src/test/run-fail/while-body-panics.rs9
-rw-r--r--src/test/run-fail/while-panic.rs7
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs1
-rw-r--r--src/test/run-pass-fulldeps/qquote.rs4
-rw-r--r--src/test/run-pass/issue-15080.rs6
-rw-r--r--src/test/run-pass/issue-15104.rs4
-rw-r--r--src/test/run-pass/issue-16648.rs7
-rw-r--r--src/test/run-pass/issue-21058.rs2
-rw-r--r--src/test/run-pass/issue-23477.rs23
-rw-r--r--src/test/run-pass/issue-30240.rs23
-rw-r--r--src/test/run-pass/issue-30276.rs14
-rw-r--r--src/test/run-pass/issue-34074.rs18
-rw-r--r--src/test/run-pass/issue-7784.rs2
-rw-r--r--src/test/run-pass/match-unsized.rs18
-rw-r--r--src/test/run-pass/match-vec-alternatives.rs40
-rw-r--r--src/test/run-pass/mir_constval_adts.rs14
-rw-r--r--src/test/run-pass/mir_trans_calls.rs27
-rw-r--r--src/test/run-pass/vec-matching-fold.rs24
-rw-r--r--src/test/run-pass/vec-matching-legal-tail-element-borrow.rs5
-rw-r--r--src/test/run-pass/vec-matching.rs77
-rw-r--r--src/test/run-pass/vec-tail-matching.rs22
-rw-r--r--src/test/run-pass/zero_sized_subslice_match.rs5
-rw-r--r--src/test/rustdoc/deprecated-impls.rs128
-rw-r--r--src/test/rustdoc/inline_cross/hidden-use.rs22
-rw-r--r--src/test/rustdoc/inline_local/hidden-use.rs20
-rw-r--r--src/test/rustdoc/issue-34025.rs22
-rw-r--r--src/test/rustdoc/redirect-const.rs23
-rw-r--r--src/test/rustdoc/redirect-rename.rs32
-rw-r--r--src/tools/cargotest/main.rs76
-rw-r--r--src/tools/linkchecker/main.rs67
437 files changed, 8839 insertions, 7766 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 495d7e46baa..60935770781 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -108,7 +108,8 @@ root.
 There are large number of options accepted by this script to alter the
 configuration used later in the build process. Some options to note:
 
-- `--enable-debug` - Build a debug version of the compiler (disables optimizations)
+- `--enable-debug` - Build a debug version of the compiler (disables optimizations,
+    which speeds up compilation of stage1 rustc)
 - `--enable-optimize` - Enable optimizations (can be used with `--enable-debug`
     to make a debug build with optimizations)
 - `--disable-valgrind-rpass` - Don't run tests with valgrind
@@ -128,6 +129,12 @@ Some common make targets are:
   cases we don't need to build the stage2 compiler, so we can save time by not
   building it. The stage1 compiler is a fully functioning compiler and
   (probably) will be enough to determine if your change works as expected.
+- `make $host/stage1/bin/rustc` - Where $host is a target triple like x86_64-unknown-linux-gnu.
+  This will build just rustc, without libstd. This is the fastest way to recompile after
+  you changed only rustc source code. Note however that the resulting rustc binary
+  won't have a stdlib to link against by default. You can build libstd once with
+  `make rustc-stage1`, rustc will pick it up afterwards. libstd is only guaranteed to
+  work if recompiled, so if there are any issues recompile it.
 - `make check` - build the full compiler & run all tests (takes a while). This
   is what gets run by the continuous integration system against your pull
   request. You should run this before submitting to make sure your tests pass
diff --git a/Makefile.in b/Makefile.in
index 9d8fdd0de62..9e87ce1d9e6 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -62,6 +62,8 @@
 #   * tidy - Basic style check, show highest rustc error code and
 #     the status of language and lib features
 #   * rustc-stage$(stage) - Only build up to a specific stage
+#   * $host/stage1/bin/rustc - Only build stage1 rustc, not libstd. For further
+#     information see "Rust recipes for build system success" below.
 #
 # Then mix in some of these environment variables to harness the
 # ultimate power of The Rust Build System.
@@ -93,6 +95,15 @@
 #     // Modifying libstd? Use this command to run unit tests just on your change
 #     make check-stage1-std NO_REBUILD=1 NO_BENCH=1
 #
+#     // Modifying just rustc?
+#     // Compile rustc+libstd once
+#     make rustc-stage1
+#     // From now on use this command to rebuild just rustc and reuse the previously built libstd
+#     // $host is a target triple, eg. x86_64-unknown-linux-gnu
+#     // The resulting binary is located at $host/stage1/bin/rustc.
+#     // If there are any issues with libstd recompile it with the command above.
+#     make $host/stage1/bin/rustc
+#
 #     // Added a run-pass test? Use this to test running your test
 #     make check-stage1-rpass TESTNAME=my-shiny-new-test
 #
@@ -266,7 +277,9 @@ endif
 
 # CTAGS building
 ifneq ($(strip $(findstring TAGS.emacs,$(MAKECMDGOALS)) \
-               $(findstring TAGS.vi,$(MAKECMDGOALS))),)
+               $(findstring TAGS.vi,$(MAKECMDGOALS)) \
+               $(findstring TAGS.rustc.emacs,$(MAKECMDGOALS)) \
+               $(findstring TAGS.rustc.vi,$(MAKECMDGOALS))),)
   CFG_INFO := $(info cfg: including ctags rules)
   include $(CFG_SRC_DIR)mk/ctags.mk
 endif
diff --git a/README.md b/README.md
index 4e476b4f357..bc41e62b36a 100644
--- a/README.md
+++ b/README.md
@@ -75,13 +75,13 @@ build.
    $ pacman -Sy pacman-mirrors
    ```
 
-Download [MinGW from
-here](http://mingw-w64.org/doku.php/download/mingw-builds), and choose the
-`version=4.9.x,threads=win32,exceptions=dwarf/seh` flavor when installing. Also, make sure to install to a path without spaces in it. After installing,
-add its `bin` directory to your `PATH`. This is due to [#28260](https://github.com/rust-lang/rust/issues/28260), in the future,
-installing from pacman should be just fine.
+   Download [MinGW from
+   here](http://mingw-w64.org/doku.php/download/mingw-builds), and choose the
+   `version=4.9.x,threads=win32,exceptions=dwarf/seh` flavor when installing. Also, make sure to install to a path without spaces in it. After installing,
+   add its `bin` directory to your `PATH`. This is due to [#28260](https://github.com/rust-lang/rust/issues/28260), in the future,
+   installing from pacman should be just fine.
 
-   ```
+   ```sh
    # Make git available in MSYS2 (if not already available on path)
    $ pacman -S git
 
@@ -90,6 +90,8 @@ installing from pacman should be just fine.
 
 3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed
    MSYS2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust.
+   (As of the latest version of MSYS2 you have to run `msys2_shell.cmd -mingw32`
+   or `msys2_shell.cmd -mingw64` from the command line instead)
 
 4. Navigate to Rust's source code, configure and build it:
 
diff --git a/configure b/configure
index a36362e0ada..b2334740f93 100755
--- a/configure
+++ b/configure
@@ -594,7 +594,7 @@ opt docs     1 "build standard library documentation"
 opt compiler-docs     0 "build compiler documentation"
 opt optimize-tests 1 "build tests with optimizations"
 opt debuginfo-tests 0 "build tests with debugger metadata"
-opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang"
+opt libcpp 1 "build llvm with libc++ instead of libstdc++ when using clang"
 opt llvm-assertions 0 "build LLVM with assertions"
 opt debug-assertions 0 "build with debugging assertions"
 opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
@@ -988,11 +988,11 @@ then
     LLVM_VERSION=$($LLVM_CONFIG --version)
 
     case $LLVM_VERSION in
-        (3.[6-8]*)
+        (3.[7-8]*)
             msg "found ok version of LLVM: $LLVM_VERSION"
             ;;
         (*)
-            err "bad LLVM version: $LLVM_VERSION, need >=3.6"
+            err "bad LLVM version: $LLVM_VERSION, need >=3.7"
             ;;
     esac
 fi
@@ -1053,7 +1053,7 @@ then
         if [ -n "$CFG_OSX_CLANG_VERSION" ]
         then
             case $CFG_OSX_CLANG_VERSION in
-                (7.0* | 7.1* | 7.2* | 7.3*)
+                (7.0* | 7.1* | 7.2* | 7.3* | 8.0*)
                 step_msg "found ok version of APPLE CLANG: $CFG_OSX_CLANG_VERSION"
                 ;;
                 (*)
diff --git a/mk/crates.mk b/mk/crates.mk
index 1583515014a..2b168b8f0e4 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -109,7 +109,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
               log graphviz rustc_llvm rustc_back rustc_data_structures\
 		  	  rustc_const_math
 DEPS_rustc_back := std syntax flate log libc
-DEPS_rustc_borrowck := rustc rustc_mir log graphviz syntax
+DEPS_rustc_borrowck := rustc log graphviz syntax rustc_mir
 DEPS_rustc_data_structures := std log serialize
 DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
                      rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
@@ -123,9 +123,9 @@ DEPS_rustc_passes := syntax rustc core rustc_const_eval
 DEPS_rustc_mir := rustc syntax rustc_const_math rustc_const_eval rustc_bitflags
 DEPS_rustc_resolve := arena rustc log syntax
 DEPS_rustc_platform_intrinsics := std
-DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
+DEPS_rustc_plugin := rustc rustc_metadata syntax
 DEPS_rustc_privacy := rustc log syntax
-DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
+DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
                     log syntax serialize rustc_llvm rustc_platform_intrinsics \
                     rustc_const_math rustc_const_eval rustc_incremental
 DEPS_rustc_incremental := rbml rustc serialize rustc_data_structures
diff --git a/mk/tests.mk b/mk/tests.mk
index f9ab84e3f8c..ed443147d46 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -276,6 +276,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
 	check-stage$(1)-T-$(2)-H-$(3)-incremental-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-ui-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-doc-exec \
+	check-stage$(1)-T-$(2)-H-$(3)-doc-error-index-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-pretty-exec
 
 ifndef CFG_DISABLE_CODEGEN_TESTS
diff --git a/src/bootstrap/build/cc.rs b/src/bootstrap/build/cc.rs
index d0b0f1007c6..7eb50b8b86d 100644
--- a/src/bootstrap/build/cc.rs
+++ b/src/bootstrap/build/cc.rs
@@ -57,7 +57,9 @@ pub fn find(build: &mut Build) {
         let compiler = cfg.get_compiler();
         let ar = cc2ar(compiler.path(), target);
         build.verbose(&format!("CC_{} = {:?}", target, compiler.path()));
-        build.verbose(&format!("AR_{} = {:?}", target, ar));
+        if let Some(ref ar) = ar {
+            build.verbose(&format!("AR_{} = {:?}", target, ar));
+        }
         build.cc.insert(target.to_string(), (compiler, ar));
     }
 
diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs
index 21d12d27d92..dadb0ffa6c9 100644
--- a/src/bootstrap/build/mod.rs
+++ b/src/bootstrap/build/mod.rs
@@ -119,7 +119,7 @@ pub struct Build {
     lldb_python_dir: Option<String>,
 
     // Runtime state filled in later on
-    cc: HashMap<String, (gcc::Tool, PathBuf)>,
+    cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
     cxx: HashMap<String, gcc::Tool>,
     compiler_rt_built: RefCell<HashMap<String, PathBuf>>,
 }
@@ -549,7 +549,7 @@ impl Build {
         // FIXME: the guard against msvc shouldn't need to be here
         if !target.contains("msvc") {
             cargo.env(format!("CC_{}", target), self.cc(target))
-                 .env(format!("AR_{}", target), self.ar(target))
+                 .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None
                  .env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
         }
 
@@ -825,8 +825,8 @@ impl Build {
     }
 
     /// Returns the path to the `ar` archive utility for the target specified.
-    fn ar(&self, target: &str) -> &Path {
-        &self.cc[target].1
+    fn ar(&self, target: &str) -> Option<&Path> {
+        self.cc[target].1.as_ref().map(|p| &**p)
     }
 
     /// Returns the path to the C++ compiler for the target specified, may panic
diff --git a/src/bootstrap/build/sanity.rs b/src/bootstrap/build/sanity.rs
index a2905277429..fd6cdc702cc 100644
--- a/src/bootstrap/build/sanity.rs
+++ b/src/bootstrap/build/sanity.rs
@@ -70,7 +70,9 @@ pub fn check(build: &mut Build) {
     // also build some C++ shims for LLVM so we need a C++ compiler.
     for target in build.config.target.iter() {
         need_cmd(build.cc(target).as_ref());
-        need_cmd(build.ar(target).as_ref());
+        if let Some(ar) = build.ar(target) {
+            need_cmd(ar.as_ref());
+        }
     }
     for host in build.config.host.iter() {
         need_cmd(build.cxx(host).as_ref());
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index 8e1da69cf02..838cc4f07a9 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -39,9 +39,11 @@ pub fn gnu_target(target: &str) -> String {
     }
 }
 
-pub fn cc2ar(cc: &Path, target: &str) -> PathBuf {
-    if target.contains("musl") || target.contains("msvc") {
-        PathBuf::from("ar")
+pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
+    if target.contains("msvc") {
+        None
+    } else if target.contains("musl") {
+        Some(PathBuf::from("ar"))
     } else {
         let parent = cc.parent().unwrap();
         let file = cc.file_name().unwrap().to_str().unwrap();
@@ -49,10 +51,10 @@ pub fn cc2ar(cc: &Path, target: &str) -> PathBuf {
             if let Some(idx) = file.rfind(suffix) {
                 let mut file = file[..idx].to_owned();
                 file.push_str("ar");
-                return parent.join(&file);
+                return Some(parent.join(&file));
             }
         }
-        parent.join(file)
+        Some(parent.join(file))
     }
 }
 
diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md
index d94eeaebf40..544f837d69b 100644
--- a/src/doc/book/error-handling.md
+++ b/src/doc/book/error-handling.md
@@ -1829,7 +1829,7 @@ use std::error::Error;
 
 fn search<P: AsRef<Path>>
          (file_path: P, city: &str)
-         -> Result<Vec<PopulationCount>, Box<Error+Send+Sync>> {
+         -> Result<Vec<PopulationCount>, Box<Error>> {
     let mut found = vec![];
     let file = try!(File::open(file_path));
     let mut rdr = csv::Reader::from_reader(file);
@@ -1858,20 +1858,17 @@ Instead of `x.unwrap()`, we now have `try!(x)`. Since our function returns a
 `Result<T, E>`, the `try!` macro will return early from the function if an
 error occurs.
 
-There is one big gotcha in this code: we used `Box<Error + Send + Sync>`
-instead of `Box<Error>`. We did this so we could convert a plain string to an
-error type. We need these extra bounds so that we can use the
-[corresponding `From`
-impls](../std/convert/trait.From.html):
+At the end of `search` we also convert a plain string to an error type 
+by using the [corresponding `From` impls](../std/convert/trait.From.html):
 
 ```rust,ignore
 // We are making use of this impl in the code above, since we call `From::from`
 // on a `&'static str`.
-impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a>
+impl<'a> From<&'a str> for Box<Error>
 
 // But this is also useful when you need to allocate a new string for an
 // error message, usually with `format!`.
-impl From<String> for Box<Error + Send + Sync>
+impl From<String> for Box<Error>
 ```
 
 Since `search` now returns a `Result<T, E>`, `main` should use case analysis
@@ -1964,7 +1961,7 @@ use std::io;
 
 fn search<P: AsRef<Path>>
          (file_path: &Option<P>, city: &str)
-         -> Result<Vec<PopulationCount>, Box<Error+Send+Sync>> {
+         -> Result<Vec<PopulationCount>, Box<Error>> {
     let mut found = vec![];
     let input: Box<io::Read> = match *file_path {
         None => Box::new(io::stdin()),
@@ -2175,9 +2172,8 @@ heuristics!
   `unwrap`. Be warned: if it winds up in someone else's hands, don't be
   surprised if they are agitated by poor error messages!
 * If you're writing a quick 'n' dirty program and feel ashamed about panicking
-  anyway, then use either a `String` or a `Box<Error + Send + Sync>` for your
-  error type (the `Box<Error + Send + Sync>` type is because of the
-  [available `From` impls](../std/convert/trait.From.html)).
+  anyway, then use either a `String` or a `Box<Error>` for your
+  error type.
 * Otherwise, in a program, define your own error types with appropriate
   [`From`](../std/convert/trait.From.html)
   and
diff --git a/src/doc/book/functions.md b/src/doc/book/functions.md
index 574929c14b3..b040684d05f 100644
--- a/src/doc/book/functions.md
+++ b/src/doc/book/functions.md
@@ -249,7 +249,7 @@ stack backtrace:
 If you need to override an already set `RUST_BACKTRACE`, 
 in cases when you cannot just unset the variable, 
 then set it to `0` to avoid getting a backtrace. 
-Any other value(even no value at all) turns on backtrace.
+Any other value (even no value at all) turns on backtrace.
 
 ```text
 $ export RUST_BACKTRACE=1
diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md
index 97ca2e3e702..e23e6f3a786 100644
--- a/src/doc/book/loops.md
+++ b/src/doc/book/loops.md
@@ -178,7 +178,7 @@ loop {
 
 We now loop forever with `loop` and use `break` to break out early. Issuing an explicit `return` statement will also serve to terminate the loop early.
 
-`continue` is similar, but instead of ending the loop, goes to the next
+`continue` is similar, but instead of ending the loop, it goes to the next
 iteration. This will only print the odd numbers:
 
 ```rust
diff --git a/src/doc/book/no-stdlib.md b/src/doc/book/no-stdlib.md
index 9823a0b6d63..c5c139e6580 100644
--- a/src/doc/book/no-stdlib.md
+++ b/src/doc/book/no-stdlib.md
@@ -12,9 +12,26 @@ don’t want to use the standard library via an attribute: `#![no_std]`.
 > `#![no_std]`](using-rust-without-the-standard-library.html)
 
 Obviously there's more to life than just libraries: one can use
-`#[no_std]` with an executable, controlling the entry point is
-possible in two ways: the `#[start]` attribute, or overriding the
-default shim for the C `main` function with your own.
+`#[no_std]` with an executable.
+
+### Using libc
+
+In order to build a `#[no_std]` executable we will need libc as a dependency. We can specify
+this using our `Cargo.toml` file:
+
+```toml
+[dependencies]
+libc = { version = "0.2.11", default-features = false }
+```
+
+Note that the default features have been disabled. This is a critical step -
+**the default features of libc include the standard library and so must be
+disabled.**
+
+### Writing an executable without stdlib
+
+Controlling the entry point is possible in two ways: the `#[start]` attribute,
+or overriding the default shim for the C `main` function with your own.
 
 The function marked `#[start]` is passed the command line parameters
 in the same format as C:
@@ -72,7 +89,6 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
 # // fn main() {} tricked you, rustdoc!
 ```
 
-
 The compiler currently makes a few assumptions about symbols which are available
 in the executable to call. Normally these functions are provided by the standard
 library, but without it you must define your own.
diff --git a/src/doc/book/primitive-types.md b/src/doc/book/primitive-types.md
index b6a123bb367..ea0bdf29fcc 100644
--- a/src/doc/book/primitive-types.md
+++ b/src/doc/book/primitive-types.md
@@ -163,7 +163,7 @@ A ‘slice’ is a reference to (or “view” into) another data structure. The
 useful for allowing safe, efficient access to a portion of an array without
 copying. For example, you might want to reference only one line of a file read
 into memory. By nature, a slice is not created directly, but from an existing
-variable binding. Slices have a defined length, can be mutable or immutable.
+variable binding. Slices have a defined length, and can be mutable or immutable.
 
 Internally, slices are represented as a pointer to the beginning of the data
 and a length.
diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md
index a28f450c942..ef339a14309 100644
--- a/src/doc/book/references-and-borrowing.md
+++ b/src/doc/book/references-and-borrowing.md
@@ -85,7 +85,7 @@ fn main() {
     fn sum_vec(v: &Vec<i32>) -> i32 {
         return v.iter().fold(0, |a, &b| a + b);
     }
-    // Borrow two vectors and and sum them.
+    // Borrow two vectors and sum them.
     // This kind of borrowing does not allow mutation to the borrowed.
     fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
         // do stuff with v1 and v2
diff --git a/src/doc/book/slice-patterns.md b/src/doc/book/slice-patterns.md
index de165b70fc4..fcedf0c994f 100644
--- a/src/doc/book/slice-patterns.md
+++ b/src/doc/book/slice-patterns.md
@@ -10,7 +10,7 @@ fn main() {
     let v = vec!["match_this", "1"];
 
     match &v[..] {
-        ["match_this", second] => println!("The second element is {}", second),
+        &["match_this", second] => println!("The second element is {}", second),
         _ => {},
     }
 }
@@ -26,8 +26,8 @@ slice will be bound to that name. For example:
 
 fn is_symmetric(list: &[u32]) -> bool {
     match list {
-        [] | [_] => true,
-        [x, inside.., y] if x == y => is_symmetric(inside),
+        &[] | &[_] => true,
+        &[x, ref inside.., y] if x == y => is_symmetric(inside),
         _ => false
     }
 }
diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md
index d8afd7c4cf3..7954085472e 100644
--- a/src/doc/book/testing.md
+++ b/src/doc/book/testing.md
@@ -380,8 +380,9 @@ the `tests` directory.
 
 # The `tests` directory
 
-To write an integration test, let's make a `tests` directory, and
-put a `tests/lib.rs` file inside, with this as its contents:
+Each file in `tests/*.rs` directory is treated as individual crate.
+So, to write an integration test, let's make a `tests` directory, and
+put a `tests/integration_test.rs` file inside, with this as its contents:
 
 ```rust,ignore
 extern crate adder;
@@ -394,8 +395,8 @@ fn it_works() {
 ```
 
 This looks similar to our previous tests, but slightly different. We now have
-an `extern crate adder` at the top. This is because the tests in the `tests`
-directory are an entirely separate crate, and so we need to import our library.
+an `extern crate adder` at the top. This is because each test in the `tests`
+directory is an entirely separate crate, and so we need to import our library.
 This is also why `tests` is a suitable place to write integration-style tests:
 they use the library like any other consumer of it would.
 
@@ -428,6 +429,11 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 Now we have three sections: our previous test is also run, as well as our new
 one.
 
+Cargo will ignore files in subdirectories of the `tests/` directory.
+Therefore shared modules in integrations tests are possible.
+For example `tests/common/mod.rs` is not seperatly compiled by cargo but can 
+be imported in every test with `mod common;`
+
 That's all there is to the `tests` directory. The `tests` module isn't needed
 here, since the whole thing is focused on tests.
 
diff --git a/src/doc/book/variable-bindings.md b/src/doc/book/variable-bindings.md
index 1c8c03cf679..b6751f57a97 100644
--- a/src/doc/book/variable-bindings.md
+++ b/src/doc/book/variable-bindings.md
@@ -37,8 +37,8 @@ of our minds as we go forward.
 Rust is a statically typed language, which means that we specify our types up
 front, and they’re checked at compile time. So why does our first example
 compile? Well, Rust has this thing called ‘type inference’. If it can figure
-out what the type of something is, Rust doesn’t require you to actually type it
-out.
+out what the type of something is, Rust doesn’t require you to explicitly type
+it out.
 
 We can add the type if we want to, though. Types come after a colon (`:`):
 
@@ -159,8 +159,9 @@ error: aborting due to previous error
 Could not compile `hello_world`.
 ```
 
-Rust will not let us use a value that has not been initialized. Next, let’s
-talk about this stuff we've added to `println!`.
+Rust will not let us use a value that has not been initialized.
+
+Let take a minute to talk about this stuff we've added to `println!`.
 
 If you include two curly braces (`{}`, some call them moustaches...) in your
 string to print, Rust will interpret this as a request to interpolate some sort
@@ -222,8 +223,8 @@ To learn more, run the command again with --verbose.
 ```
 
 Additionally, variable bindings can be shadowed. This means that a later
-variable binding with the same name as another binding, that's currently in
-scope, will override the previous binding.
+variable binding with the same name as another binding that is currently in
+scope will override the previous binding.
 
 ```rust
 let x: i32 = 8;
@@ -240,7 +241,10 @@ println!("{}", x); // Prints "42"
 Shadowing and mutable bindings may appear as two sides of the same coin, but
 they are two distinct concepts that can't always be used interchangeably. For
 one, shadowing enables us to rebind a name to a value of a different type. It
-is also possible to change the mutability of a binding.
+is also possible to change the mutability of a binding. Note that shadowing a 
+name does not alter or destroy the value it was bound to, and the value will
+continue to exist until it goes out of scope, even if it is no longer accessible
+by any means.
 
 ```rust
 let mut x: i32 = 1;
diff --git a/src/doc/nomicon/safe-unsafe-meaning.md b/src/doc/nomicon/safe-unsafe-meaning.md
index 5fd61eb51dd..c4f939a608b 100644
--- a/src/doc/nomicon/safe-unsafe-meaning.md
+++ b/src/doc/nomicon/safe-unsafe-meaning.md
@@ -1,150 +1,127 @@
 % How Safe and Unsafe Interact
 
-So what's the relationship between Safe and Unsafe Rust? How do they interact?
-
-Rust models the separation between Safe and Unsafe Rust with the `unsafe`
-keyword, which can be thought as a sort of *foreign function interface* (FFI)
-between Safe and Unsafe Rust. This is the magic behind why we can say Safe Rust
-is a safe language: all the scary unsafe bits are relegated exclusively to FFI
-*just like every other safe language*.
-
-However because one language is a subset of the other, the two can be cleanly
-intermixed as long as the boundary between Safe and Unsafe Rust is denoted with
-the `unsafe` keyword. No need to write headers, initialize runtimes, or any of
-that other FFI boiler-plate.
-
-There are several places `unsafe` can appear in Rust today, which can largely be
-grouped into two categories:
-
-* There are unchecked contracts here. To declare you understand this, I require
-you to write `unsafe` elsewhere:
-    * On functions, `unsafe` is declaring the function to be unsafe to call.
-      Users of the function must check the documentation to determine what this
-      means, and then have to write `unsafe` somewhere to identify that they're
-      aware of the danger.
-    * On trait declarations, `unsafe` is declaring that *implementing* the trait
-      is an unsafe operation, as it has contracts that other unsafe code is free
-      to trust blindly. (More on this below.)
-
-* I am declaring that I have, to the best of my knowledge, adhered to the
-unchecked contracts:
-    * On trait implementations, `unsafe` is declaring that the contract of the
-      `unsafe` trait has been upheld.
-    * On blocks, `unsafe` is declaring any unsafety from an unsafe
-      operation within to be handled, and therefore the parent function is safe.
-
-There is also `#[unsafe_no_drop_flag]`, which is a special case that exists for
-historical reasons and is in the process of being phased out. See the section on
-[drop flags] for details.
-
-Some examples of unsafe functions:
-
-* `slice::get_unchecked` will perform unchecked indexing, allowing memory
-  safety to be freely violated.
-* every raw pointer to sized type has intrinsic `offset` method that invokes
-  Undefined Behavior if it is not "in bounds" as defined by LLVM.
-* `mem::transmute` reinterprets some value as having the given type,
-  bypassing type safety in arbitrary ways. (see [conversions] for details)
-* All FFI functions are `unsafe` because they can do arbitrary things.
-  C being an obvious culprit, but generally any language can do something
-  that Rust isn't happy about.
+What's the relationship between Safe Rust and Unsafe Rust? How do they
+interact?
+
+The separation between Safe Rust and Unsafe Rust is controlled with the
+`unsafe` keyword, which acts as an interface from one to the other. This is
+why we can say Safe Rust is a safe language: all the unsafe parts are kept
+exclusively behind the boundary.
+
+The `unsafe` keyword has two uses: to declare the existence of contracts the
+compiler can't check, and to declare that the adherence of some code to
+those contracts has been checked by the programmer.
+
+You can use `unsafe` to indicate the existence of unchecked contracts on
+_functions_ and on _trait declarations_. On functions, `unsafe` means that
+users of the function must check that function's documentation to ensure
+they are using it in a way that maintains the contracts the function
+requires. On trait declarations, `unsafe` means that implementors of the
+trait must check the trait documentation to ensure their implementation
+maintains the contracts the trait requires.
+
+You can use `unsafe` on a block to declare that all constraints required
+by an unsafe function within the block have been adhered to, and the code
+can therefore be trusted. You can use `unsafe` on a trait implementation
+to declare that the implementation of that trait has adhered to whatever
+contracts the trait's documentation requires.
+
+There is also the `#[unsafe_no_drop_flag]` attribute, which exists for
+historic reasons and is being phased out. See the section on [drop flags]
+for details.
+
+The standard library has a number of unsafe functions, including:
+
+* `slice::get_unchecked`, which performs unchecked indexing, allowing
+  memory safety to be freely violated.
+* `mem::transmute` reinterprets some value as having a given type, bypassing
+  type safety in arbitrary ways (see [conversions] for details).
+* Every raw pointer to a sized type has an intrinstic `offset` method that
+  invokes Undefined Behavior if the passed offset is not "in bounds" as
+  defined by LLVM.
+* All FFI functions are `unsafe` because the other language can do arbitrary
+  operations that the Rust compiler can't check.
 
 As of Rust 1.0 there are exactly two unsafe traits:
 
-* `Send` is a marker trait (it has no actual API) that promises implementors
-  are safe to send (move) to another thread.
-* `Sync` is a marker trait that promises that threads can safely share
-  implementors through a shared reference.
-
-The need for unsafe traits boils down to the fundamental property of safe code:
-
-**No matter how completely awful Safe code is, it can't cause Undefined
-Behavior.**
-
-This means that Unsafe Rust, **the royal vanguard of Undefined Behavior**, has to be
-*super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust
-specific safe code. Anything else would degenerate into infinite spirals of
-paranoid despair. In particular it's generally regarded as ok to trust the standard library
-to be correct. `std` is effectively an extension of the language, and you
-really just have to trust the language. If `std` fails to uphold the
-guarantees it declares, then it's basically a language bug.
-
-That said, it would be best to minimize *needlessly* relying on properties of
-concrete safe code. Bugs happen! Of course, I must reinforce that this is only
-a concern for Unsafe code. Safe code can blindly trust anyone and everyone
-as far as basic memory-safety is concerned.
-
-On the other hand, safe traits are free to declare arbitrary contracts, but because
-implementing them is safe, unsafe code can't trust those contracts to actually
-be upheld. This is different from the concrete case because *anyone* can
-randomly implement the interface. There is something fundamentally different
-about trusting a particular piece of code to be correct, and trusting *all the
-code that will ever be written* to be correct.
-
-For instance Rust has `PartialOrd` and `Ord` traits to try to differentiate
-between types which can "just" be compared, and those that actually implement a
-total ordering. Pretty much every API that wants to work with data that can be
-compared wants Ord data. For instance, a sorted map like BTreeMap
-*doesn't even make sense* for partially ordered types. If you claim to implement
-Ord for a type, but don't actually provide a proper total ordering, BTreeMap will
-get *really confused* and start making a total mess of itself. Data that is
-inserted may be impossible to find!
-
-But that's okay. BTreeMap is safe, so it guarantees that even if you give it a
-completely garbage Ord implementation, it will still do something *safe*. You
-won't start reading uninitialized or unallocated memory. In fact, BTreeMap
-manages to not actually lose any of your data. When the map is dropped, all the
-destructors will be successfully called! Hooray!
-
-However BTreeMap is implemented using a modest spoonful of Unsafe Rust (most collections
-are). That means that it's not necessarily *trivially true* that a bad Ord
-implementation will make BTreeMap behave safely. BTreeMap must be sure not to rely
-on Ord *where safety is at stake*. Ord is provided by safe code, and safety is not
-safe code's responsibility to uphold.
-
-But wouldn't it be grand if there was some way for Unsafe to trust some trait
-contracts *somewhere*? This is the problem that unsafe traits tackle: by marking
-*the trait itself* as unsafe to implement, unsafe code can trust the implementation
-to uphold the trait's contract. Although the trait implementation may be
-incorrect in arbitrary other ways.
-
-For instance, given a hypothetical UnsafeOrd trait, this is technically a valid
-implementation:
+* `Send` is a marker trait (a trait with no API) that promises implementors are
+  safe to send (move) to another thread.
+* `Sync` is a marker trait that promises threads can safely share implementors
+  through a shared reference.
+
+Much of the Rust standard library also uses Unsafe Rust internally, although
+these implementations are rigorously manually checked, and the Safe Rust
+interfaces provided on top of these implementations can be assumed to be safe.
+
+The need for all of this separation boils down a single fundamental property
+of Safe Rust:
+
+**No matter what, Safe Rust can't cause Undefined Behavior.**
+
+The design of the safe/unsafe split means that Safe Rust inherently has to
+trust that any Unsafe Rust it touches has been written correctly (meaning
+the Unsafe Rust actually maintains whatever contracts it is supposed to
+maintain). On the other hand, Unsafe Rust has to be very careful about
+trusting Safe Rust.
+
+As an example, Rust has the `PartialOrd` and `Ord` traits to differentiate
+between types which can "just" be compared, and those that provide a total
+ordering (where every value of the type is either equal to, greater than,
+or less than any other value of the same type). The sorted map type
+`BTreeMap` doesn't make sense for partially-ordered types, and so it
+requires that any key type for it implements the `Ord` trait. However,
+`BTreeMap` has Unsafe Rust code inside of its implementation, and this
+Unsafe Rust code cannot assume that any `Ord` implementation it gets makes
+sense. The unsafe portions of `BTreeMap`'s internals have to be careful to
+maintain all necessary contracts, even if a key type's `Ord` implementation
+does not implement a total ordering.
+
+Unsafe Rust cannot automatically trust Safe Rust. When writing Unsafe Rust,
+you must be careful to only rely on specific Safe Rust code, and not make
+assumptions about potential future Safe Rust code providing the same
+guarantees.
+
+This is the problem that `unsafe` traits exist to resolve. The `BTreeMap`
+type could theoretically require that keys implement a new trait called
+`UnsafeOrd`, rather than `Ord`, that might look like this:
 
 ```rust
-# use std::cmp::Ordering;
-# struct MyType;
-# unsafe trait UnsafeOrd { fn cmp(&self, other: &Self) -> Ordering; }
-unsafe impl UnsafeOrd for MyType {
-    fn cmp(&self, other: &Self) -> Ordering {
-        Ordering::Equal
-    }
+use std::cmp::Ordering;
+
+unsafe trait UnsafeOrd {
+    fn cmp(&self, other: &Self) -> Ordering;
 }
 ```
 
-But it's probably not the implementation you want.
-
-Rust has traditionally avoided making traits unsafe because it makes Unsafe
-pervasive, which is not desirable. The reason Send and Sync are unsafe is because thread
-safety is a *fundamental property* that unsafe code cannot possibly hope to defend
-against in the same way it would defend against a bad Ord implementation. The
-only way to possibly defend against thread-unsafety would be to *not use
-threading at all*. Making every load and store atomic isn't even sufficient,
-because it's possible for complex invariants to exist between disjoint locations
-in memory. For instance, the pointer and capacity of a Vec must be in sync.
-
-Even concurrent paradigms that are traditionally regarded as Totally Safe like
-message passing implicitly rely on some notion of thread safety -- are you
-really message-passing if you pass a pointer? Send and Sync therefore require
-some fundamental level of trust that Safe code can't provide, so they must be
-unsafe to implement. To help obviate the pervasive unsafety that this would
-introduce, Send (resp. Sync) is automatically derived for all types composed only
-of Send (resp. Sync) values. 99% of types are Send and Sync, and 99% of those
-never actually say it (the remaining 1% is overwhelmingly synchronization
-primitives).
-
-
-
+Then, a type would use `unsafe` to implement `UnsafeOrd`, indicating that
+they've ensured their implementation maintains whatever contracts the
+trait expects. In this situation, the Unsafe Rust in the internals of
+`BTreeMap` could trust that the key type's `UnsafeOrd` implementation is
+correct. If it isn't, it's the fault of the unsafe trait implementation
+code, which is consistent with Rust's safety guarantees.
+
+The decision of whether to mark a trait `unsafe` is an API design choice.
+Rust has traditionally avoided marking traits unsafe because it makes Unsafe
+Rust pervasive, which is not desirable. `Send` and `Sync` are marked unsafe
+because thread safety is a *fundamental property* that unsafe code can't
+possibly hope to defend against in the way it could defend against a bad
+`Ord` implementation. The decision of whether to mark your own traits `unsafe`
+depends on the same sort of consideration. If `unsafe` code cannot reasonably
+expect to defend against a bad implementation of the trait, then marking the
+trait `unsafe` is a reasonable choice.
+
+As an aside, while `Send` and `Sync` are `unsafe` traits, they are
+automatically implemented for types when such derivations are provably safe
+to do. `Send` is automatically derived for all types composed only of values
+whose types also implement `Send`. `Sync` is automatically derived for all
+types composed only of values whose types also implement `Sync`.
+
+This is the dance of Safe Rust and Unsafe Rust. It is designed to make using
+Safe Rust as ergonomic as possible, but requires extra effort and care when
+writing Unsafe Rust. The rest of the book is largely a discussion of the sort
+of care that must be taken, and what contracts it is expected of Unsafe Rust
+to uphold.
 
 [drop flags]: drop-flags.html
 [conversions]: conversions.html
+
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 810138e5a29..fb8ea0f5661 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -1628,7 +1628,7 @@ Functions within external blocks may be called by Rust code, just like
 functions defined in Rust. The Rust compiler automatically translates between
 the Rust ABI and the foreign ABI.
 
-A number of [attributes](#attributes) control the behavior of external blocks.
+A number of [attributes](#ffi-attributes) control the behavior of external blocks.
 
 By default external blocks assume that the library they are calling uses the
 standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as
@@ -1983,6 +1983,7 @@ macro scope.
 
 ### Miscellaneous attributes
 
+- `deprecated` - mark the item as deprecated; the full attribute is `#[deprecated(since = "crate version", note = "...")`, where both arguments are optional.
 - `export_name` - on statics and functions, this determines the name of the
   exported symbol.
 - `link_section` - on statics and functions, this specifies the section of the
@@ -2426,8 +2427,6 @@ The currently implemented features of the reference compiler are:
 * - `stmt_expr_attributes` - Allows attributes on expressions and
                              non-item statements.
 
-* - `deprecated` - Allows using the `#[deprecated]` attribute.
-
 * - `type_ascription` - Allows type ascription expressions `expr: Type`.
 
 * - `abi_vectorcall` - Allows the usage of the vectorcall calling convention
diff --git a/src/doc/rust.css b/src/doc/rust.css
index 874f6976619..9c1b3724d8d 100644
--- a/src/doc/rust.css
+++ b/src/doc/rust.css
@@ -229,7 +229,7 @@ a > code {
 pre.rust .kw { color: #8959A8; }
 pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
 pre.rust .number, pre.rust .string { color: #718C00; }
-pre.rust .self, pre.rust .boolval, pre.rust .prelude-val,
+pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
 pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
 pre.rust .comment { color: #8E908C; }
 pre.rust .doccomment { color: #4D4D4C; }
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index cf4fb459bc1..a873be455d5 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -271,7 +271,7 @@ impl<T> Rc<T> {
 }
 
 impl<T: ?Sized> Rc<T> {
-    /// Downgrades the `Rc<T>` to a `Weak<T>` reference.
+    /// Creates a new `Weak<T>` reference from this value.
     ///
     /// # Examples
     ///
diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs
index 33a675331ab..d1b3583d256 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -33,18 +33,27 @@ fn main() {
                  jemalloc.parent().unwrap().display());
         let stem = jemalloc.file_stem().unwrap().to_str().unwrap();
         let name = jemalloc.file_name().unwrap().to_str().unwrap();
-        let kind = if name.ends_with(".a") {"static"} else {"dylib"};
+        let kind = if name.ends_with(".a") {
+            "static"
+        } else {
+            "dylib"
+        };
         println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]);
-        return
+        return;
     }
 
     let compiler = gcc::Config::new().get_compiler();
-    let ar = build_helper::cc2ar(compiler.path(), &target);
-    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
-                         .collect::<Vec<_>>().join(" ");
+    // only msvc returns None for ar so unwrap is okay
+    let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
+    let cflags = compiler.args()
+                         .iter()
+                         .map(|s| s.to_str().unwrap())
+                         .collect::<Vec<_>>()
+                         .join(" ");
 
     let mut stack = src_dir.join("../jemalloc")
-                           .read_dir().unwrap()
+                           .read_dir()
+                           .unwrap()
                            .map(|e| e.unwrap())
                            .collect::<Vec<_>>();
     while let Some(entry) = stack.pop() {
@@ -57,7 +66,9 @@ fn main() {
     }
 
     let mut cmd = Command::new("sh");
-    cmd.arg(src_dir.join("../jemalloc/configure").to_str().unwrap()
+    cmd.arg(src_dir.join("../jemalloc/configure")
+                   .to_str()
+                   .unwrap()
                    .replace("C:\\", "/c/")
                    .replace("\\", "/"))
        .current_dir(&build_dir)
@@ -117,9 +128,10 @@ fn main() {
 
     run(&mut cmd);
     run(Command::new("make")
-                .current_dir(&build_dir)
-                .arg("build_lib_static")
-                .arg("-j").arg(env::var("NUM_JOBS").unwrap()));
+            .current_dir(&build_dir)
+            .arg("build_lib_static")
+            .arg("-j")
+            .arg(env::var("NUM_JOBS").unwrap()));
 
     if target.contains("windows") {
         println!("cargo:rustc-link-lib=static=jemalloc");
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index 7651d91c06d..347e97e6ffc 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -39,12 +39,12 @@ use libc::{c_int, c_void, size_t};
                not(target_env = "musl")),
            link(name = "pthread"))]
 #[cfg(not(cargobuild))]
-extern {}
+extern "C" {}
 
 // Note that the symbols here are prefixed by default on OSX and Windows (we
 // don't explicitly request it), and on Android and DragonFly we explicitly
 // request it as unprefixing cause segfaults (mismatches in allocators).
-extern {
+extern "C" {
     #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
                    target_os = "dragonfly", target_os = "windows"),
                link_name = "je_mallocx")]
@@ -136,8 +136,9 @@ pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
 // are available.
 #[no_mangle]
 #[cfg(target_os = "android")]
-pub extern fn pthread_atfork(_prefork: *mut u8,
-                             _postfork_parent: *mut u8,
-                             _postfork_child: *mut u8) -> i32 {
+pub extern "C" fn pthread_atfork(_prefork: *mut u8,
+                                 _postfork_parent: *mut u8,
+                                 _postfork_child: *mut u8)
+                                 -> i32 {
     0
 }
diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs
index 29f3e4b1b61..3b775dc2865 100644
--- a/src/libcollections/btree/map.rs
+++ b/src/libcollections/btree/map.rs
@@ -17,9 +17,9 @@ use core::ops::Index;
 use core::{fmt, intrinsics, mem, ptr};
 
 use borrow::Borrow;
-use Bound::{self, Included, Excluded, Unbounded};
+use Bound::{self, Excluded, Included, Unbounded};
 
-use super::node::{self, NodeRef, Handle, marker};
+use super::node::{self, Handle, NodeRef, marker};
 use super::search;
 
 use super::node::InsertResult::*;
@@ -68,7 +68,7 @@ use self::Entry::*;
 /// // would be `BTreeMap<&str, &str>` in this example).
 /// let mut movie_reviews = BTreeMap::new();
 ///
-/// // review some books.
+/// // review some movies.
 /// movie_reviews.insert("Office Space",       "Deals with real issues in the workplace.");
 /// movie_reviews.insert("Pulp Fiction",       "Masterpiece.");
 /// movie_reviews.insert("The Godfather",      "Very enjoyable.");
@@ -129,35 +129,38 @@ use self::Entry::*;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BTreeMap<K, V> {
     root: node::Root<K, V>,
-    length: usize
+    length: usize,
 }
 
 impl<K, V> Drop for BTreeMap<K, V> {
     #[unsafe_destructor_blind_to_params]
     fn drop(&mut self) {
         unsafe {
-            for _ in ptr::read(self).into_iter() { }
+            for _ in ptr::read(self).into_iter() {
+            }
         }
     }
 }
 
 impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
     fn clone(&self) -> BTreeMap<K, V> {
-        fn clone_subtree<K: Clone, V: Clone>(
-                node: node::NodeRef<marker::Immut, K, V, marker::LeafOrInternal>)
-                -> BTreeMap<K, V> {
+        fn clone_subtree<K: Clone, V: Clone>(node: node::NodeRef<marker::Immut,
+                                                                 K,
+                                                                 V,
+                                                                 marker::LeafOrInternal>)
+                                             -> BTreeMap<K, V> {
 
             match node.force() {
                 Leaf(leaf) => {
                     let mut out_tree = BTreeMap {
                         root: node::Root::new_leaf(),
-                        length: 0
+                        length: 0,
                     };
 
                     {
                         let mut out_node = match out_tree.root.as_mut().force() {
                             Leaf(leaf) => leaf,
-                            Internal(_) => unreachable!()
+                            Internal(_) => unreachable!(),
                         };
 
                         let mut in_edge = leaf.first_edge();
@@ -171,7 +174,7 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
                     }
 
                     out_tree
-                },
+                }
                 Internal(internal) => {
                     let mut out_tree = clone_subtree(internal.first_edge().descend());
 
@@ -218,7 +221,7 @@ impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
     fn get(&self, key: &Q) -> Option<&K> {
         match search::search_tree(self.root.as_ref(), key) {
             Found(handle) => Some(handle.into_kv().0),
-            GoDown(_) => None
+            GoDown(_) => None,
         }
     }
 
@@ -226,12 +229,14 @@ impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
         match search::search_tree(self.root.as_mut(), key) {
             Found(handle) => {
                 Some(OccupiedEntry {
-                    handle: handle,
-                    length: &mut self.length,
-                    _marker: PhantomData,
-                }.remove_kv().0)
-            },
-            GoDown(_) => None
+                         handle: handle,
+                         length: &mut self.length,
+                         _marker: PhantomData,
+                     }
+                     .remove_kv()
+                     .0)
+            }
+            GoDown(_) => None,
         }
     }
 
@@ -244,7 +249,8 @@ impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
                     handle: handle,
                     length: &mut self.length,
                     _marker: PhantomData,
-                }.insert(());
+                }
+                .insert(());
                 None
             }
         }
@@ -255,14 +261,14 @@ impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a, V: 'a> {
     range: Range<'a, K, V>,
-    length: usize
+    length: usize,
 }
 
 /// A mutable iterator over a BTreeMap's entries.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, K: 'a, V: 'a> {
     range: RangeMut<'a, K, V>,
-    length: usize
+    length: usize,
 }
 
 /// An owning iterator over a BTreeMap's entries.
@@ -270,7 +276,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
 pub struct IntoIter<K, V> {
     front: Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
     back: Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
-    length: usize
+    length: usize,
 }
 
 /// An iterator over a BTreeMap's keys.
@@ -294,7 +300,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 /// An iterator over a sub-range of BTreeMap's entries.
 pub struct Range<'a, K: 'a, V: 'a> {
     front: Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
-    back: Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>
+    back: Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
 }
 
 /// A mutable iterator over a sub-range of BTreeMap's entries.
@@ -311,15 +317,13 @@ pub struct RangeMut<'a, K: 'a, V: 'a> {
 pub enum Entry<'a, K: 'a, V: 'a> {
     /// A vacant Entry
     #[stable(feature = "rust1", since = "1.0.0")]
-    Vacant(
-        #[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>
-    ),
+    Vacant(#[stable(feature = "rust1", since = "1.0.0")]
+           VacantEntry<'a, K, V>),
 
     /// An occupied Entry
     #[stable(feature = "rust1", since = "1.0.0")]
-    Occupied(
-        #[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>
-    ),
+    Occupied(#[stable(feature = "rust1", since = "1.0.0")]
+             OccupiedEntry<'a, K, V>),
 }
 
 /// A vacant Entry.
@@ -336,11 +340,7 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> {
 /// An occupied Entry.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
-    handle: Handle<NodeRef<
-        marker::Mut<'a>,
-        K, V,
-        marker::LeafOrInternal
-    >, marker::KV>,
+    handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
 
     length: &'a mut usize,
 
@@ -349,7 +349,7 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
 }
 
 // An iterator for merging two sorted sequences into one
-struct MergeIter<K, V, I: Iterator<Item=(K, V)>> {
+struct MergeIter<K, V, I: Iterator<Item = (K, V)>> {
     left: Peekable<I>,
     right: Peekable<I>,
 }
@@ -373,7 +373,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
     pub fn new() -> BTreeMap<K, V> {
         BTreeMap {
             root: node::Root::new_leaf(),
-            length: 0
+            length: 0,
         }
     }
 
@@ -415,10 +415,13 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// assert_eq!(map.get(&2), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V> where K: Borrow<Q>, Q: Ord {
+    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
+        where K: Borrow<Q>,
+              Q: Ord
+    {
         match search::search_tree(self.root.as_ref(), key) {
             Found(handle) => Some(handle.into_kv().1),
-            GoDown(_) => None
+            GoDown(_) => None,
         }
     }
 
@@ -440,7 +443,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// assert_eq!(map.contains_key(&2), false);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool where K: Borrow<Q>, Q: Ord {
+    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
+        where K: Borrow<Q>,
+              Q: Ord
+    {
         self.get(key).is_some()
     }
 
@@ -465,10 +471,13 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// ```
     // See `get` for implementation notes, this is basically a copy-paste with mut's added
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V> where K: Borrow<Q>, Q: Ord {
+    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
+        where K: Borrow<Q>,
+              Q: Ord
+    {
         match search::search_tree(self.root.as_mut(), key) {
             Found(handle) => Some(handle.into_kv_mut().1),
-            GoDown(_) => None
+            GoDown(_) => None,
         }
     }
 
@@ -528,16 +537,20 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// assert_eq!(map.remove(&1), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V> where K: Borrow<Q>, Q: Ord {
+    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
+        where K: Borrow<Q>,
+              Q: Ord
+    {
         match search::search_tree(self.root.as_mut(), key) {
             Found(handle) => {
                 Some(OccupiedEntry {
-                    handle: handle,
-                    length: &mut self.length,
-                    _marker: PhantomData,
-                }.remove())
-            },
-            GoDown(_) => None
+                         handle: handle,
+                         length: &mut self.length,
+                         _marker: PhantomData,
+                     }
+                     .remove())
+            }
+            GoDown(_) => None,
         }
     }
 
@@ -571,7 +584,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// assert_eq!(a[&5], "f");
     /// ```
     #[unstable(feature = "btree_append", reason = "recently added as part of collections reform 2",
-               issue = "19986")]
+               issue = "34152")]
     pub fn append(&mut self, other: &mut Self) {
         // Do we have to append anything at all?
         if other.len() == 0 {
@@ -628,47 +641,63 @@ impl<K: Ord, V> BTreeMap<K, V> {
                                                        min: Bound<&Min>,
                                                        max: Bound<&Max>)
                                                        -> Range<K, V>
-        where K: Borrow<Min> + Borrow<Max>,
+        where K: Borrow<Min> + Borrow<Max>
     {
         let front = match min {
-            Included(key) => match search::search_tree(self.root.as_ref(), key) {
-                Found(kv_handle) => match kv_handle.left_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => last_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Excluded(key) => match search::search_tree(self.root.as_ref(), key) {
-                Found(kv_handle) => match kv_handle.right_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => first_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Unbounded => first_leaf_edge(self.root.as_ref())
+            Included(key) => {
+                match search::search_tree(self.root.as_ref(), key) {
+                    Found(kv_handle) => {
+                        match kv_handle.left_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => last_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Excluded(key) => {
+                match search::search_tree(self.root.as_ref(), key) {
+                    Found(kv_handle) => {
+                        match kv_handle.right_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => first_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Unbounded => first_leaf_edge(self.root.as_ref()),
         };
 
         let back = match max {
-            Included(key) => match search::search_tree(self.root.as_ref(), key) {
-                Found(kv_handle) => match kv_handle.right_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => first_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Excluded(key) => match search::search_tree(self.root.as_ref(), key) {
-                Found(kv_handle) => match kv_handle.left_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => last_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Unbounded => last_leaf_edge(self.root.as_ref())
+            Included(key) => {
+                match search::search_tree(self.root.as_ref(), key) {
+                    Found(kv_handle) => {
+                        match kv_handle.right_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => first_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Excluded(key) => {
+                match search::search_tree(self.root.as_ref(), key) {
+                    Found(kv_handle) => {
+                        match kv_handle.left_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => last_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Unbounded => last_leaf_edge(self.root.as_ref()),
         };
 
         Range {
             front: front,
-            back: back
+            back: back,
         }
     }
 
@@ -704,51 +733,67 @@ impl<K: Ord, V> BTreeMap<K, V> {
                                                            min: Bound<&Min>,
                                                            max: Bound<&Max>)
                                                            -> RangeMut<K, V>
-        where K: Borrow<Min> + Borrow<Max>,
+        where K: Borrow<Min> + Borrow<Max>
     {
         let root1 = self.root.as_mut();
         let root2 = unsafe { ptr::read(&root1) };
 
         let front = match min {
-            Included(key) => match search::search_tree(root1, key) {
-                Found(kv_handle) => match kv_handle.left_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => last_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Excluded(key) => match search::search_tree(root1, key) {
-                Found(kv_handle) => match kv_handle.right_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => first_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Unbounded => first_leaf_edge(root1)
+            Included(key) => {
+                match search::search_tree(root1, key) {
+                    Found(kv_handle) => {
+                        match kv_handle.left_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => last_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Excluded(key) => {
+                match search::search_tree(root1, key) {
+                    Found(kv_handle) => {
+                        match kv_handle.right_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => first_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Unbounded => first_leaf_edge(root1),
         };
 
         let back = match max {
-            Included(key) => match search::search_tree(root2, key) {
-                Found(kv_handle) => match kv_handle.right_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => first_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Excluded(key) => match search::search_tree(root2, key) {
-                Found(kv_handle) => match kv_handle.left_edge().force() {
-                    Leaf(bottom) => bottom,
-                    Internal(internal) => last_leaf_edge(internal.descend())
-                },
-                GoDown(bottom) => bottom
-            },
-            Unbounded => last_leaf_edge(root2)
+            Included(key) => {
+                match search::search_tree(root2, key) {
+                    Found(kv_handle) => {
+                        match kv_handle.right_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => first_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Excluded(key) => {
+                match search::search_tree(root2, key) {
+                    Found(kv_handle) => {
+                        match kv_handle.left_edge().force() {
+                            Leaf(bottom) => bottom,
+                            Internal(internal) => last_leaf_edge(internal.descend()),
+                        }
+                    }
+                    GoDown(bottom) => bottom,
+                }
+            }
+            Unbounded => last_leaf_edge(root2),
         };
 
         RangeMut {
             front: front,
             back: back,
-            _marker: PhantomData
+            _marker: PhantomData,
         }
     }
 
@@ -773,21 +818,25 @@ impl<K: Ord, V> BTreeMap<K, V> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn entry(&mut self, key: K) -> Entry<K, V> {
         match search::search_tree(self.root.as_mut(), &key) {
-            Found(handle) => Occupied(OccupiedEntry {
-                handle: handle,
-                length: &mut self.length,
-                _marker: PhantomData,
-            }),
-            GoDown(handle) => Vacant(VacantEntry {
-                key: key,
-                handle: handle,
-                length: &mut self.length,
-                _marker: PhantomData,
-            })
+            Found(handle) => {
+                Occupied(OccupiedEntry {
+                    handle: handle,
+                    length: &mut self.length,
+                    _marker: PhantomData,
+                })
+            }
+            GoDown(handle) => {
+                Vacant(VacantEntry {
+                    key: key,
+                    handle: handle,
+                    length: &mut self.length,
+                    _marker: PhantomData,
+                })
+            }
         }
     }
 
-    fn from_sorted_iter<I: Iterator<Item=(K, V)>>(&mut self, iter: I) {
+    fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
         let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node();
         // Iterate through all key-value pairs, pushing them into nodes at the right level.
         for (key, value) in iter {
@@ -810,12 +859,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
                                 // Go up again.
                                 test_node = parent.forget_type();
                             }
-                        },
+                        }
                         Err(node) => {
                             // We are at the top, create a new root node and push there.
                             open_node = node.into_root_mut().push_level();
                             break;
-                        },
+                        }
                     }
                 }
 
@@ -889,8 +938,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
     /// ```
     #[unstable(feature = "btree_split_off",
                reason = "recently added as part of collections reform 2",
-               issue = "19986")]
-    pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self where K: Borrow<Q> {
+               issue = "34152")]
+    pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
+        where K: Borrow<Q>
+    {
         if self.is_empty() {
             return Self::new();
         }
@@ -910,7 +961,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
                 let mut split_edge = match search::search_node(left_node, key) {
                     // key is going to the right tree
                     Found(handle) => handle.left_edge(),
-                    GoDown(handle) => handle
+                    GoDown(handle) => handle,
                 };
 
                 split_edge.move_suffix(&mut right_node);
@@ -920,8 +971,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
                         left_node = edge.descend();
                         right_node = node.first_edge().descend();
                     }
-                    (Leaf(_), Leaf(_)) => { break; },
-                    _ => { unreachable!(); }
+                    (Leaf(_), Leaf(_)) => {
+                        break;
+                    }
+                    _ => {
+                        unreachable!();
+                    }
                 }
             }
         }
@@ -950,8 +1005,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
                 loop {
                     res += dfs(edge.reborrow().descend());
                     match edge.right_kv() {
-                        Ok(right_kv) => { edge = right_kv.right_edge(); },
-                        Err(_) => { break; }
+                        Ok(right_kv) => {
+                            edge = right_kv.right_edge();
+                        }
+                        Err(_) => {
+                            break;
+                        }
                     }
                 }
             }
@@ -1064,14 +1123,16 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
 }
 
 impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> {
-    fn len(&self) -> usize { self.length }
+    fn len(&self) -> usize {
+        self.length
+    }
 }
 
 impl<'a, K, V> Clone for Iter<'a, K, V> {
     fn clone(&self) -> Iter<'a, K, V> {
         Iter {
             range: self.range.clone(),
-            length: self.length
+            length: self.length,
         }
     }
 }
@@ -1114,7 +1175,9 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
 }
 
 impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
-    fn len(&self) -> usize { self.length }
+    fn len(&self) -> usize {
+        self.length
+    }
 }
 
 impl<K, V> IntoIterator for BTreeMap<K, V> {
@@ -1130,14 +1193,15 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
         IntoIter {
             front: first_leaf_edge(root1),
             back: last_leaf_edge(root2),
-            length: len
+            length: len,
         }
     }
 }
 
 impl<K, V> Drop for IntoIter<K, V> {
     fn drop(&mut self) {
-        for _ in &mut *self { }
+        for _ in &mut *self {
+        }
         unsafe {
             let leaf_node = ptr::read(&self.front).into_node();
             if let Some(first_parent) = leaf_node.deallocate_and_ascend() {
@@ -1168,10 +1232,10 @@ impl<K, V> Iterator for IntoIter<K, V> {
                 let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
                 self.front = kv.right_edge();
                 return Some((k, v));
-            },
+            }
             Err(last_edge) => unsafe {
                 unwrap_unchecked(last_edge.into_node().deallocate_and_ascend())
-            }
+            },
         };
 
         loop {
@@ -1181,10 +1245,10 @@ impl<K, V> Iterator for IntoIter<K, V> {
                     let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
                     self.front = first_leaf_edge(kv.right_edge().descend());
                     return Some((k, v));
-                },
+                }
                 Err(last_edge) => unsafe {
                     cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend());
-                }
+                },
             }
         }
     }
@@ -1210,10 +1274,10 @@ impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
                 let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
                 self.back = kv.left_edge();
                 return Some((k, v));
-            },
+            }
             Err(last_edge) => unsafe {
                 unwrap_unchecked(last_edge.into_node().deallocate_and_ascend())
-            }
+            },
         };
 
         loop {
@@ -1223,17 +1287,19 @@ impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
                     let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
                     self.back = last_leaf_edge(kv.left_edge().descend());
                     return Some((k, v));
-                },
+                }
                 Err(last_edge) => unsafe {
                     cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend());
-                }
+                },
             }
         }
     }
 }
 
 impl<K, V> ExactSizeIterator for IntoIter<K, V> {
-    fn len(&self) -> usize { self.length }
+    fn len(&self) -> usize {
+        self.length
+    }
 }
 
 impl<'a, K, V> Iterator for Keys<'a, K, V> {
@@ -1262,9 +1328,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
 
 impl<'a, K, V> Clone for Keys<'a, K, V> {
     fn clone(&self) -> Keys<'a, K, V> {
-        Keys {
-            inner: self.inner.clone()
-        }
+        Keys { inner: self.inner.clone() }
     }
 }
 
@@ -1294,9 +1358,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
 
 impl<'a, K, V> Clone for Values<'a, K, V> {
     fn clone(&self) -> Values<'a, K, V> {
-        Values {
-            inner: self.inner.clone()
-        }
+        Values { inner: self.inner.clone() }
     }
 }
 
@@ -1348,7 +1410,7 @@ impl<'a, K, V> Range<'a, K, V> {
                 let ret = kv.into_kv();
                 self.front = kv.right_edge();
                 return ret;
-            },
+            }
             Err(last_edge) => {
                 let next_level = last_edge.into_node().ascend().ok();
                 unwrap_unchecked(next_level)
@@ -1361,7 +1423,7 @@ impl<'a, K, V> Range<'a, K, V> {
                     let ret = kv.into_kv();
                     self.front = first_leaf_edge(kv.right_edge().descend());
                     return ret;
-                },
+                }
                 Err(last_edge) => {
                     let next_level = last_edge.into_node().ascend().ok();
                     cur_handle = unwrap_unchecked(next_level);
@@ -1390,7 +1452,7 @@ impl<'a, K, V> Range<'a, K, V> {
                 let ret = kv.into_kv();
                 self.back = kv.left_edge();
                 return ret;
-            },
+            }
             Err(last_edge) => {
                 let next_level = last_edge.into_node().ascend().ok();
                 unwrap_unchecked(next_level)
@@ -1403,7 +1465,7 @@ impl<'a, K, V> Range<'a, K, V> {
                     let ret = kv.into_kv();
                     self.back = last_leaf_edge(kv.left_edge().descend());
                     return ret;
-                },
+                }
                 Err(last_edge) => {
                     let next_level = last_edge.into_node().ascend().ok();
                     cur_handle = unwrap_unchecked(next_level);
@@ -1417,7 +1479,7 @@ impl<'a, K, V> Clone for Range<'a, K, V> {
     fn clone(&self) -> Range<'a, K, V> {
         Range {
             front: self.front,
-            back: self.back
+            back: self.back,
         }
     }
 }
@@ -1429,7 +1491,7 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
         if self.front == self.back {
             None
         } else {
-            unsafe { Some (self.next_unchecked()) }
+            unsafe { Some(self.next_unchecked()) }
         }
     }
 }
@@ -1443,7 +1505,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
                 let (k, v) = ptr::read(&kv).into_kv_mut();
                 self.front = kv.right_edge();
                 return (k, v);
-            },
+            }
             Err(last_edge) => {
                 let next_level = last_edge.into_node().ascend().ok();
                 unwrap_unchecked(next_level)
@@ -1456,7 +1518,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
                     let (k, v) = ptr::read(&kv).into_kv_mut();
                     self.front = first_leaf_edge(kv.right_edge().descend());
                     return (k, v);
-                },
+                }
                 Err(last_edge) => {
                     let next_level = last_edge.into_node().ascend().ok();
                     cur_handle = unwrap_unchecked(next_level);
@@ -1485,7 +1547,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
                 let (k, v) = ptr::read(&kv).into_kv_mut();
                 self.back = kv.left_edge();
                 return (k, v);
-            },
+            }
             Err(last_edge) => {
                 let next_level = last_edge.into_node().ascend().ok();
                 unwrap_unchecked(next_level)
@@ -1498,7 +1560,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
                     let (k, v) = ptr::read(&kv).into_kv_mut();
                     self.back = last_leaf_edge(kv.left_edge().descend());
                     return (k, v);
-                },
+                }
                 Err(last_edge) => {
                     let next_level = last_edge.into_node().ascend().ok();
                     cur_handle = unwrap_unchecked(next_level);
@@ -1509,7 +1571,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
 }
 
 impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> {
-    fn from_iter<T: IntoIterator<Item=(K, V)>>(iter: T) -> BTreeMap<K, V> {
+    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> BTreeMap<K, V> {
         let mut map = BTreeMap::new();
         map.extend(iter);
         map
@@ -1518,7 +1580,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> {
 
 impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
     #[inline]
-    fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) {
+    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
         for (k, v) in iter {
             self.insert(k, v);
         }
@@ -1526,7 +1588,7 @@ impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
 }
 
 impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap<K, V> {
-    fn extend<I: IntoIterator<Item=(&'a K, &'a V)>>(&mut self, iter: I) {
+    fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
         self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
     }
 }
@@ -1547,8 +1609,7 @@ impl<K: Ord, V> Default for BTreeMap<K, V> {
 
 impl<K: PartialEq, V: PartialEq> PartialEq for BTreeMap<K, V> {
     fn eq(&self, other: &BTreeMap<K, V>) -> bool {
-        self.len() == other.len() &&
-            self.iter().zip(other).all(|(a, b)| a == b)
+        self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b)
     }
 }
 
@@ -1575,7 +1636,8 @@ impl<K: Debug, V: Debug> Debug for BTreeMap<K, V> {
 }
 
 impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap<K, V>
-    where K: Borrow<Q>, Q: Ord
+    where K: Borrow<Q>,
+          Q: Ord
 {
     type Output = V;
 
@@ -1585,11 +1647,9 @@ impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap<K, V>
     }
 }
 
-fn first_leaf_edge<BorrowType, K, V>(
-        mut node: NodeRef<BorrowType,
-                          K, V,
-                          marker::LeafOrInternal>
-        ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
+fn first_leaf_edge<BorrowType, K, V>
+    (mut node: NodeRef<BorrowType, K, V, marker::LeafOrInternal>)
+     -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
     loop {
         match node.force() {
             Leaf(leaf) => return leaf.first_edge(),
@@ -1600,11 +1660,9 @@ fn first_leaf_edge<BorrowType, K, V>(
     }
 }
 
-fn last_leaf_edge<BorrowType, K, V>(
-        mut node: NodeRef<BorrowType,
-                          K, V,
-                          marker::LeafOrInternal>
-        ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
+fn last_leaf_edge<BorrowType, K, V>
+    (mut node: NodeRef<BorrowType, K, V, marker::LeafOrInternal>)
+     -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
     loop {
         match node.force() {
             Leaf(leaf) => return leaf.last_edge(),
@@ -1653,9 +1711,9 @@ impl<K, V> BTreeMap<K, V> {
         Iter {
             range: Range {
                 front: first_leaf_edge(self.root.as_ref()),
-                back: last_leaf_edge(self.root.as_ref())
+                back: last_leaf_edge(self.root.as_ref()),
             },
-            length: self.length
+            length: self.length,
         }
     }
 
@@ -1690,7 +1748,7 @@ impl<K, V> BTreeMap<K, V> {
                 back: last_leaf_edge(root2),
                 _marker: PhantomData,
             },
-            length: self.length
+            length: self.length,
         }
     }
 
@@ -1840,6 +1898,12 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
         &self.key
     }
 
+    /// Take ownership of the key.
+    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    pub fn into_key(self) -> K {
+        self.key
+    }
+
     /// Sets the value of the entry with the VacantEntry's key,
     /// and returns a mutable reference to it.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1865,15 +1929,17 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
 
         loop {
             match cur_parent {
-                Ok(parent) => match parent.insert(ins_k, ins_v, ins_edge) {
-                    Fit(_) => return unsafe { &mut *out_ptr },
-                    Split(left, k, v, right) => {
-                        ins_k = k;
-                        ins_v = v;
-                        ins_edge = right;
-                        cur_parent = left.ascend().map_err(|n| n.into_root_mut());
+                Ok(parent) => {
+                    match parent.insert(ins_k, ins_v, ins_edge) {
+                        Fit(_) => return unsafe { &mut *out_ptr },
+                        Split(left, k, v, right) => {
+                            ins_k = k;
+                            ins_v = v;
+                            ins_edge = right;
+                            cur_parent = left.ascend().map_err(|n| n.into_root_mut());
+                        }
                     }
-                },
+                }
                 Err(root) => {
                     root.push_level().push(ins_k, ins_v, ins_edge);
                     return unsafe { &mut *out_ptr };
@@ -1890,6 +1956,12 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
         self.handle.reborrow().into_kv().0
     }
 
+    /// Take ownership of the key and value from the map.
+    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    pub fn remove_pair(self) -> (K, V) {
+        self.remove_kv()
+    }
+
     /// Gets a reference to the value in the entry.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get(&self) -> &V {
@@ -1928,7 +2000,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
             Leaf(leaf) => {
                 let (hole, old_key, old_val) = leaf.remove();
                 (hole.into_node(), old_key, old_val)
-            },
+            }
             Internal(mut internal) => {
                 let key_loc = internal.kv_mut().0 as *mut K;
                 let val_loc = internal.kv_mut().1 as *mut V;
@@ -1938,12 +2010,8 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
 
                 let (hole, key, val) = to_remove.remove();
 
-                let old_key = unsafe {
-                    mem::replace(&mut *key_loc, key)
-                };
-                let old_val = unsafe {
-                    mem::replace(&mut *val_loc, val)
-                };
+                let old_key = unsafe { mem::replace(&mut *key_loc, key) };
+                let old_val = unsafe { mem::replace(&mut *val_loc, val) };
 
                 (hole.into_node(), old_key, old_val)
             }
@@ -1955,14 +2023,16 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
             match handle_underfull_node(cur_node) {
                 AtRoot => break,
                 EmptyParent(_) => unreachable!(),
-                Merged(parent) => if parent.len() == 0 {
-                    // We must be at the root
-                    parent.into_root_mut().pop_level();
-                    break;
-                } else {
-                    cur_node = parent.forget_type();
-                },
-                Stole(_) => break
+                Merged(parent) => {
+                    if parent.len() == 0 {
+                        // We must be at the root
+                        parent.into_root_mut().pop_level();
+                        break;
+                    } else {
+                        cur_node = parent.forget_type();
+                    }
+                }
+                Stole(_) => break,
             }
         }
 
@@ -1974,13 +2044,11 @@ enum UnderflowResult<'a, K, V> {
     AtRoot,
     EmptyParent(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
     Merged(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
-    Stole(NodeRef<marker::Mut<'a>, K, V, marker::Internal>)
+    Stole(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
 }
 
-fn handle_underfull_node<'a, K, V>(node: NodeRef<marker::Mut<'a>,
-                                                 K, V,
-                                                 marker::LeafOrInternal>)
-                                                 -> UnderflowResult<'a, K, V> {
+fn handle_underfull_node<'a, K, V>(node: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>)
+                                   -> UnderflowResult<'a, K, V> {
     let parent = if let Ok(parent) = node.ascend() {
         parent
     } else {
@@ -1989,10 +2057,12 @@ fn handle_underfull_node<'a, K, V>(node: NodeRef<marker::Mut<'a>,
 
     let (is_left, mut handle) = match parent.left_kv() {
         Ok(left) => (true, left),
-        Err(parent) => match parent.right_kv() {
-            Ok(right) => (false, right),
-            Err(parent) => {
-                return EmptyParent(parent.into_node());
+        Err(parent) => {
+            match parent.right_kv() {
+                Ok(right) => (false, right),
+                Err(parent) => {
+                    return EmptyParent(parent.into_node());
+                }
             }
         }
     };
@@ -2009,7 +2079,7 @@ fn handle_underfull_node<'a, K, V>(node: NodeRef<marker::Mut<'a>,
     }
 }
 
-impl<K: Ord, V, I: Iterator<Item=(K, V)>> Iterator for MergeIter<K, V, I> {
+impl<K: Ord, V, I: Iterator<Item = (K, V)>> Iterator for MergeIter<K, V, I> {
     type Item = (K, V);
 
     fn next(&mut self) -> Option<(K, V)> {
@@ -2023,16 +2093,12 @@ impl<K: Ord, V, I: Iterator<Item=(K, V)>> Iterator for MergeIter<K, V, I> {
         // Check which elements comes first and only advance the corresponding iterator.
         // If two keys are equal, take the value from `right`.
         match res {
-            Ordering::Less => {
-                self.left.next()
-            },
-            Ordering::Greater => {
-                self.right.next()
-            },
+            Ordering::Less => self.left.next(),
+            Ordering::Greater => self.right.next(),
             Ordering::Equal => {
                 self.left.next();
                 self.right.next()
-            },
+            }
         }
     }
 }
diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs
index 765595be317..c47eb0b3fad 100644
--- a/src/libcollections/btree/set.rs
+++ b/src/libcollections/btree/set.rs
@@ -576,7 +576,7 @@ impl<T: Ord> BTreeSet<T> {
     /// assert!(a.contains(&5));
     /// ```
     #[unstable(feature = "btree_append", reason = "recently added as part of collections reform 2",
-               issue = "19986")]
+               issue = "34152")]
     pub fn append(&mut self, other: &mut Self) {
         self.map.append(&mut other.map);
     }
@@ -613,7 +613,7 @@ impl<T: Ord> BTreeSet<T> {
     /// ```
     #[unstable(feature = "btree_split_off",
                reason = "recently added as part of collections reform 2",
-               issue = "19986")]
+               issue = "34152")]
     pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self where T: Borrow<Q> {
         BTreeSet { map: self.map.split_off(key) }
     }
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 6ab66fc217b..b824817d53f 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -105,12 +105,14 @@ pub mod vec_deque;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_map {
+    //! A map based on a B-Tree.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use btree::map::*;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_set {
+    //! A set based on a B-Tree.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use btree::set::*;
 }
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index d7c11f32404..3364d7e1697 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -1404,8 +1404,8 @@ impl str {
     /// Returns a string slice with all prefixes and suffixes that match a
     /// pattern repeatedly removed.
     ///
-    /// The pattern can be a `&str`, [`char`], or a closure that determines
-    /// if a character matches.
+    /// The pattern can be a [`char`] or a closure that determines if a
+    /// character matches.
     ///
     /// [`char`]: primitive.char.html
     ///
diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs
index 124b85bfca8..07428f3f8b2 100644
--- a/src/libcollectionstest/str.rs
+++ b/src/libcollectionstest/str.rs
@@ -123,8 +123,6 @@ macro_rules! test_concat {
 fn test_concat_for_different_types() {
     test_concat!("ab", vec![s("a"), s("b")]);
     test_concat!("ab", vec!["a", "b"]);
-    test_concat!("ab", vec!["a", "b"]);
-    test_concat!("ab", vec![s("a"), s("b")]);
 }
 
 #[test]
@@ -194,24 +192,24 @@ fn test_unsafe_slice() {
 
 #[test]
 fn test_starts_with() {
-    assert!(("".starts_with("")));
-    assert!(("abc".starts_with("")));
-    assert!(("abc".starts_with("a")));
-    assert!((!"a".starts_with("abc")));
-    assert!((!"".starts_with("abc")));
-    assert!((!"ödd".starts_with("-")));
-    assert!(("ödd".starts_with("öd")));
+    assert!("".starts_with(""));
+    assert!("abc".starts_with(""));
+    assert!("abc".starts_with("a"));
+    assert!(!"a".starts_with("abc"));
+    assert!(!"".starts_with("abc"));
+    assert!(!"ödd".starts_with("-"));
+    assert!("ödd".starts_with("öd"));
 }
 
 #[test]
 fn test_ends_with() {
-    assert!(("".ends_with("")));
-    assert!(("abc".ends_with("")));
-    assert!(("abc".ends_with("c")));
-    assert!((!"a".ends_with("abc")));
-    assert!((!"".ends_with("abc")));
-    assert!((!"ddö".ends_with("-")));
-    assert!(("ddö".ends_with("dö")));
+    assert!("".ends_with(""));
+    assert!("abc".ends_with(""));
+    assert!("abc".ends_with("c"));
+    assert!(!"a".ends_with("abc"));
+    assert!(!"".ends_with("abc"));
+    assert!(!"ddö".ends_with("-"));
+    assert!("ddö".ends_with("dö"));
 }
 
 #[test]
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index dfd2ba9154d..49304b1f3bf 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -85,7 +85,7 @@ use marker::{Reflect, Sized};
 
 /// A type to emulate dynamic typing.
 ///
-/// Every type with no non-`'static` references implements `Any`.
+/// Most types implement `Any`. However, any type which contains a non-`'static` reference does not.
 /// See the [module-level documentation][mod] for more details.
 ///
 /// [mod]: index.html
diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 8c8b2017007..6f5bb2747df 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -22,6 +22,7 @@ use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse,
 use super::ChainState;
 use super::{DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator,
             IntoIterator};
+use super::ZipImpl;
 
 fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
 
@@ -382,7 +383,7 @@ pub trait Iterator {
     fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter> where
         Self: Sized, U: IntoIterator
     {
-        Zip{a: self, b: other.into_iter()}
+        Zip::new(self, other.into_iter())
     }
 
     /// Takes a closure and creates an iterator which calls that closure on each
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index ae1e3116826..b866655bbd5 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -301,7 +301,9 @@
 
 use clone::Clone;
 use cmp;
+use default::Default;
 use fmt;
+use iter_private::TrustedRandomAccess;
 use ops::FnMut;
 use option::Option::{self, Some, None};
 use usize;
@@ -622,7 +624,8 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Zip<A, B> {
     a: A,
-    b: B
+    b: B,
+    spec: <(A, B) as ZipImplData>::Data,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -631,29 +634,13 @@ impl<A, B> Iterator for Zip<A, B> where A: Iterator, B: Iterator
     type Item = (A::Item, B::Item);
 
     #[inline]
-    fn next(&mut self) -> Option<(A::Item, B::Item)> {
-        self.a.next().and_then(|x| {
-            self.b.next().and_then(|y| {
-                Some((x, y))
-            })
-        })
+    fn next(&mut self) -> Option<Self::Item> {
+        ZipImpl::next(self)
     }
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let (a_lower, a_upper) = self.a.size_hint();
-        let (b_lower, b_upper) = self.b.size_hint();
-
-        let lower = cmp::min(a_lower, b_lower);
-
-        let upper = match (a_upper, b_upper) {
-            (Some(x), Some(y)) => Some(cmp::min(x,y)),
-            (Some(x), None) => Some(x),
-            (None, Some(y)) => Some(y),
-            (None, None) => None
-        };
-
-        (lower, upper)
+        ZipImpl::size_hint(self)
     }
 }
 
@@ -664,6 +651,61 @@ impl<A, B> DoubleEndedIterator for Zip<A, B> where
 {
     #[inline]
     fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
+        ZipImpl::next_back(self)
+    }
+}
+
+// Zip specialization trait
+#[doc(hidden)]
+trait ZipImpl<A, B> {
+    type Item;
+    fn new(a: A, b: B) -> Self;
+    fn next(&mut self) -> Option<Self::Item>;
+    fn size_hint(&self) -> (usize, Option<usize>);
+    fn next_back(&mut self) -> Option<Self::Item>
+        where A: DoubleEndedIterator + ExactSizeIterator,
+              B: DoubleEndedIterator + ExactSizeIterator;
+}
+
+// Zip specialization data members
+#[doc(hidden)]
+trait ZipImplData {
+    type Data: 'static + Clone + Default + fmt::Debug;
+}
+
+#[doc(hidden)]
+impl<T> ZipImplData for T {
+    default type Data = ();
+}
+
+// General Zip impl
+#[doc(hidden)]
+impl<A, B> ZipImpl<A, B> for Zip<A, B>
+    where A: Iterator, B: Iterator
+{
+    type Item = (A::Item, B::Item);
+    default fn new(a: A, b: B) -> Self {
+        Zip {
+            a: a,
+            b: b,
+            spec: Default::default(), // unused
+        }
+    }
+
+    #[inline]
+    default fn next(&mut self) -> Option<(A::Item, B::Item)> {
+        self.a.next().and_then(|x| {
+            self.b.next().and_then(|y| {
+                Some((x, y))
+            })
+        })
+    }
+
+    #[inline]
+    default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
+        where A: DoubleEndedIterator + ExactSizeIterator,
+              B: DoubleEndedIterator + ExactSizeIterator
+    {
         let a_sz = self.a.len();
         let b_sz = self.b.len();
         if a_sz != b_sz {
@@ -680,12 +722,106 @@ impl<A, B> DoubleEndedIterator for Zip<A, B> where
             _ => unreachable!(),
         }
     }
+
+    #[inline]
+    default fn size_hint(&self) -> (usize, Option<usize>) {
+        let (a_lower, a_upper) = self.a.size_hint();
+        let (b_lower, b_upper) = self.b.size_hint();
+
+        let lower = cmp::min(a_lower, b_lower);
+
+        let upper = match (a_upper, b_upper) {
+            (Some(x), Some(y)) => Some(cmp::min(x,y)),
+            (Some(x), None) => Some(x),
+            (None, Some(y)) => Some(y),
+            (None, None) => None
+        };
+
+        (lower, upper)
+    }
+}
+
+#[doc(hidden)]
+#[derive(Default, Debug, Clone)]
+struct ZipImplFields {
+    index: usize,
+    len: usize,
+}
+
+#[doc(hidden)]
+impl<A, B> ZipImplData for (A, B)
+    where A: TrustedRandomAccess, B: TrustedRandomAccess
+{
+    type Data = ZipImplFields;
+}
+
+#[doc(hidden)]
+impl<A, B> ZipImpl<A, B> for Zip<A, B>
+    where A: TrustedRandomAccess, B: TrustedRandomAccess
+{
+    fn new(a: A, b: B) -> Self {
+        let len = cmp::min(a.len(), b.len());
+        Zip {
+            a: a,
+            b: b,
+            spec: ZipImplFields {
+                index: 0,
+                len: len,
+            }
+        }
+    }
+
+    #[inline]
+    fn next(&mut self) -> Option<(A::Item, B::Item)> {
+        if self.spec.index < self.spec.len {
+            let i = self.spec.index;
+            self.spec.index += 1;
+            unsafe {
+                Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
+            }
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let len = self.spec.len - self.spec.index;
+        (len, Some(len))
+    }
+
+    #[inline]
+    fn next_back(&mut self) -> Option<(A::Item, B::Item)>
+        where A: DoubleEndedIterator + ExactSizeIterator,
+              B: DoubleEndedIterator + ExactSizeIterator
+    {
+        if self.spec.index < self.spec.len {
+            self.spec.len -= 1;
+            let i = self.spec.len;
+            unsafe {
+                Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
+            }
+        } else {
+            None
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A, B> ExactSizeIterator for Zip<A, B>
     where A: ExactSizeIterator, B: ExactSizeIterator {}
 
+#[doc(hidden)]
+unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
+    where A: TrustedRandomAccess,
+          B: TrustedRandomAccess,
+{
+    unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) {
+        (self.a.get_unchecked(i), self.b.get_unchecked(i))
+    }
+
+}
+
 /// An iterator that maps the values of `iter` with `f`.
 ///
 /// This `struct` is created by the [`map()`] method on [`Iterator`]. See its
@@ -982,6 +1118,15 @@ impl<I> DoubleEndedIterator for Enumerate<I> where
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> ExactSizeIterator for Enumerate<I> where I: ExactSizeIterator {}
 
+#[doc(hidden)]
+unsafe impl<I> TrustedRandomAccess for Enumerate<I>
+    where I: TrustedRandomAccess
+{
+    unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) {
+        (self.count + i, self.iter.get_unchecked(i))
+    }
+}
+
 /// An iterator with a `peek()` that returns an optional reference to the next
 /// element.
 ///
diff --git a/src/libcore/iter_private.rs b/src/libcore/iter_private.rs
new file mode 100644
index 00000000000..effe43cc67c
--- /dev/null
+++ b/src/libcore/iter_private.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.
+
+
+use iter::ExactSizeIterator;
+
+/// An iterator whose items are random accessible efficiently
+///
+/// # Safety
+///
+/// The iterator's .len() and size_hint() must be exact.
+///
+/// .get_unchecked() must return distinct mutable references for distinct
+/// indices (if applicable), and must return a valid reference if index is in
+/// 0..self.len().
+#[doc(hidden)]
+pub unsafe trait TrustedRandomAccess : ExactSizeIterator {
+    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
+}
+
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index f2a297b7630..db73f4759a5 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -156,4 +156,5 @@ pub mod hash;
 pub mod fmt;
 
 // note: does not need to be public
+mod iter_private;
 mod tuple;
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 50c4dc697c2..5e1210b2ff9 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -1475,7 +1475,7 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
 ///     assert_eq!(arr[1..3], [  1,2  ]);
 /// }
 /// ```
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeFull;
 
@@ -1506,7 +1506,7 @@ impl fmt::Debug for RangeFull {
 ///     assert_eq!(arr[1..3], [  1,2  ]);  // Range
 /// }
 /// ```
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, Hash)]  // not Copy -- see #27186
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Range<Idx> {
     /// The lower bound of the range (inclusive).
@@ -1570,7 +1570,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
 ///     assert_eq!(arr[1..3], [  1,2  ]);
 /// }
 /// ```
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, Hash)]  // not Copy -- see #27186
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeFrom<Idx> {
     /// The lower bound of the range (inclusive).
@@ -1619,7 +1619,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
 ///     assert_eq!(arr[1..3], [  1,2  ]);
 /// }
 /// ```
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeTo<Idx> {
     /// The upper bound of the range (exclusive).
@@ -1669,7 +1669,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
 ///     assert_eq!(arr[1...2], [  1,2  ]);  // RangeInclusive
 /// }
 /// ```
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, Hash)]  // not Copy -- see #27186
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
 pub enum RangeInclusive<Idx> {
     /// Empty range (iteration has finished)
@@ -1774,7 +1774,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
 ///     assert_eq!(arr[1...2], [  1,2  ]);
 /// }
 /// ```
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
 pub struct RangeToInclusive<Idx> {
     /// The upper bound of the range (inclusive)
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index b6ae6fde1e3..727c26ba9ab 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -50,6 +50,7 @@ use result::Result::{Ok, Err};
 use ptr;
 use mem;
 use marker::{Copy, Send, Sync, self};
+use iter_private::TrustedRandomAccess;
 
 #[repr(C)]
 struct Repr<T> {
@@ -1942,3 +1943,17 @@ macro_rules! impl_marker_for {
 
 impl_marker_for!(BytewiseEquality,
                  u8 i8 u16 i16 u32 i32 u64 i64 usize isize char bool);
+
+#[doc(hidden)]
+unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
+    unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
+        &*self.ptr.offset(i as isize)
+    }
+}
+
+#[doc(hidden)]
+unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
+    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
+        &mut *self.ptr.offset(i as isize)
+    }
+}
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 658b1312c49..47d9deb62ff 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -289,7 +289,7 @@ impl AtomicBool {
     /// Stores a value into the `bool` if the current value is the same as the `current` value.
     ///
     /// The return value is a result indicating whether the new value was written and containing
-    /// the previous value. On success this value is guaranteed to be equal to `new`.
+    /// the previous value. On success this value is guaranteed to be equal to `current`.
     ///
     /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
     /// operation. The first describes the required ordering if the operation succeeds while the
@@ -633,7 +633,7 @@ impl<T> AtomicPtr<T> {
     /// Stores a value into the pointer if the current value is the same as the `current` value.
     ///
     /// The return value is a result indicating whether the new value was written and containing
-    /// the previous value. On success this value is guaranteed to be equal to `new`.
+    /// the previous value. On success this value is guaranteed to be equal to `current`.
     ///
     /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
     /// operation. The first describes the required ordering if the operation succeeds while the
@@ -886,7 +886,7 @@ macro_rules! atomic_int {
             ///
             /// The return value is a result indicating whether the new value was written and
             /// containing the previous value. On success this value is guaranteed to be equal to
-            /// `new`.
+            /// `current`.
             ///
             /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of
             /// this operation. The first describes the required ordering if the operation succeeds
diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs
index 54fca291e5e..a2848faa105 100644
--- a/src/libcoretest/iter.rs
+++ b/src/libcoretest/iter.rs
@@ -13,6 +13,7 @@ use core::{i8, i16, isize};
 use core::usize;
 
 use test::Bencher;
+use test::black_box;
 
 #[test]
 fn test_lt() {
@@ -1030,3 +1031,33 @@ fn bench_max(b: &mut Bencher) {
         it.map(scatter).max()
     })
 }
+
+pub fn copy_zip(xs: &[u8], ys: &mut [u8]) {
+    for (a, b) in ys.iter_mut().zip(xs) {
+        *a = *b;
+    }
+}
+
+pub fn add_zip(xs: &[f32], ys: &mut [f32]) {
+    for (a, b) in ys.iter_mut().zip(xs) {
+        *a += *b;
+    }
+}
+
+#[bench]
+fn bench_zip_copy(b: &mut Bencher) {
+    let source = vec![0u8; 16 * 1024];
+    let mut dst = black_box(vec![0u8; 16 * 1024]);
+    b.iter(|| {
+        copy_zip(&source, &mut dst)
+    })
+}
+
+#[bench]
+fn bench_zip_add(b: &mut Bencher) {
+    let source = vec![1.; 16 * 1024];
+    let mut dst = vec![0.; 16 * 1024];
+    b.iter(|| {
+        add_zip(&source, &mut dst)
+    });
+}
diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs
index b578b064d67..63913f2878c 100644
--- a/src/libflate/lib.rs
+++ b/src/libflate/lib.rs
@@ -31,7 +31,7 @@
 
 extern crate libc;
 
-use libc::{c_void, size_t, c_int};
+use libc::{c_int, c_void, size_t};
 use std::fmt;
 use std::ops::Deref;
 use std::ptr::Unique;
@@ -76,9 +76,9 @@ impl Drop for Bytes {
 
 #[link(name = "miniz", kind = "static")]
 #[cfg(not(cargobuild))]
-extern {}
+extern "C" {}
 
-extern {
+extern "C" {
     /// Raw miniz compression function.
     fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
                                   src_buf_len: size_t,
@@ -154,8 +154,8 @@ pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result<Bytes, Error> {
 #[cfg(test)]
 mod tests {
     #![allow(deprecated)]
-    use super::{inflate_bytes, deflate_bytes};
-    use std::__rand::{thread_rng, Rng};
+    use super::{deflate_bytes, inflate_bytes};
+    use std::__rand::{Rng, thread_rng};
 
     #[test]
     fn test_flate_round_trip() {
diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs
index 1c3fca98a1f..0ad6a74d101 100644
--- a/src/libpanic_unwind/dwarf/eh.rs
+++ b/src/libpanic_unwind/dwarf/eh.rs
@@ -24,36 +24,35 @@
 use dwarf::DwarfReader;
 use core::mem;
 
-pub const DW_EH_PE_omit     : u8 = 0xFF;
-pub const DW_EH_PE_absptr   : u8 = 0x00;
-
-pub const DW_EH_PE_uleb128  : u8 = 0x01;
-pub const DW_EH_PE_udata2   : u8 = 0x02;
-pub const DW_EH_PE_udata4   : u8 = 0x03;
-pub const DW_EH_PE_udata8   : u8 = 0x04;
-pub const DW_EH_PE_sleb128  : u8 = 0x09;
-pub const DW_EH_PE_sdata2   : u8 = 0x0A;
-pub const DW_EH_PE_sdata4   : u8 = 0x0B;
-pub const DW_EH_PE_sdata8   : u8 = 0x0C;
-
-pub const DW_EH_PE_pcrel    : u8 = 0x10;
-pub const DW_EH_PE_textrel  : u8 = 0x20;
-pub const DW_EH_PE_datarel  : u8 = 0x30;
-pub const DW_EH_PE_funcrel  : u8 = 0x40;
-pub const DW_EH_PE_aligned  : u8 = 0x50;
-
-pub const DW_EH_PE_indirect : u8 = 0x80;
+pub const DW_EH_PE_omit: u8 = 0xFF;
+pub const DW_EH_PE_absptr: u8 = 0x00;
+
+pub const DW_EH_PE_uleb128: u8 = 0x01;
+pub const DW_EH_PE_udata2: u8 = 0x02;
+pub const DW_EH_PE_udata4: u8 = 0x03;
+pub const DW_EH_PE_udata8: u8 = 0x04;
+pub const DW_EH_PE_sleb128: u8 = 0x09;
+pub const DW_EH_PE_sdata2: u8 = 0x0A;
+pub const DW_EH_PE_sdata4: u8 = 0x0B;
+pub const DW_EH_PE_sdata8: u8 = 0x0C;
+
+pub const DW_EH_PE_pcrel: u8 = 0x10;
+pub const DW_EH_PE_textrel: u8 = 0x20;
+pub const DW_EH_PE_datarel: u8 = 0x30;
+pub const DW_EH_PE_funcrel: u8 = 0x40;
+pub const DW_EH_PE_aligned: u8 = 0x50;
+
+pub const DW_EH_PE_indirect: u8 = 0x80;
 
 #[derive(Copy, Clone)]
 pub struct EHContext {
-    pub ip: usize,         // Current instruction pointer
+    pub ip: usize, // Current instruction pointer
     pub func_start: usize, // Address of the current function
     pub text_start: usize, // Address of the code section
     pub data_start: usize, // Address of the data section
 }
 
-pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
-                               -> Option<usize> {
+pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option<usize> {
     if lsda.is_null() {
         return None;
     }
@@ -80,7 +79,7 @@ pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
     let action_table = reader.ptr.offset(call_site_table_length as isize);
     // Return addresses point 1 byte past the call instruction, which could
     // be in the next IP range.
-    let ip = context.ip-1;
+    let ip = context.ip - 1;
 
     while reader.ptr < action_table {
         let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
@@ -90,7 +89,7 @@ pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
         // Callsite table is sorted by cs_start, so if we've passed the ip, we
         // may stop searching.
         if ip < func_start + cs_start {
-            break
+            break;
         }
         if ip < func_start + cs_start + cs_len {
             if cs_lpad != 0 {
@@ -114,13 +113,13 @@ fn round_up(unrounded: usize, align: usize) -> usize {
 
 unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                                context: &EHContext,
-                               encoding: u8) -> usize {
+                               encoding: u8)
+                               -> usize {
     assert!(encoding != DW_EH_PE_omit);
 
     // DW_EH_PE_aligned implies it's an absolute pointer value
     if encoding == DW_EH_PE_aligned {
-        reader.ptr = round_up(reader.ptr as usize,
-                              mem::size_of::<usize>()) as *const u8;
+        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
         return reader.read::<usize>();
     }
 
@@ -134,20 +133,26 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
         DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
         DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
         DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
-        _ => panic!()
+        _ => panic!(),
     };
 
     result += match encoding & 0x70 {
         DW_EH_PE_absptr => 0,
         // relative to address of the encoded value, despite the name
         DW_EH_PE_pcrel => reader.ptr as usize,
-        DW_EH_PE_textrel => { assert!(context.text_start != 0);
-                              context.text_start },
-        DW_EH_PE_datarel => { assert!(context.data_start != 0);
-                              context.data_start },
-        DW_EH_PE_funcrel => { assert!(context.func_start != 0);
-                              context.func_start },
-        _ => panic!()
+        DW_EH_PE_textrel => {
+            assert!(context.text_start != 0);
+            context.text_start
+        }
+        DW_EH_PE_datarel => {
+            assert!(context.data_start != 0);
+            context.data_start
+        }
+        DW_EH_PE_funcrel => {
+            assert!(context.func_start != 0);
+            context.func_start
+        }
+        _ => panic!(),
     };
 
     if encoding & DW_EH_PE_indirect != 0 {
diff --git a/src/libpanic_unwind/dwarf/mod.rs b/src/libpanic_unwind/dwarf/mod.rs
index cde21f90811..5c05ac11d30 100644
--- a/src/libpanic_unwind/dwarf/mod.rs
+++ b/src/libpanic_unwind/dwarf/mod.rs
@@ -21,25 +21,22 @@ pub mod eh;
 use core::mem;
 
 pub struct DwarfReader {
-    pub ptr : *const u8
+    pub ptr: *const u8,
 }
 
 #[repr(C,packed)]
 struct Unaligned<T>(T);
 
 impl DwarfReader {
-
-    pub fn new(ptr : *const u8) -> DwarfReader {
-        DwarfReader {
-            ptr : ptr
-        }
+    pub fn new(ptr: *const u8) -> DwarfReader {
+        DwarfReader { ptr: ptr }
     }
 
     // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
     // on a 4-byte boundary. This may cause problems on platforms with strict
     // alignment requirements. By wrapping data in a "packed" struct, we are
     // telling the backend to generate "misalignment-safe" code.
-    pub unsafe fn read<T:Copy>(&mut self) -> T {
+    pub unsafe fn read<T: Copy>(&mut self) -> T {
         let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
         self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
         result
@@ -48,9 +45,9 @@ impl DwarfReader {
     // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
     // Length Data".
     pub unsafe fn read_uleb128(&mut self) -> u64 {
-        let mut shift : usize = 0;
-        let mut result : u64 = 0;
-        let mut byte : u8;
+        let mut shift: usize = 0;
+        let mut result: u64 = 0;
+        let mut byte: u8;
         loop {
             byte = self.read::<u8>();
             result |= ((byte & 0x7F) as u64) << shift;
@@ -63,9 +60,9 @@ impl DwarfReader {
     }
 
     pub unsafe fn read_sleb128(&mut self) -> i64 {
-        let mut shift : usize = 0;
-        let mut result : u64 = 0;
-        let mut byte : u8;
+        let mut shift: usize = 0;
+        let mut result: u64 = 0;
+        let mut byte: u8;
         loop {
             byte = self.read::<u8>();
             result |= ((byte & 0x7F) as u64) << shift;
@@ -84,12 +81,7 @@ impl DwarfReader {
 
 #[test]
 fn dwarf_reader() {
-    let encoded: &[u8] = &[1,
-                           2, 3,
-                           4, 5, 6, 7,
-                           0xE5, 0x8E, 0x26,
-                           0x9B, 0xF1, 0x59,
-                           0xFF, 0xFF];
+    let encoded: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 0xE5, 0x8E, 0x26, 0x9B, 0xF1, 0x59, 0xFF, 0xFF];
 
     let mut reader = DwarfReader::new(encoded.as_ptr());
 
diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs
index 50b2e1534d7..8df68da3786 100644
--- a/src/libpanic_unwind/gcc.rs
+++ b/src/libpanic_unwind/gcc.rs
@@ -79,8 +79,8 @@ pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
     let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
     return uw::_Unwind_RaiseException(exception_param) as u32;
 
-    extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
-                                exception: *mut uw::_Unwind_Exception) {
+    extern "C" fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
+                                    exception: *mut uw::_Unwind_Exception) {
         unsafe {
             let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
         }
@@ -130,50 +130,41 @@ pub mod eabi {
     use unwind as uw;
     use libc::c_int;
 
-    extern {
+    extern "C" {
         fn __gcc_personality_v0(version: c_int,
                                 actions: uw::_Unwind_Action,
                                 exception_class: uw::_Unwind_Exception_Class,
                                 ue_header: *mut uw::_Unwind_Exception,
                                 context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
+                                -> uw::_Unwind_Reason_Code;
     }
 
     #[lang = "eh_personality"]
     #[no_mangle]
-    extern fn rust_eh_personality(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                 context)
-        }
+    extern "C" fn rust_eh_personality(version: c_int,
+                                      actions: uw::_Unwind_Action,
+                                      exception_class: uw::_Unwind_Exception_Class,
+                                      ue_header: *mut uw::_Unwind_Exception,
+                                      context: *mut uw::_Unwind_Context)
+                                      -> uw::_Unwind_Reason_Code {
+        unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
     }
 
     #[lang = "eh_personality_catch"]
     #[no_mangle]
-    pub extern fn rust_eh_personality_catch(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
+    pub extern "C" fn rust_eh_personality_catch(version: c_int,
+                                                actions: uw::_Unwind_Action,
+                                                exception_class: uw::_Unwind_Exception_Class,
+                                                ue_header: *mut uw::_Unwind_Exception,
+                                                context: *mut uw::_Unwind_Context)
+                                                -> uw::_Unwind_Reason_Code {
 
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
+            // search phase
             uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                     context)
-            }
+        } else {
+            // cleanup phase
+            unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) }
         }
     }
 }
@@ -186,49 +177,40 @@ pub mod eabi {
     use unwind as uw;
     use libc::c_int;
 
-    extern {
+    extern "C" {
         fn __gcc_personality_sj0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
+                                 actions: uw::_Unwind_Action,
+                                 exception_class: uw::_Unwind_Exception_Class,
+                                 ue_header: *mut uw::_Unwind_Exception,
+                                 context: *mut uw::_Unwind_Context)
+                                 -> uw::_Unwind_Reason_Code;
     }
 
     #[lang = "eh_personality"]
     #[no_mangle]
-    pub extern fn rust_eh_personality(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_sj0(version, actions, exception_class, ue_header,
-                                  context)
-        }
+    pub extern "C" fn rust_eh_personality(version: c_int,
+                                          actions: uw::_Unwind_Action,
+                                          exception_class: uw::_Unwind_Exception_Class,
+                                          ue_header: *mut uw::_Unwind_Exception,
+                                          context: *mut uw::_Unwind_Context)
+                                          -> uw::_Unwind_Reason_Code {
+        unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
     }
 
     #[lang = "eh_personality_catch"]
     #[no_mangle]
-    pub extern fn rust_eh_personality_catch(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+    pub extern "C" fn rust_eh_personality_catch(version: c_int,
+                                                actions: uw::_Unwind_Action,
+                                                exception_class: uw::_Unwind_Exception_Class,
+                                                ue_header: *mut uw::_Unwind_Exception,
+                                                context: *mut uw::_Unwind_Context)
+                                                -> uw::_Unwind_Reason_Code {
+        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 {
+            // search phase
             uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_sj0(version, actions, exception_class, ue_header,
-                                      context)
-            }
+        } else {
+            // cleanup phase
+            unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) }
         }
     }
 }
@@ -241,47 +223,40 @@ pub mod eabi {
     use unwind as uw;
     use libc::c_int;
 
-    extern {
+    extern "C" {
         fn __gcc_personality_v0(state: uw::_Unwind_State,
                                 ue_header: *mut uw::_Unwind_Exception,
                                 context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
+                                -> uw::_Unwind_Reason_Code;
     }
 
     #[lang = "eh_personality"]
     #[no_mangle]
-    extern fn rust_eh_personality(
-        state: uw::_Unwind_State,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(state, ue_header, context)
-        }
+    extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
+                                      ue_header: *mut uw::_Unwind_Exception,
+                                      context: *mut uw::_Unwind_Context)
+                                      -> uw::_Unwind_Reason_Code {
+        unsafe { __gcc_personality_v0(state, ue_header, context) }
     }
 
     #[lang = "eh_personality_catch"]
     #[no_mangle]
-    pub extern fn rust_eh_personality_catch(
-        state: uw::_Unwind_State,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
+    pub extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State,
+                                                ue_header: *mut uw::_Unwind_Exception,
+                                                context: *mut uw::_Unwind_Context)
+                                                -> uw::_Unwind_Reason_Code {
         // Backtraces on ARM will call the personality routine with
         // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
         // we want to continue unwinding the stack, otherwise all our backtraces
         // would end at __rust_try.
-        if (state as c_int & uw::_US_ACTION_MASK as c_int)
-                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int
-               && (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { // search phase
+        if (state as c_int & uw::_US_ACTION_MASK as c_int) ==
+           uw::_US_VIRTUAL_UNWIND_FRAME as c_int &&
+           (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 {
+            // search phase
             uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_v0(state, ue_header, context)
-            }
+        } else {
+            // cleanup phase
+            unsafe { __gcc_personality_v0(state, ue_header, context) }
         }
     }
 }
@@ -290,7 +265,7 @@ pub mod eabi {
 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
 #[lang = "eh_unwind_resume"]
 #[unwind]
-unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
+unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
     uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
 }
 
@@ -314,22 +289,21 @@ unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
 pub mod eh_frame_registry {
     #[link(name = "gcc_eh")]
     #[cfg(not(cargobuild))]
-    extern {}
+    extern "C" {}
 
-    extern {
+    extern "C" {
         fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
         fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8);
     }
 
     #[no_mangle]
-    pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
-                                                 object: *mut u8) {
+    pub unsafe extern "C" fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8) {
         __register_frame_info(eh_frame_begin, object);
     }
 
     #[no_mangle]
-    pub  unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
-                                                   object: *mut u8) {
+    pub unsafe extern "C" fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
+                                                       object: *mut u8) {
         __deregister_frame_info(eh_frame_begin, object);
     }
 }
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index 39a93c4ac29..b765ee6f81c 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -82,11 +82,11 @@ mod windows;
 // hairy and tightly coupled, for more information see the compiler's
 // implementation of this.
 #[no_mangle]
-pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
-                                              data: *mut u8,
-                                              data_ptr: *mut usize,
-                                              vtable_ptr: *mut usize)
-                                              -> u32 {
+pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8),
+                                                  data: *mut u8,
+                                                  data_ptr: *mut usize,
+                                                  vtable_ptr: *mut usize)
+                                                  -> u32 {
     let mut payload = imp::payload();
     if intrinsics::try(f, data, &mut payload as *mut _ as *mut _) == 0 {
         0
@@ -101,7 +101,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
 // Entry point for raising an exception, just delegates to the platform-specific
 // implementation.
 #[no_mangle]
-pub unsafe extern fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
+pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
     imp::panic(mem::transmute(raw::TraitObject {
         data: data as *mut (),
         vtable: vtable as *mut (),
diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs
index 2b2926426f7..dd6e92fe9ae 100644
--- a/src/libpanic_unwind/seh.rs
+++ b/src/libpanic_unwind/seh.rs
@@ -128,7 +128,7 @@ mod imp {
     pub const NAME1: [u8; 7] = [b'.', b'P', b'E', b'A', b'_', b'K', 0];
     pub const NAME2: [u8; 7] = [b'.', b'P', b'E', b'A', b'X', 0, 0];
 
-    extern {
+    extern "C" {
         pub static __ImageBase: u8;
     }
 
@@ -186,10 +186,7 @@ static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
 
 static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray = _CatchableTypeArray {
     nCatchableTypes: 2,
-    arrayOfCatchableTypes: [
-        ptr!(0),
-        ptr!(0),
-    ],
+    arrayOfCatchableTypes: [ptr!(0), ptr!(0)],
 };
 
 static mut CATCHABLE_TYPE1: _CatchableType = _CatchableType {
@@ -216,7 +213,7 @@ static mut CATCHABLE_TYPE2: _CatchableType = _CatchableType {
     copy_function: ptr!(0),
 };
 
-extern {
+extern "C" {
     // The leading `\x01` byte here is actually a magical signal to LLVM to
     // *not* apply any other mangling like prefixing with a `_` character.
     //
diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs
index adb38d857ea..12e1a764c5f 100644
--- a/src/libpanic_unwind/seh64_gnu.rs
+++ b/src/libpanic_unwind/seh64_gnu.rs
@@ -32,11 +32,11 @@ use windows as c;
 const ETYPE: c::DWORD = 0b1110_u32 << 28;
 const MAGIC: c::DWORD = 0x525354; // "RST"
 
-const RUST_PANIC: c::DWORD  = ETYPE | (1 << 24) | MAGIC;
+const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
 
 #[repr(C)]
 struct PanicData {
-    data: Box<Any + Send>
+    data: Box<Any + Send>,
 }
 
 pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
@@ -82,30 +82,29 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
 
 #[lang = "eh_personality_catch"]
 #[cfg(not(test))]
-unsafe extern fn rust_eh_personality_catch(
-    exceptionRecord: *mut c::EXCEPTION_RECORD,
-    establisherFrame: c::LPVOID,
-    contextRecord: *mut c::CONTEXT,
-    dispatcherContext: *mut c::DISPATCHER_CONTEXT
-) -> c::EXCEPTION_DISPOSITION
-{
-    rust_eh_personality(exceptionRecord, establisherFrame,
-                        contextRecord, dispatcherContext)
+unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD,
+                                               establisherFrame: c::LPVOID,
+                                               contextRecord: *mut c::CONTEXT,
+                                               dispatcherContext: *mut c::DISPATCHER_CONTEXT)
+                                               -> c::EXCEPTION_DISPOSITION {
+    rust_eh_personality(exceptionRecord,
+                        establisherFrame,
+                        contextRecord,
+                        dispatcherContext)
 }
 
 #[lang = "eh_personality"]
 #[cfg(not(test))]
-unsafe extern fn rust_eh_personality(
-    exceptionRecord: *mut c::EXCEPTION_RECORD,
-    establisherFrame: c::LPVOID,
-    contextRecord: *mut c::CONTEXT,
-    dispatcherContext: *mut c::DISPATCHER_CONTEXT
-) -> c::EXCEPTION_DISPOSITION
-{
+unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECORD,
+                                         establisherFrame: c::LPVOID,
+                                         contextRecord: *mut c::CONTEXT,
+                                         dispatcherContext: *mut c::DISPATCHER_CONTEXT)
+                                         -> c::EXCEPTION_DISPOSITION {
     let er = &*exceptionRecord;
     let dc = &*dispatcherContext;
 
-    if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
+    if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 {
+        // we are in the dispatch phase
         if er.ExceptionCode == RUST_PANIC {
             if let Some(lpad) = find_landing_pad(dc) {
                 c::RtlUnwindEx(establisherFrame,
@@ -122,7 +121,7 @@ unsafe extern fn rust_eh_personality(
 
 #[lang = "eh_unwind_resume"]
 #[unwind]
-unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
+unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
     let params = [panic_ctx as c::ULONG_PTR];
     c::RaiseException(RUST_PANIC,
                       c::EXCEPTION_NONCONTINUABLE,
@@ -136,7 +135,7 @@ unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
         ip: dc.ControlPc as usize,
         func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
         text_start: dc.ImageBase as usize,
-        data_start: 0
+        data_start: 0,
     };
     eh::find_landing_pad(dc.HandlerData, &eh_ctx)
 }
diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs
index 9cca018ff11..fd8429d262e 100644
--- a/src/libpanic_unwind/windows.rs
+++ b/src/libpanic_unwind/windows.rs
@@ -12,7 +12,7 @@
 #![allow(dead_code)]
 #![cfg(windows)]
 
-use libc::{c_void, c_ulong, c_long, c_ulonglong};
+use libc::{c_long, c_ulong, c_ulonglong, c_void};
 
 pub type DWORD = c_ulong;
 pub type LONG = c_long;
@@ -25,8 +25,7 @@ pub const EXCEPTION_UNWINDING: DWORD = 0x2;        // Unwind is in progress
 pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4;      // Exit unwind is in progress
 pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20;   // Target unwind in progress
 pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
-pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
-                                    EXCEPTION_EXIT_UNWIND |
+pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND |
                                     EXCEPTION_TARGET_UNWIND |
                                     EXCEPTION_COLLIDED_UNWIND;
 
@@ -37,7 +36,7 @@ pub struct EXCEPTION_RECORD {
     pub ExceptionRecord: *mut EXCEPTION_RECORD,
     pub ExceptionAddress: LPVOID,
     pub NumberParameters: DWORD,
-    pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
+    pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS],
 }
 
 #[repr(C)]
@@ -75,7 +74,7 @@ pub enum EXCEPTION_DISPOSITION {
     ExceptionContinueExecution,
     ExceptionContinueSearch,
     ExceptionNestedException,
-    ExceptionCollidedUnwind
+    ExceptionCollidedUnwind,
 }
 pub use self::EXCEPTION_DISPOSITION::*;
 
@@ -93,6 +92,5 @@ extern "system" {
                        OriginalContext: *const CONTEXT,
                        HistoryTable: *const UNWIND_HISTORY_TABLE);
     #[unwind]
-    pub fn _CxxThrowException(pExceptionObject: *mut c_void,
-                              pThrowInfo: *mut u8);
+    pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8);
 }
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 76b53094a72..18ea17f4816 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -574,8 +574,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             return *self.loop_scopes.last().unwrap();
         }
 
-        match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
-            Some(Def::Label(loop_id)) => {
+        match self.tcx.expect_def(expr.id) {
+            Def::Label(loop_id) => {
                 for l in &self.loop_scopes {
                     if l.loop_id == loop_id {
                         return *l;
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 1ba722b6bae..eb51043fcd0 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1112,6 +1112,7 @@ fn main() {
 ```
 
 Or in a generic context, an erroneous code example would look like:
+
 ```compile_fail
 fn some_func<T>(foo: T) {
     println!("{:?}", foo); // error: the trait `core::fmt::Debug` is not
@@ -1130,6 +1131,7 @@ we only call it with a parameter that does implement `Debug`, the compiler
 still rejects the function: It must work with all possible input types. In
 order to make this example compile, we need to restrict the generic type we're
 accepting:
+
 ```
 use std::fmt;
 
@@ -1146,11 +1148,10 @@ fn main() {
     // struct WithoutDebug;
     // some_func(WithoutDebug);
 }
+```
 
 Rust only looks at the signature of the called function, as such it must
 already specify all requirements that will be used for every type parameter.
-```
-
 "##,
 
 E0281: r##"
@@ -1381,6 +1382,7 @@ denotes this will cause this error.
 struct Foo<T> {
     foo: &'static T
 }
+```
 
 This will compile, because it has the constraint on the type parameter:
 
@@ -1442,6 +1444,51 @@ lint name). Ensure the attribute is of this form:
 ```
 "##,
 
+E0453: r##"
+A lint check attribute was overruled by a `forbid` directive set as an
+attribute on an enclosing scope, or on the command line with the `-F` option.
+
+Example of erroneous code:
+
+```compile_fail
+#![forbid(non_snake_case)]
+
+#[allow(non_snake_case)]
+fn main() {
+    let MyNumber = 2; // error: allow(non_snake_case) overruled by outer
+                      //        forbid(non_snake_case)
+}
+```
+
+The `forbid` lint setting, like `deny`, turns the corresponding compiler
+warning into a hard error. Unlike `deny`, `forbid` prevents itself from being
+overridden by inner attributes.
+
+If you're sure you want to override the lint check, you can change `forbid` to
+`deny` (or use `-D` instead of `-F` if the `forbid` setting was given as a
+command-line option) to allow the inner lint check attribute:
+
+```
+#![deny(non_snake_case)]
+
+#[allow(non_snake_case)]
+fn main() {
+    let MyNumber = 2; // ok!
+}
+```
+
+Otherwise, edit the code to pass the lint check, and remove the overruled
+attribute:
+
+```
+#![forbid(non_snake_case)]
+
+fn main() {
+    let my_number = 2;
+}
+```
+"##,
+
 E0496: r##"
 A lifetime name is shadowing another lifetime name. Erroneous code example:
 
@@ -1626,7 +1673,6 @@ register_diagnostics! {
     E0314, // closure outlives stack frame
     E0315, // cannot invoke closure outside of its lifetime
     E0316, // nested quantification of lifetimes
-    E0453, // overruled by outer forbid
     E0473, // dereference of reference outside its lifetime
     E0474, // captured variable `..` does not outlive the enclosing closure
     E0475, // index of slice outside its lifetime
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index a056ba588b8..72261c473e5 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -67,6 +67,10 @@ pub struct PathResolution {
 }
 
 impl PathResolution {
+    pub fn new(def: Def) -> PathResolution {
+        PathResolution { base_def: def, depth: 0 }
+    }
+
     /// Get the definition, if fully resolved, otherwise panic.
     pub fn full_def(&self) -> Def {
         if self.depth != 0 {
@@ -75,17 +79,11 @@ impl PathResolution {
         self.base_def
     }
 
-    /// Get the DefId, if fully resolved, otherwise panic.
-    pub fn def_id(&self) -> DefId {
-        self.full_def().def_id()
-    }
-
-    pub fn new(base_def: Def,
-               depth: usize)
-               -> PathResolution {
-        PathResolution {
-            base_def: base_def,
-            depth: depth,
+    pub fn kind_name(&self) -> &'static str {
+        if self.depth != 0 {
+            "associated item"
+        } else {
+            self.base_def.kind_name()
         }
     }
 }
@@ -161,8 +159,8 @@ impl Def {
             Def::Struct(..) => "struct",
             Def::Trait(..) => "trait",
             Def::Method(..) => "method",
-            Def::Const(..) => "const",
-            Def::AssociatedConst(..) => "associated const",
+            Def::Const(..) => "constant",
+            Def::AssociatedConst(..) => "associated constant",
             Def::TyParam(..) => "type parameter",
             Def::PrimTy(..) => "builtin type",
             Def::Local(..) => "local variable",
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 90dd2dad720..393045bf93e 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -51,10 +51,9 @@ use std::collections::BTreeMap;
 use std::iter;
 use syntax::ast::*;
 use syntax::attr::{ThinAttributes, ThinAttributesExt};
-use syntax::ext::mtwt;
 use syntax::ptr::P;
 use syntax::codemap::{respan, Spanned, Span};
-use syntax::parse::token::{self, keywords};
+use syntax::parse::token;
 use syntax::std_inject;
 use syntax::visit::{self, Visitor};
 
@@ -184,16 +183,8 @@ impl<'a> LoweringContext<'a> {
         result
     }
 
-    fn lower_ident(&mut self, ident: Ident) -> Name {
-        if ident.name != keywords::Invalid.name() {
-            mtwt::resolve(ident)
-        } else {
-            ident.name
-        }
-    }
-
     fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned<Name>> {
-        o_id.map(|sp_ident| respan(sp_ident.span, self.lower_ident(sp_ident.node)))
+        o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
     }
 
     fn lower_attrs(&mut self, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
@@ -338,18 +329,14 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_path_full(&mut self, p: &Path, rename: bool) -> hir::Path {
+    fn lower_path(&mut self, p: &Path) -> hir::Path {
         hir::Path {
             global: p.global,
             segments: p.segments
                        .iter()
                        .map(|&PathSegment { identifier, ref parameters }| {
                            hir::PathSegment {
-                               name: if rename {
-                                   self.lower_ident(identifier)
-                               } else {
-                                   identifier.name
-                               },
+                               name: identifier.name,
                                parameters: self.lower_path_parameters(parameters),
                            }
                        })
@@ -358,10 +345,6 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_path(&mut self, p: &Path) -> hir::Path {
-        self.lower_path_full(p, false)
-    }
-
     fn lower_path_parameters(&mut self, path_parameters: &PathParameters) -> hir::PathParameters {
         match *path_parameters {
             PathParameters::AngleBracketed(ref data) =>
@@ -866,12 +849,11 @@ impl<'a> LoweringContext<'a> {
                 PatKind::Wild => hir::PatKind::Wild,
                 PatKind::Ident(ref binding_mode, pth1, ref sub) => {
                     self.with_parent_def(p.id, |this| {
-                        match this.resolver.get_resolution(p.id).map(|d| d.full_def()) {
+                        match this.resolver.get_resolution(p.id).map(|d| d.base_def) {
                             // `None` can occur in body-less function signatures
                             None | Some(Def::Local(..)) => {
                                 hir::PatKind::Binding(this.lower_binding_mode(binding_mode),
-                                                      respan(pth1.span,
-                                                             this.lower_ident(pth1.node)),
+                                                      respan(pth1.span, pth1.node.name),
                                                       sub.as_ref().map(|x| this.lower_pat(x)))
                             }
                             _ => hir::PatKind::Path(hir::Path::from_name(pth1.span, pth1.node.name))
@@ -1238,16 +1220,7 @@ impl<'a> LoweringContext<'a> {
                             position: position,
                         }
                     });
-                    let rename = if path.segments.len() == 1 {
-                        // Only local variables are renamed
-                        match self.resolver.get_resolution(e.id).map(|d| d.full_def()) {
-                            Some(Def::Local(..)) | Some(Def::Upvar(..)) => true,
-                            _ => false,
-                        }
-                    } else {
-                        false
-                    };
-                    hir::ExprPath(hir_qself, self.lower_path_full(path, rename))
+                    hir::ExprPath(hir_qself, self.lower_path(path))
                 }
                 ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)),
                 ExprKind::Again(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)),
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index c36c88c7990..8faa1cc1174 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1138,7 +1138,7 @@ pub type ExplicitSelf = Spanned<SelfKind>;
 impl Arg {
     pub fn to_self(&self) -> Option<ExplicitSelf> {
         if let PatKind::Binding(BindByValue(mutbl), name, _) = self.pat.node {
-            if name.node.unhygienize() == keywords::SelfValue.name() {
+            if name.node == keywords::SelfValue.name() {
                 return match self.ty.node {
                     TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
                     TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
@@ -1154,7 +1154,7 @@ impl Arg {
 
     pub fn is_self(&self) -> bool {
         if let PatKind::Binding(_, name, _) = self.pat.node {
-            name.node.unhygienize() == keywords::SelfValue.name()
+            name.node == keywords::SelfValue.name()
         } else {
             false
         }
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 27530d8c75d..6405be7455d 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -53,16 +53,6 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
     }
 }
 
-// This is used because same-named variables in alternative patterns need to
-// use the NodeId of their namesake in the first pattern.
-pub fn pat_id_map(pat: &hir::Pat) -> PatIdMap {
-    let mut map = FnvHashMap();
-    pat_bindings(pat, |_bm, p_id, _s, path1| {
-        map.insert(path1.node, p_id);
-    });
-    map
-}
-
 pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
     match pat.node {
         PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::QPath(..) => true,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index ceaf348117e..6340f9e7472 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -911,8 +911,9 @@ impl<'a> State<'a> {
             if struct_def.is_tuple() {
                 self.popen()?;
                 self.commasep(Inconsistent, struct_def.fields(), |s, field| {
-                    s.print_visibility(&field.vis)?;
                     s.maybe_print_comment(field.span.lo)?;
+                    s.print_outer_attributes(&field.attrs)?;
+                    s.print_visibility(&field.vis)?;
                     s.print_type(&field.ty)
                 })?;
                 self.pclose()?;
@@ -1728,12 +1729,9 @@ impl<'a> State<'a> {
                     }
                 }
                 self.print_name(path1.node)?;
-                match *sub {
-                    Some(ref p) => {
-                        word(&mut self.s, "@")?;
-                        self.print_pat(&p)?;
-                    }
-                    None => (),
+                if let Some(ref p) = *sub {
+                    word(&mut self.s, "@")?;
+                    self.print_pat(&p)?;
                 }
             }
             PatKind::TupleStruct(ref path, ref elts, ddpos) => {
@@ -2246,25 +2244,21 @@ impl<'a> State<'a> {
             Some(cm) => cm,
             _ => return Ok(()),
         };
-        match self.next_comment() {
-            Some(ref cmnt) => {
-                if (*cmnt).style != comments::Trailing {
-                    return Ok(());
-                }
-                let span_line = cm.lookup_char_pos(span.hi);
-                let comment_line = cm.lookup_char_pos((*cmnt).pos);
-                let mut next = (*cmnt).pos + BytePos(1);
-                match next_pos {
-                    None => (),
-                    Some(p) => next = p,
-                }
-                if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
-                   span_line.line == comment_line.line {
-                    self.print_comment(cmnt)?;
-                    self.cur_cmnt_and_lit.cur_cmnt += 1;
-                }
+        if let Some(ref cmnt) = self.next_comment() {
+            if (*cmnt).style != comments::Trailing {
+                return Ok(());
+            }
+            let span_line = cm.lookup_char_pos(span.hi);
+            let comment_line = cm.lookup_char_pos((*cmnt).pos);
+            let mut next = (*cmnt).pos + BytePos(1);
+            if let Some(p) = next_pos {
+                next = p;
+            }
+            if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
+               span_line.line == comment_line.line {
+                self.print_comment(cmnt)?;
+                self.cur_cmnt_and_lit.cur_cmnt += 1;
             }
-            _ => (),
         }
         Ok(())
     }
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index e2f27074dbf..fa3715b6891 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -337,8 +337,10 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
 
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
-            // Never make variables for regions bound within the type itself.
-            ty::ReLateBound(..) => { return r; }
+            // Never make variables for regions bound within the type itself,
+            // nor for erased regions.
+            ty::ReLateBound(..) |
+            ty::ReErased => { return r; }
 
             // Early-bound regions should really have been substituted away before
             // we get to this point.
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 2f67042ca1c..86bc4355b2d 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -216,7 +216,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             //
             // We shouldn't really be having unification failures with ReVar
             // and ReLateBound though.
-            ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) => {
+            ty::ReSkolemized(..) |
+            ty::ReVar(_) |
+            ty::ReLateBound(..) |
+            ty::ReErased => {
                 (format!("lifetime {:?}", region), None)
             }
         };
@@ -1354,17 +1357,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
                     ty_queue.push(&mut_ty.ty);
                 }
                 hir::TyPath(ref maybe_qself, ref path) => {
-                    let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) {
-                        None => {
-                            self.tcx
-                                .sess
-                                .fatal(&format!(
-                                        "unbound path {}",
-                                        pprust::path_to_string(path)))
-                        }
-                        Some(d) => d.full_def()
-                    };
-                    match a_def {
+                    match self.tcx.expect_def(cur_ty.id) {
                         Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
                             let generics = self.tcx.lookup_item_type(did).generics;
 
@@ -1863,11 +1856,10 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         },
         None => None
     };
-    if method_id_opt.is_some() {
-        let method_id = method_id_opt.unwrap();
+    if let Some(method_id) = method_id_opt {
         let parent = tcx.map.get_parent(method_id);
-        match tcx.map.find(parent) {
-            Some(node) => match node {
+        if let Some(node) = tcx.map.find(parent) {
+            match node {
                 ast_map::NodeItem(item) => match item.node {
                     hir::ItemImpl(_, _, ref gen, _, _, _) => {
                         taken.extend_from_slice(&gen.lifetimes);
@@ -1875,8 +1867,7 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     _ => ()
                 },
                 _ => ()
-            },
-            None => ()
+            }
         }
     }
     return taken;
@@ -1945,4 +1936,3 @@ fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime {
                     span: codemap::DUMMY_SP,
                     name: name }
 }
-
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 5ded6dc7364..880661a882a 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -23,7 +23,7 @@
 //! error messages or in any other form. Freshening is only really useful as an internal detail.
 //!
 //! __An important detail concerning regions.__ The freshener also replaces *all* regions with
-//! 'static. The reason behind this is that, in general, we do not take region relationships into
+//! 'erased. The reason behind this is that, in general, we do not take region relationships into
 //! account when making type-overloaded decisions. This is important because of the design of the
 //! region inferencer, which is not based on unification but rather on accumulating and then
 //! solving a set of constraints. In contrast, the type inferencer assigns a value to each type
@@ -96,9 +96,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
             ty::ReScope(_) |
             ty::ReVar(_) |
             ty::ReSkolemized(..) |
-            ty::ReEmpty => {
-                // replace all free regions with 'static
-                ty::ReStatic
+            ty::ReEmpty |
+            ty::ReErased => {
+                // replace all free regions with 'erased
+                ty::ReErased
             }
         }
     }
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 2211a565a32..ebfa942e5e4 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -25,7 +25,7 @@ use rustc_data_structures::unify::{self, UnificationTable};
 use middle::free_region::FreeRegionMap;
 use ty::{self, Ty, TyCtxt};
 use ty::{BoundRegion, Region, RegionVid};
-use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
+use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased};
 use ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
 
 use std::cell::{Cell, RefCell};
@@ -918,8 +918,10 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
             (ReLateBound(..), _) |
             (_, ReLateBound(..)) |
             (ReEarlyBound(..), _) |
-            (_, ReEarlyBound(..)) => {
-                bug!("cannot relate bound region: LUB({:?}, {:?})", a, b);
+            (_, ReEarlyBound(..)) |
+            (ReErased, _) |
+            (_, ReErased) => {
+                bug!("cannot relate region: LUB({:?}, {:?})", a, b);
             }
 
             (ReStatic, _) | (_, ReStatic) => {
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index e1fb701e641..fc2d68d7262 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -28,6 +28,7 @@
 #![feature(box_syntax)]
 #![feature(collections)]
 #![feature(const_fn)]
+#![feature(core_intrinsics)]
 #![feature(enumset)]
 #![feature(iter_arith)]
 #![feature(libc)]
@@ -102,10 +103,12 @@ pub mod middle {
 }
 
 pub mod mir {
+    mod cache;
     pub mod repr;
     pub mod tcx;
     pub mod visit;
     pub mod transform;
+    pub mod traversal;
     pub mod mir_map;
 }
 
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
index 8f97a89e654..f132212415f 100644
--- a/src/librustc/middle/astconv_util.rs
+++ b/src/librustc/middle/astconv_util.rs
@@ -65,13 +65,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// to it.
     pub fn ast_ty_to_prim_ty(self, ast_ty: &ast::Ty) -> Option<Ty<'tcx>> {
         if let ast::TyPath(None, ref path) = ast_ty.node {
-            let def = match self.def_map.borrow().get(&ast_ty.id) {
-                None => {
-                    span_bug!(ast_ty.span, "unbound path {:?}", path)
-                }
-                Some(d) => d.full_def()
-            };
-            if let Def::PrimTy(nty) = def {
+            if let Def::PrimTy(nty) = self.expect_def(ast_ty.id) {
                 Some(self.prim_ty_to_ty(&path.segments, nty))
             } else {
                 None
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index cc6b83fccf9..17da8ddbbc3 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -84,36 +84,35 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
+    fn lookup_and_handle_definition(&mut self, id: ast::NodeId) {
         use ty::TypeVariants::{TyEnum, TyStruct};
 
         // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar`
-        self.tcx.tables.borrow().item_substs.get(id)
+        self.tcx.tables.borrow().item_substs.get(&id)
             .and_then(|substs| substs.substs.self_ty())
             .map(|ty| match ty.sty {
                 TyEnum(tyid, _) | TyStruct(tyid, _) => self.check_def_id(tyid.did),
                 _ => (),
             });
 
-        self.tcx.def_map.borrow().get(id).map(|def| {
-            match def.full_def() {
-                Def::Const(_) | Def::AssociatedConst(..) => {
-                    self.check_def_id(def.def_id());
-                }
-                _ if self.ignore_non_const_paths => (),
-                Def::PrimTy(_) => (),
-                Def::SelfTy(..) => (),
-                Def::Variant(enum_id, variant_id) => {
-                    self.check_def_id(enum_id);
-                    if !self.ignore_variant_stack.contains(&variant_id) {
-                        self.check_def_id(variant_id);
-                    }
-                }
-                _ => {
-                    self.check_def_id(def.def_id());
+        let def = self.tcx.expect_def(id);
+        match def {
+            Def::Const(_) | Def::AssociatedConst(..) => {
+                self.check_def_id(def.def_id());
+            }
+            _ if self.ignore_non_const_paths => (),
+            Def::PrimTy(_) => (),
+            Def::SelfTy(..) => (),
+            Def::Variant(enum_id, variant_id) => {
+                self.check_def_id(enum_id);
+                if !self.ignore_variant_stack.contains(&variant_id) {
+                    self.check_def_id(variant_id);
                 }
             }
-        });
+            _ => {
+                self.check_def_id(def.def_id());
+            }
+        }
     }
 
     fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
@@ -138,10 +137,10 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
     fn handle_field_pattern_match(&mut self, lhs: &hir::Pat,
                                   pats: &[codemap::Spanned<hir::FieldPat>]) {
-        let def = self.tcx.def_map.borrow().get(&lhs.id).unwrap().full_def();
-        let pat_ty = self.tcx.node_id_to_type(lhs.id);
-        let variant = match pat_ty.sty {
-            ty::TyStruct(adt, _) | ty::TyEnum(adt, _) => adt.variant_of_def(def),
+        let variant = match self.tcx.node_id_to_type(lhs.id).sty {
+            ty::TyStruct(adt, _) | ty::TyEnum(adt, _) => {
+                adt.variant_of_def(self.tcx.expect_def(lhs.id))
+            }
             _ => span_bug!(lhs.span, "non-ADT in struct pattern")
         };
         for pat in pats {
@@ -161,12 +160,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             }
             scanned.insert(id);
 
-            match self.tcx.map.find(id) {
-                Some(ref node) => {
-                    self.live_symbols.insert(id);
-                    self.visit_node(node);
-                }
-                None => (),
+            if let Some(ref node) = self.tcx.map.find(id) {
+                self.live_symbols.insert(id);
+                self.visit_node(node);
             }
         }
     }
@@ -272,7 +268,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
             }
             _ if pat_util::pat_is_const(&def_map.borrow(), pat) => {
                 // it might be the only use of a const
-                self.lookup_and_handle_definition(&pat.id)
+                self.lookup_and_handle_definition(pat.id)
             }
             _ => ()
         }
@@ -283,12 +279,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
-        self.lookup_and_handle_definition(&id);
+        self.lookup_and_handle_definition(id);
         intravisit::walk_path(self, path);
     }
 
     fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) {
-        self.lookup_and_handle_definition(&item.node.id());
+        self.lookup_and_handle_definition(item.node.id());
         intravisit::walk_path_list_item(self, path, item);
     }
 }
@@ -373,9 +369,8 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     // Seed entry point
-    match *tcx.sess.entry_fn.borrow() {
-        Some((id, _)) => worklist.push(id),
-        None => ()
+    if let Some((id, _)) = *tcx.sess.entry_fn.borrow() {
+        worklist.push(id);
     }
 
     // Seed implemented trait items
@@ -465,16 +460,14 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
         // method of a private type is used, but the type itself is never
         // called directly.
         let impl_items = self.tcx.impl_items.borrow();
-        match self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) {
-            None => (),
-            Some(impl_list) => {
-                for impl_did in impl_list.iter() {
-                    for item_did in impl_items.get(impl_did).unwrap().iter() {
-                        if let Some(item_node_id) =
-                                self.tcx.map.as_local_node_id(item_did.def_id()) {
-                            if self.live_symbols.contains(&item_node_id) {
-                                return true;
-                            }
+        if let Some(impl_list) =
+                self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) {
+            for impl_did in impl_list.iter() {
+                for item_did in impl_items.get(impl_did).unwrap().iter() {
+                    if let Some(item_node_id) =
+                            self.tcx.map.as_local_node_id(item_did.def_id()) {
+                        if self.live_symbols.contains(&item_node_id) {
+                            return true;
                         }
                     }
                 }
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index b62368c2a98..24816d2b497 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -172,7 +172,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                 self.require_unsafe(expr.span, "use of inline assembly");
             }
             hir::ExprPath(..) => {
-                if let Def::Static(_, true) = self.tcx.resolve_expr(expr) {
+                if let Def::Static(_, true) = self.tcx.expect_def(expr.id) {
                     self.require_unsafe(expr.span, "use of mutable static");
                 }
             }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 48b5420dd6b..3b571ed0576 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -955,9 +955,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr,
                pat);
 
+        let tcx = &self.tcx();
         let mc = &self.mc;
         let infcx = self.mc.infcx;
-        let def_map = &self.tcx().def_map;
         let delegate = &mut self.delegate;
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
             match pat.node {
@@ -972,8 +972,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
                     // Each match binding is effectively an assignment to the
                     // binding being produced.
-                    let def = def_map.borrow().get(&pat.id).unwrap().full_def();
-                    if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, def) {
+                    if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
+                                                        tcx.expect_def(pat.id)) {
                         delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
                     }
 
@@ -993,40 +993,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                         }
                     }
                 }
-                PatKind::Vec(_, Some(ref slice_pat), _) => {
-                    // The `slice_pat` here creates a slice into
-                    // the original vector.  This is effectively a
-                    // borrow of the elements of the vector being
-                    // matched.
-
-                    let (slice_cmt, slice_mutbl, slice_r) =
-                        return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat));
-
-                    // Note: We declare here that the borrow
-                    // occurs upon entering the `[...]`
-                    // pattern. This implies that something like
-                    // `[a; b]` where `a` is a move is illegal,
-                    // because the borrow is already in effect.
-                    // In fact such a move would be safe-ish, but
-                    // it effectively *requires* that we use the
-                    // nulling out semantics to indicate when a
-                    // value has been moved, which we are trying
-                    // to move away from.  Otherwise, how can we
-                    // indicate that the first element in the
-                    // vector has been moved?  Eventually, we
-                    // could perhaps modify this rule to permit
-                    // `[..a, b]` where `b` is a move, because in
-                    // that case we can adjust the length of the
-                    // original vec accordingly, but we'd have to
-                    // make trans do the right thing, and it would
-                    // only work for `Box<[T]>`s. It seems simpler
-                    // to just require that people call
-                    // `vec.pop()` or `vec.unshift()`.
-                    let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
-                    delegate.borrow(pat.id, pat.span,
-                                    slice_cmt, slice_r,
-                                    slice_bk, RefBinding);
-                }
                 _ => {}
             }
         }));
@@ -1036,14 +1002,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         // to the above loop's visit of than the bindings that form
         // the leaves of the pattern tree structure.
         return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
-            let def_map = def_map.borrow();
-            let tcx = infcx.tcx;
-
             match pat.node {
                 PatKind::Struct(..) | PatKind::TupleStruct(..) |
                 PatKind::Path(..) | PatKind::QPath(..) => {
-                    match def_map.get(&pat.id).map(|d| d.full_def()) {
-                        Some(Def::Variant(enum_did, variant_did)) => {
+                    match tcx.expect_def(pat.id) {
+                        Def::Variant(enum_did, variant_did) => {
                             let downcast_cmt =
                                 if tcx.lookup_adt_def(enum_did).is_univariant() {
                                     cmt_pat
@@ -1059,7 +1022,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                             delegate.matched_pat(pat, downcast_cmt, match_mode);
                         }
 
-                        Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => {
+                        Def::Struct(..) | Def::TyAlias(..) => {
                             // A struct (in either the value or type
                             // namespace; we encounter the former on
                             // e.g. patterns for unit structs).
@@ -1071,8 +1034,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                             delegate.matched_pat(pat, cmt_pat, match_mode);
                         }
 
-                        Some(Def::Const(..)) |
-                        Some(Def::AssociatedConst(..)) => {
+                        Def::Const(..) | Def::AssociatedConst(..) => {
                             // This is a leaf (i.e. identifier binding
                             // or constant value to match); thus no
                             // `matched_pat` call.
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 07e69d85ff4..70158e9b9df 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -156,7 +156,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
 impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
     fn visit_expr(&mut self, expr: &hir::Expr) {
         if let hir::ExprPath(..) = expr.node {
-            match self.infcx.tcx.resolve_expr(expr) {
+            match self.infcx.tcx.expect_def(expr.id) {
                 Def::Fn(did) if self.def_id_is_transmute(did) => {
                     let typ = self.infcx.tcx.node_id_to_type(expr.id);
                     match typ.sty {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index f6ea10a70eb..ceffa366413 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -445,7 +445,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
     match expr.node {
       // live nodes required for uses or definitions of variables:
       hir::ExprPath(..) => {
-        let def = ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def();
+        let def = ir.tcx.expect_def(expr.id);
         debug!("expr {}: path that leads to {:?}", expr.id, def);
         if let Def::Local(..) = def {
             ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
@@ -695,8 +695,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             Some(_) => {
                 // Refers to a labeled loop. Use the results of resolve
                 // to find with one
-                match self.ir.tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
-                    Some(Def::Label(loop_id)) => loop_id,
+                match self.ir.tcx.expect_def(id) {
+                    Def::Label(loop_id) => loop_id,
                     _ => span_bug!(sp, "label on break/loop \
                                         doesn't refer to a loop")
                 }
@@ -1269,7 +1269,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
                    -> LiveNode {
-        match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
+        match self.ir.tcx.expect_def(expr.id) {
           Def::Local(_, nid) => {
             let ln = self.live_node(expr.id, expr.span);
             if acc != 0 {
@@ -1534,9 +1534,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
             hir::ExprPath(..) => {
-                if let Def::Local(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
-                                                                      .unwrap()
-                                                                      .full_def() {
+                if let Def::Local(_, nid) = self.ir.tcx.expect_def(expr.id) {
                     // Assignment to an immutable variable or argument: only legal
                     // if there is no later assignment. If this local is actually
                     // mutable, then check for a reassignment to flag the mutability
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 31e3db51f55..a345e94ebda 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -228,10 +228,10 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult<deref_kind> {
             Ok(deref_interior(InteriorField(PositionalField(0))))
         }
 
-        ty::TyArray(_, _) | ty::TySlice(_) | ty::TyStr => {
+        ty::TyArray(_, _) | ty::TySlice(_) => {
             // no deref of indexed content without supplying InteriorOffsetKind
             if let Some(context) = context {
-                Ok(deref_interior(InteriorElement(context, element_kind(t))))
+                Ok(deref_interior(InteriorElement(context, ElementKind::VecElement)))
             } else {
                 Err(())
             }
@@ -517,8 +517,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
           }
 
           hir::ExprPath(..) => {
-            let def = self.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
-            self.cat_def(expr.id, expr.span, expr_ty, def)
+            self.cat_def(expr.id, expr.span, expr_ty, self.tcx().expect_def(expr.id))
           }
 
           hir::ExprType(ref e, _) => {
@@ -981,18 +980,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         let method_call = ty::MethodCall::expr(elt.id());
         let method_ty = self.infcx.node_method_ty(method_call);
 
-        let element_ty = match method_ty {
+        let (element_ty, element_kind) = match method_ty {
             Some(method_ty) => {
                 let ref_ty = self.overloaded_method_return_ty(method_ty);
                 base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
 
                 // FIXME(#20649) -- why are we using the `self_ty` as the element type...?
                 let self_ty = method_ty.fn_sig().input(0);
-                self.tcx().no_late_bound_regions(&self_ty).unwrap()
+                (self.tcx().no_late_bound_regions(&self_ty).unwrap(),
+                 ElementKind::OtherElement)
             }
             None => {
                 match base_cmt.ty.builtin_index() {
-                    Some(ty) => ty,
+                    Some(ty) => (ty, ElementKind::VecElement),
                     None => {
                         return Err(());
                     }
@@ -1000,102 +1000,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
         };
 
-        let m = base_cmt.mutbl.inherit();
-        let ret = interior(elt, base_cmt.clone(), base_cmt.ty,
-                           m, context, element_ty);
+        let interior_elem = InteriorElement(context, element_kind);
+        let ret =
+            self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
         debug!("cat_index ret {:?}", ret);
         return Ok(ret);
-
-        fn interior<'tcx, N: ast_node>(elt: &N,
-                                       of_cmt: cmt<'tcx>,
-                                       vec_ty: Ty<'tcx>,
-                                       mutbl: MutabilityCategory,
-                                       context: InteriorOffsetKind,
-                                       element_ty: Ty<'tcx>) -> cmt<'tcx>
-        {
-            let interior_elem = InteriorElement(context, element_kind(vec_ty));
-            Rc::new(cmt_ {
-                id:elt.id(),
-                span:elt.span(),
-                cat:Categorization::Interior(of_cmt, interior_elem),
-                mutbl:mutbl,
-                ty:element_ty,
-                note: NoteNone
-            })
-        }
-    }
-
-    // Takes either a vec or a reference to a vec and returns the cmt for the
-    // underlying vec.
-    fn deref_vec<N:ast_node>(&self,
-                             elt: &N,
-                             base_cmt: cmt<'tcx>,
-                             context: InteriorOffsetKind)
-                             -> McResult<cmt<'tcx>>
-    {
-        let ret = match deref_kind(base_cmt.ty, Some(context))? {
-            deref_ptr(ptr) => {
-                // for unique ptrs, we inherit mutability from the
-                // owning reference.
-                let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);
-
-                // the deref is explicit in the resulting cmt
-                Rc::new(cmt_ {
-                    id:elt.id(),
-                    span:elt.span(),
-                    cat:Categorization::Deref(base_cmt.clone(), 0, ptr),
-                    mutbl:m,
-                    ty: match base_cmt.ty.builtin_deref(false, ty::NoPreference) {
-                        Some(mt) => mt.ty,
-                        None => bug!("Found non-derefable type")
-                    },
-                    note: NoteNone
-                })
-            }
-
-            deref_interior(_) => {
-                base_cmt
-            }
-        };
-        debug!("deref_vec ret {:?}", ret);
-        Ok(ret)
-    }
-
-    /// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is
-    /// the pattern `Q`, returns:
-    ///
-    /// * a cmt for `Q`
-    /// * the mutability and region of the slice `Q`
-    ///
-    /// These last two bits of info happen to be things that borrowck needs.
-    pub fn cat_slice_pattern(&self,
-                             vec_cmt: cmt<'tcx>,
-                             slice_pat: &hir::Pat)
-                             -> McResult<(cmt<'tcx>, hir::Mutability, ty::Region)> {
-        let slice_ty = self.node_ty(slice_pat.id)?;
-        let (slice_mutbl, slice_r) = vec_slice_info(slice_pat, slice_ty);
-        let context = InteriorOffsetKind::Pattern;
-        let cmt_vec = self.deref_vec(slice_pat, vec_cmt, context)?;
-        let cmt_slice = self.cat_index(slice_pat, cmt_vec, context)?;
-        return Ok((cmt_slice, slice_mutbl, slice_r));
-
-        /// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
-        /// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
-        /// have to recurse through rptrs.
-        fn vec_slice_info(pat: &hir::Pat, slice_ty: Ty)
-                          -> (hir::Mutability, ty::Region) {
-            match slice_ty.sty {
-                ty::TyRef(r, ref mt) => match mt.ty.sty {
-                    ty::TySlice(_) => (mt.mutbl, *r),
-                    _ => vec_slice_info(pat, mt.ty),
-                },
-
-                _ => {
-                    span_bug!(pat.span,
-                              "type of slice pattern is not a slice");
-                }
-            }
-        }
     }
 
     pub fn cat_imm_interior<N:ast_node>(&self,
@@ -1196,18 +1105,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         (*op)(self, cmt.clone(), pat);
 
-        let opt_def = if let Some(path_res) = self.tcx().def_map.borrow().get(&pat.id) {
-            if path_res.depth != 0 || path_res.base_def == Def::Err {
-                // Since patterns can be associated constants
-                // which are resolved during typeck, we might have
-                // some unresolved patterns reaching this stage
-                // without aborting
-                return Err(());
-            }
-            Some(path_res.full_def())
-        } else {
-            None
-        };
+        let opt_def = self.tcx().expect_def_or_none(pat.id);
+        if opt_def == Some(Def::Err) {
+            return Err(());
+        }
 
         // Note: This goes up here (rather than within the PatKind::TupleStruct arm
         // alone) because struct patterns can refer to struct types or
@@ -1244,8 +1145,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                     }
                 }
                 Some(Def::Struct(..)) => {
-                    let expected_len = match self.pat_ty(&pat) {
-                        Ok(&ty::TyS{sty: ty::TyStruct(adt_def, _), ..}) => {
+                    let expected_len = match self.pat_ty(&pat)?.sty {
+                        ty::TyStruct(adt_def, _) => {
                             adt_def.struct_variant().fields.len()
                         }
                         ref ty => {
@@ -1295,8 +1196,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
           PatKind::Tuple(ref subpats, ddpos) => {
             // (p1, ..., pN)
-            let expected_len = match self.pat_ty(&pat) {
-                Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(),
+            let expected_len = match self.pat_ty(&pat)?.sty {
+                ty::TyTuple(ref tys) => tys.len(),
                 ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
             };
             for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
@@ -1319,15 +1220,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
           PatKind::Vec(ref before, ref slice, ref after) => {
               let context = InteriorOffsetKind::Pattern;
-              let vec_cmt = self.deref_vec(pat, cmt, context)?;
-              let elt_cmt = self.cat_index(pat, vec_cmt, context)?;
+              let elt_cmt = self.cat_index(pat, cmt, context)?;
               for before_pat in before {
                   self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
               }
               if let Some(ref slice_pat) = *slice {
-                  let slice_ty = self.pat_ty(&slice_pat)?;
-                  let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
-                  self.cat_pattern_(slice_cmt, &slice_pat, op)?;
+                  self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
               }
               for after_pat in after {
                   self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
@@ -1620,18 +1518,6 @@ impl fmt::Debug for InteriorKind {
     }
 }
 
-fn element_kind(t: Ty) -> ElementKind {
-    match t.sty {
-        ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
-        ty::TyBox(ty) => match ty.sty {
-            ty::TySlice(_) => VecElement,
-            _ => OtherElement
-        },
-        ty::TyArray(..) | ty::TySlice(_) => VecElement,
-        _ => OtherElement
-    }
-}
-
 impl fmt::Debug for Upvar {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{:?}/{:?}", self.id, self.kind)
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 55d75ace081..6ea0fa20c57 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -92,13 +92,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &hir::Expr) {
         match expr.node {
             hir::ExprPath(..) => {
-                let def = match self.tcx.def_map.borrow().get(&expr.id) {
-                    Some(d) => d.full_def(),
-                    None => {
-                        span_bug!(expr.span, "def ID not in def map?!")
-                    }
-                };
-
+                let def = self.tcx.expect_def(expr.id);
                 let def_id = def.def_id();
                 if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
                     if self.def_id_represents_local_inlined_item(def_id) {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index dcc84fb0439..78d9f5c9b7c 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -456,8 +456,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) {
     fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
         match ex.node {
             hir::ExprWhile(_, _, Some(label)) |
-            hir::ExprLoop(_, Some(label)) => Some((label.node.unhygienize(),
-                                                   label.span)),
+            hir::ExprLoop(_, Some(label)) => Some((label.node, label.span)),
             _ => None,
         }
     }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index eb1fb43789f..3744f564fa2 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -494,7 +494,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // individually as it's possible to have a stable trait with unstable
         // items.
         hir::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
-            let trait_did = tcx.def_map.borrow().get(&t.ref_id).unwrap().def_id();
+            let trait_did = tcx.expect_def(t.ref_id).def_id();
             let trait_items = tcx.trait_items(trait_did);
 
             for impl_item in impl_items {
@@ -580,7 +580,8 @@ pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             cb: &mut FnMut(DefId, Span,
                                            &Option<&Stability>,
                                            &Option<Deprecation>)) {
-    match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
+    // Paths in import prefixes may have no resolution.
+    match tcx.expect_def_or_none(id) {
         Some(Def::PrimTy(..)) => {}
         Some(Def::SelfTy(..)) => {}
         Some(def) => {
@@ -595,12 +596,11 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       cb: &mut FnMut(DefId, Span,
                                                      &Option<&Stability>,
                                                      &Option<Deprecation>)) {
-    match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) {
-        Some(Def::PrimTy(..)) => {}
-        Some(def) => {
+    match tcx.expect_def(item.node.id()) {
+        Def::PrimTy(..) => {}
+        def => {
             maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
         }
-        None => {}
     }
 }
 
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
new file mode 100644
index 00000000000..138fed2d64e
--- /dev/null
+++ b/src/librustc/mir/cache.rs
@@ -0,0 +1,69 @@
+// 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::cell::{Ref, RefCell};
+use rustc_data_structures::indexed_vec::IndexVec;
+
+use mir::repr::{Mir, BasicBlock};
+
+use rustc_serialize as serialize;
+
+#[derive(Clone)]
+pub struct Cache {
+    predecessors: RefCell<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>>
+}
+
+
+impl serialize::Encodable for Cache {
+    fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        serialize::Encodable::encode(&(), s)
+    }
+}
+
+impl serialize::Decodable for Cache {
+    fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+        serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+    }
+}
+
+
+impl Cache {
+    pub fn new() -> Self {
+        Cache {
+            predecessors: RefCell::new(None)
+        }
+    }
+
+    pub fn invalidate(&self) {
+        // FIXME: consider being more fine-grained
+        *self.predecessors.borrow_mut() = None;
+    }
+
+    pub fn predecessors(&self, mir: &Mir) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> {
+        if self.predecessors.borrow().is_none() {
+            *self.predecessors.borrow_mut() = Some(calculate_predecessors(mir));
+        }
+
+        Ref::map(self.predecessors.borrow(), |p| p.as_ref().unwrap())
+    }
+}
+
+fn calculate_predecessors(mir: &Mir) -> IndexVec<BasicBlock, Vec<BasicBlock>> {
+    let mut result = IndexVec::from_elem(vec![], mir.basic_blocks());
+    for (bb, data) in mir.basic_blocks().iter_enumerated() {
+        if let Some(ref term) = data.terminator {
+            for &tgt in term.successors().iter() {
+                result[tgt].push(bb);
+            }
+        }
+    }
+
+    result
+}
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 9666741d032..a6052f9aa75 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -11,6 +11,7 @@
 use graphviz::IntoCow;
 use middle::const_val::ConstVal;
 use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use hir::def_id::DefId;
 use ty::subst::Substs;
 use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
@@ -19,43 +20,70 @@ use rustc_back::slice;
 use hir::InlineAsm;
 use std::ascii;
 use std::borrow::{Cow};
+use std::cell::Ref;
 use std::fmt::{self, Debug, Formatter, Write};
 use std::{iter, u32};
 use std::ops::{Index, IndexMut};
 use syntax::ast::{self, Name};
 use syntax::codemap::Span;
 
+use super::cache::Cache;
+
+macro_rules! newtype_index {
+    ($name:ident, $debug_name:expr) => (
+        #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
+         RustcEncodable, RustcDecodable)]
+        pub struct $name(u32);
+
+        impl Idx for $name {
+            fn new(value: usize) -> Self {
+                assert!(value < (u32::MAX) as usize);
+                $name(value as u32)
+            }
+            fn index(self) -> usize {
+                self.0 as usize
+            }
+        }
+
+        impl Debug for $name {
+            fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
+                write!(fmt, "{}{}", $debug_name, self.0)
+            }
+        }
+    )
+}
+
 /// Lowered representation of a single function.
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Mir<'tcx> {
     /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
     /// that indexes into this vector.
-    pub basic_blocks: Vec<BasicBlockData<'tcx>>,
+    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
 
-    /// List of lexical scopes; these are referenced by statements and
-    /// used (eventually) for debuginfo. Indexed by a `ScopeId`.
-    pub scopes: Vec<ScopeData>,
+    /// List of visibility (lexical) scopes; these are referenced by statements
+    /// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`.
+    pub visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
 
     /// Rvalues promoted from this function, such as borrows of constants.
     /// Each of them is the Mir of a constant with the fn's type parameters
     /// in scope, but no vars or args and a separate set of temps.
-    pub promoted: Vec<Mir<'tcx>>,
+    pub promoted: IndexVec<Promoted, Mir<'tcx>>,
 
     /// Return type of the function.
     pub return_ty: FnOutput<'tcx>,
 
     /// Variables: these are stack slots corresponding to user variables. They may be
     /// assigned many times.
-    pub var_decls: Vec<VarDecl<'tcx>>,
+    pub var_decls: IndexVec<Var, VarDecl<'tcx>>,
 
     /// Args: these are stack slots corresponding to the input arguments.
-    pub arg_decls: Vec<ArgDecl<'tcx>>,
+    pub arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
 
     /// Temp declarations: stack slots that for temporaries created by
     /// the compiler. These are assigned once, but they are not SSA
     /// values in that it is possible to borrow them and mutate them
     /// through the resulting reference.
-    pub temp_decls: Vec<TempDecl<'tcx>>,
+    pub temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
 
     /// Names and capture modes of all the closure upvars, assuming
     /// the first argument is either the closure or a reference to it.
@@ -63,24 +91,92 @@ pub struct Mir<'tcx> {
 
     /// A span representing this MIR, for error reporting
     pub span: Span,
+
+    /// A cache for various calculations
+    cache: Cache
 }
 
 /// where execution begins
 pub const START_BLOCK: BasicBlock = BasicBlock(0);
 
 impl<'tcx> Mir<'tcx> {
-    pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
-        (0..self.basic_blocks.len())
-            .map(|i| BasicBlock::new(i))
-            .collect()
+    pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+               visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
+               promoted: IndexVec<Promoted, Mir<'tcx>>,
+               return_ty: FnOutput<'tcx>,
+               var_decls: IndexVec<Var, VarDecl<'tcx>>,
+               arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
+               temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
+               upvar_decls: Vec<UpvarDecl>,
+               span: Span) -> Self
+    {
+        Mir {
+            basic_blocks: basic_blocks,
+            visibility_scopes: visibility_scopes,
+            promoted: promoted,
+            return_ty: return_ty,
+            var_decls: var_decls,
+            arg_decls: arg_decls,
+            temp_decls: temp_decls,
+            upvar_decls: upvar_decls,
+            span: span,
+            cache: Cache::new()
+        }
+    }
+
+    #[inline]
+    pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        &self.basic_blocks
+    }
+
+    #[inline]
+    pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        self.cache.invalidate();
+        &mut self.basic_blocks
     }
 
-    pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> {
-        &self.basic_blocks[bb.index()]
+    #[inline]
+    pub fn predecessors(&self) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> {
+        self.cache.predecessors(self)
+    }
+
+    #[inline]
+    pub fn predecessors_for(&self, bb: BasicBlock) -> Ref<Vec<BasicBlock>> {
+        Ref::map(self.predecessors(), |p| &p[bb])
+    }
+
+    /// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
+    /// to their index in the whole list of locals. This is useful if you
+    /// want to treat all locals the same instead of repeating yourself.
+    pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
+        let idx = match *lvalue {
+            Lvalue::Arg(arg) => arg.index(),
+            Lvalue::Var(var) => {
+                self.arg_decls.len() +
+                var.index()
+            }
+            Lvalue::Temp(temp) => {
+                self.arg_decls.len() +
+                self.var_decls.len() +
+                temp.index()
+            }
+            Lvalue::ReturnPointer => {
+                self.arg_decls.len() +
+                self.var_decls.len() +
+                self.temp_decls.len()
+            }
+            Lvalue::Static(_) |
+            Lvalue::Projection(_) => return None
+        };
+        Some(Local::new(idx))
     }
 
-    pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> {
-        &mut self.basic_blocks[bb.index()]
+    /// Counts the number of locals, such that that local_index
+    /// will always return an index smaller than this count.
+    pub fn count_locals(&self) -> usize {
+        self.arg_decls.len() +
+        self.var_decls.len() +
+        self.temp_decls.len() + 1
     }
 }
 
@@ -89,17 +185,29 @@ impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
 
     #[inline]
     fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
-        self.basic_block_data(index)
+        &self.basic_blocks()[index]
     }
 }
 
 impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> {
     #[inline]
     fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
-        self.basic_block_data_mut(index)
+        &mut self.basic_blocks_mut()[index]
     }
 }
 
+/// Grouped information about the source code origin of a MIR entity.
+/// Intended to be inspected by diagnostics and debuginfo.
+/// Most passes can work with it as a whole, within a single function.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
+pub struct SourceInfo {
+    /// Source span for the AST pertaining to this MIR entity.
+    pub span: Span,
+
+    /// The lexical visibility scope, i.e. which bindings can be seen.
+    pub scope: VisibilityScope
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Mutability and borrow kinds
 
@@ -172,11 +280,8 @@ pub struct VarDecl<'tcx> {
     /// type inferred for this variable (`let x: ty = ...`)
     pub ty: Ty<'tcx>,
 
-    /// scope in which variable was declared
-    pub scope: ScopeId,
-
-    /// span where variable was declared
-    pub span: Span,
+    /// source information (span, scope, etc.) for the declaration
+    pub source_info: SourceInfo,
 }
 
 /// A "temp" is a temporary that we place on the stack. They are
@@ -222,31 +327,7 @@ pub struct UpvarDecl {
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlock
 
-/// The index of a particular basic block. The index is into the `basic_blocks`
-/// list of the `Mir`.
-///
-/// (We use a `u32` internally just to save memory.)
-#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
-         RustcEncodable, RustcDecodable)]
-pub struct BasicBlock(u32);
-
-impl BasicBlock {
-    pub fn new(index: usize) -> BasicBlock {
-        assert!(index < (u32::MAX as usize));
-        BasicBlock(index as u32)
-    }
-
-    /// Extract the index.
-    pub fn index(self) -> usize {
-        self.0 as usize
-    }
-}
-
-impl Debug for BasicBlock {
-    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        write!(fmt, "bb{}", self.0)
-    }
-}
+newtype_index!(BasicBlock, "bb");
 
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlockData and Terminator
@@ -275,8 +356,7 @@ pub struct BasicBlockData<'tcx> {
 
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct Terminator<'tcx> {
-    pub span: Span,
-    pub scope: ScopeId,
+    pub source_info: SourceInfo,
     pub kind: TerminatorKind<'tcx>
 }
 
@@ -328,6 +408,9 @@ pub enum TerminatorKind<'tcx> {
     /// have been filled in by now. This should occur at most once.
     Return,
 
+    /// Indicates a terminator that can never be reached.
+    Unreachable,
+
     /// Drop the Lvalue
     Drop {
         location: Lvalue<'tcx>,
@@ -386,6 +469,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             SwitchInt { targets: ref b, .. } => b[..].into_cow(),
             Resume => (&[]).into_cow(),
             Return => (&[]).into_cow(),
+            Unreachable => (&[]).into_cow(),
             Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(),
             Call { destination: Some((_, ref t)), cleanup: None, .. } =>
                 slice::ref_slice(t).into_cow(),
@@ -415,6 +499,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(),
             Resume => Vec::new(),
             Return => Vec::new(),
+            Unreachable => Vec::new(),
             Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c],
             Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t],
             Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c],
@@ -493,6 +578,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
             Return => write!(fmt, "return"),
             Resume => write!(fmt, "resume"),
+            Unreachable => write!(fmt, "unreachable"),
             Drop { ref location, .. } => write!(fmt, "drop({:?})", location),
             DropAndReplace { ref location, ref value, .. } =>
                 write!(fmt, "replace({:?} <- {:?})", location, value),
@@ -536,7 +622,7 @@ impl<'tcx> TerminatorKind<'tcx> {
     pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
         use self::TerminatorKind::*;
         match *self {
-            Return | Resume => vec![],
+            Return | Resume | Unreachable => vec![],
             Goto { .. } => vec!["".into()],
             If { .. } => vec!["true".into(), "false".into()],
             Switch { ref adt_def, .. } => {
@@ -587,8 +673,7 @@ pub enum AssertMessage<'tcx> {
 
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Statement<'tcx> {
-    pub span: Span,
-    pub scope: ScopeId,
+    pub source_info: SourceInfo,
     pub kind: StatementKind<'tcx>,
 }
 
@@ -609,19 +694,24 @@ impl<'tcx> Debug for Statement<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Lvalues
 
+newtype_index!(Var, "var");
+newtype_index!(Temp, "tmp");
+newtype_index!(Arg, "arg");
+newtype_index!(Local, "local");
+
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Lvalue<'tcx> {
     /// local variable declared by the user
-    Var(u32),
+    Var(Var),
 
     /// temporary introduced during lowering into MIR
-    Temp(u32),
+    Temp(Temp),
 
     /// formal parameter of the function; note that these are NOT the
     /// bindings that the user declares, which are vars
-    Arg(u32),
+    Arg(Arg),
 
     /// static or static mut variable
     Static(DefId),
@@ -667,6 +757,14 @@ pub enum ProjectionElem<'tcx, V> {
         from_end: bool,
     },
 
+    /// These indices are generated by slice patterns.
+    ///
+    /// slice[from:-to] in Python terms.
+    Subslice {
+        from: u32,
+        to: u32,
+    },
+
     /// "Downcast" to a variant of an ADT. Currently, we only introduce
     /// this for ADTs with more than one variant. It may be better to
     /// just introduce it always, or always for enums.
@@ -681,20 +779,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Operand<'tcx>>;
 /// and the index is an operand.
 pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Operand<'tcx>>;
 
-/// Index into the list of fields found in a `VariantDef`
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub struct Field(u32);
-
-impl Field {
-    pub fn new(value: usize) -> Field {
-        assert!(value < (u32::MAX) as usize);
-        Field(value as u32)
-    }
-
-    pub fn index(self) -> usize {
-        self.0 as usize
-    }
-}
+newtype_index!(Field, "field");
 
 impl<'tcx> Lvalue<'tcx> {
     pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
@@ -722,12 +807,9 @@ impl<'tcx> Debug for Lvalue<'tcx> {
         use self::Lvalue::*;
 
         match *self {
-            Var(id) =>
-                write!(fmt, "var{:?}", id),
-            Arg(id) =>
-                write!(fmt, "arg{:?}", id),
-            Temp(id) =>
-                write!(fmt, "tmp{:?}", id),
+            Var(id) => write!(fmt, "{:?}", id),
+            Arg(id) => write!(fmt, "{:?}", id),
+            Temp(id) => write!(fmt, "{:?}", id),
             Static(def_id) =>
                 write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
             ReturnPointer =>
@@ -746,6 +828,14 @@ impl<'tcx> Debug for Lvalue<'tcx> {
                         write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length),
                     ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
                         write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length),
+                    ProjectionElem::Subslice { from, to } if to == 0 =>
+                        write!(fmt, "{:?}[{:?}:", data.base, from),
+                    ProjectionElem::Subslice { from, to } if from == 0 =>
+                        write!(fmt, "{:?}[:-{:?}]", data.base, to),
+                    ProjectionElem::Subslice { from, to } =>
+                        write!(fmt, "{:?}[{:?}:-{:?}]", data.base,
+                               from, to),
+
                 },
         }
     }
@@ -754,40 +844,13 @@ impl<'tcx> Debug for Lvalue<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Scopes
 
-impl Index<ScopeId> for Vec<ScopeData> {
-    type Output = ScopeData;
-
-    #[inline]
-    fn index(&self, index: ScopeId) -> &ScopeData {
-        &self[index.index()]
-    }
-}
-
-impl IndexMut<ScopeId> for Vec<ScopeData> {
-    #[inline]
-    fn index_mut(&mut self, index: ScopeId) -> &mut ScopeData {
-        &mut self[index.index()]
-    }
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
-pub struct ScopeId(u32);
-
-impl ScopeId {
-    pub fn new(index: usize) -> ScopeId {
-        assert!(index < (u32::MAX as usize));
-        ScopeId(index as u32)
-    }
-
-    pub fn index(self) -> usize {
-        self.0 as usize
-    }
-}
+newtype_index!(VisibilityScope, "scope");
+pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0);
 
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct ScopeData {
+pub struct VisibilityScopeData {
     pub span: Span,
-    pub parent_scope: Option<ScopeId>,
+    pub parent_scope: Option<VisibilityScope>,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -846,17 +909,6 @@ pub enum Rvalue<'tcx> {
     /// away after type-checking and before lowering.
     Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>),
 
-    /// Generates a slice of the form `&input[from_start..L-from_end]`
-    /// where `L` is the length of the slice. This is only created by
-    /// slice pattern matching, so e.g. a pattern of the form `[x, y,
-    /// .., z]` might create a slice with `from_start=2` and
-    /// `from_end=1`.
-    Slice {
-        input: Lvalue<'tcx>,
-        from_start: usize,
-        from_end: usize,
-    },
-
     InlineAsm {
         asm: InlineAsm,
         outputs: Vec<Lvalue<'tcx>>,
@@ -962,8 +1014,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             InlineAsm { ref asm, ref outputs, ref inputs } => {
                 write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
             }
-            Slice { ref input, from_start, from_end } =>
-                write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
 
             Ref(_, borrow_kind, ref lv) => {
                 let kind_str = match borrow_kind {
@@ -1067,6 +1117,8 @@ impl<'tcx> Debug for TypedConstVal<'tcx> {
     }
 }
 
+newtype_index!(Promoted, "promoted");
+
 #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum Literal<'tcx> {
     Item {
@@ -1078,7 +1130,7 @@ pub enum Literal<'tcx> {
     },
     Promoted {
         // Index into the `promoted` vector of `Mir`.
-        index: usize
+        index: Promoted
     },
 }
 
@@ -1102,7 +1154,7 @@ impl<'tcx> Debug for Literal<'tcx> {
                 fmt_const_val(fmt, value)
             }
             Promoted { index } => {
-                write!(fmt, "promoted{}", index)
+                write!(fmt, "{:?}", index)
             }
         }
     }
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index d0ac98a7958..e3905c39daa 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -59,6 +59,20 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
                 LvalueTy::Ty {
                     ty: self.to_ty(tcx).builtin_index().unwrap()
                 },
+            ProjectionElem::Subslice { from, to } => {
+                let ty = self.to_ty(tcx);
+                LvalueTy::Ty {
+                    ty: match ty.sty {
+                        ty::TyArray(inner, size) => {
+                            tcx.mk_array(inner, size-(from as usize)-(to as usize))
+                        }
+                        ty::TySlice(..) => ty,
+                        _ => {
+                            bug!("cannot subslice non-array type: `{:?}`", self)
+                        }
+                    }
+                }
+            }
             ProjectionElem::Downcast(adt_def1, index) =>
                 match self.to_ty(tcx).sty {
                     ty::TyEnum(adt_def, substs) => {
@@ -140,11 +154,11 @@ impl<'a, 'gcx, 'tcx> Mir<'tcx> {
     {
         match *lvalue {
             Lvalue::Var(index) =>
-                LvalueTy::Ty { ty: self.var_decls[index as usize].ty },
+                LvalueTy::Ty { ty: self.var_decls[index].ty },
             Lvalue::Temp(index) =>
-                LvalueTy::Ty { ty: self.temp_decls[index as usize].ty },
+                LvalueTy::Ty { ty: self.temp_decls[index].ty },
             Lvalue::Arg(index) =>
-                LvalueTy::Ty { ty: self.arg_decls[index as usize].ty },
+                LvalueTy::Ty { ty: self.arg_decls[index].ty },
             Lvalue::Static(def_id) =>
                 LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
             Lvalue::ReturnPointer =>
@@ -219,7 +233,6 @@ impl<'a, 'gcx, 'tcx> Mir<'tcx> {
                     }
                 }
             }
-            Rvalue::Slice { .. } => None,
             Rvalue::InlineAsm { .. } => None
         }
     }
diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs
index 828a48532a2..4ca3907d4e6 100644
--- a/src/librustc/mir/transform.rs
+++ b/src/librustc/mir/transform.rs
@@ -13,10 +13,12 @@ use hir;
 use hir::map::DefPathData;
 use hir::def_id::DefId;
 use mir::mir_map::MirMap;
-use mir::repr::Mir;
+use mir::repr::{Mir, Promoted};
 use ty::TyCtxt;
 use syntax::ast::NodeId;
 
+use std::fmt;
+
 /// Where a specific Mir comes from.
 #[derive(Debug, Copy, Clone)]
 pub enum MirSource {
@@ -30,7 +32,7 @@ pub enum MirSource {
     Static(NodeId, hir::Mutability),
 
     /// Promoted rvalues within a function.
-    Promoted(NodeId, usize)
+    Promoted(NodeId, Promoted)
 }
 
 impl<'a, 'tcx> MirSource {
@@ -70,40 +72,76 @@ impl<'a, 'tcx> MirSource {
 
 /// Various information about pass.
 pub trait Pass {
-    // fn name() for printouts of various sorts?
     // fn should_run(Session) to check if pass should run?
     fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
         DepNode::MirPass(def_id)
     }
+    fn name(&self) -> &str {
+        let name = unsafe { ::std::intrinsics::type_name::<Self>() };
+        if let Some(tail) = name.rfind(":") {
+            &name[tail+1..]
+        } else {
+            name
+        }
+    }
+    fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> { None }
 }
 
 /// A pass which inspects the whole MirMap.
 pub trait MirMapPass<'tcx>: Pass {
-    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>);
+    fn run_pass<'a>(
+        &mut self,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        map: &mut MirMap<'tcx>,
+        hooks: &mut [Box<for<'s> MirPassHook<'s>>]);
+}
+
+pub trait MirPassHook<'tcx>: Pass {
+    fn on_mir_pass<'a>(
+        &mut self,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        src: MirSource,
+        mir: &Mir<'tcx>,
+        pass: &Pass,
+        is_after: bool
+    );
 }
 
 /// A pass which inspects Mir of functions in isolation.
 pub trait MirPass<'tcx>: Pass {
-    fn run_pass_on_promoted<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                item_id: NodeId, index: usize,
-                                mir: &mut Mir<'tcx>) {
-        self.run_pass(tcx, MirSource::Promoted(item_id, index), mir);
-    }
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     src: MirSource, mir: &mut Mir<'tcx>);
 }
 
 impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
-    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) {
+    fn run_pass<'a>(&mut self,
+                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    map: &mut MirMap<'tcx>,
+                    hooks: &mut [Box<for<'s> MirPassHook<'s>>])
+    {
         for (&id, mir) in &mut map.map {
             let def_id = tcx.map.local_def_id(id);
             let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
 
             let src = MirSource::from_node(tcx, id);
+
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, false);
+            }
             MirPass::run_pass(self, tcx, src, mir);
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, true);
+            }
 
-            for (i, mir) in mir.promoted.iter_mut().enumerate() {
-                self.run_pass_on_promoted(tcx, id, i, mir);
+            for (i, mir) in mir.promoted.iter_enumerated_mut() {
+                let src = MirSource::Promoted(id, i);
+                for hook in &mut *hooks {
+                    hook.on_mir_pass(tcx, src, mir, self, false);
+                }
+                MirPass::run_pass(self, tcx, src, mir);
+                for hook in &mut *hooks {
+                    hook.on_mir_pass(tcx, src, mir, self, true);
+                }
             }
         }
     }
@@ -112,6 +150,7 @@ impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
 /// A manager for MIR passes.
 pub struct Passes {
     passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>,
+    pass_hooks: Vec<Box<for<'tcx> MirPassHook<'tcx>>>,
     plugin_passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>
 }
 
@@ -119,6 +158,7 @@ impl<'a, 'tcx> Passes {
     pub fn new() -> Passes {
         let passes = Passes {
             passes: Vec::new(),
+            pass_hooks: Vec::new(),
             plugin_passes: Vec::new()
         };
         passes
@@ -126,10 +166,10 @@ impl<'a, 'tcx> Passes {
 
     pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) {
         for pass in &mut self.plugin_passes {
-            pass.run_pass(tcx, map);
+            pass.run_pass(tcx, map, &mut self.pass_hooks);
         }
         for pass in &mut self.passes {
-            pass.run_pass(tcx, map);
+            pass.run_pass(tcx, map, &mut self.pass_hooks);
         }
     }
 
@@ -137,6 +177,11 @@ impl<'a, 'tcx> Passes {
     pub fn push_pass(&mut self, pass: Box<for<'b> MirMapPass<'b>>) {
         self.passes.push(pass);
     }
+
+    /// Pushes a pass hook.
+    pub fn push_hook(&mut self, hook: Box<for<'b> MirPassHook<'b>>) {
+        self.pass_hooks.push(hook);
+    }
 }
 
 /// Copies the plugin passes.
diff --git a/src/librustc_mir/traversal.rs b/src/librustc/mir/traversal.rs
index c58b5c87724..1af5123b4df 100644
--- a/src/librustc_mir/traversal.rs
+++ b/src/librustc/mir/traversal.rs
@@ -11,8 +11,9 @@
 use std::vec;
 
 use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::Idx;
 
-use rustc::mir::repr::*;
+use super::repr::*;
 
 /// Preorder traversal of a graph.
 ///
@@ -44,7 +45,7 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> {
 
         Preorder {
             mir: mir,
-            visited: BitVector::new(mir.basic_blocks.len()),
+            visited: BitVector::new(mir.basic_blocks().len()),
             worklist: worklist
         }
     }
@@ -63,7 +64,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
                 continue;
             }
 
-            let data = self.mir.basic_block_data(idx);
+            let data = &self.mir[idx];
 
             if let Some(ref term) = data.terminator {
                 for &succ in term.successors().iter() {
@@ -106,12 +107,12 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
     pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
         let mut po = Postorder {
             mir: mir,
-            visited: BitVector::new(mir.basic_blocks.len()),
+            visited: BitVector::new(mir.basic_blocks().len()),
             visit_stack: Vec::new()
         };
 
 
-        let data = po.mir.basic_block_data(root);
+        let data = &po.mir[root];
 
         if let Some(ref term) = data.terminator {
             po.visited.insert(root.index());
@@ -185,9 +186,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
             };
 
             if self.visited.insert(bb.index()) {
-                let data = self.mir.basic_block_data(bb);
-
-                if let Some(ref term) = data.terminator {
+                if let Some(ref term) = self.mir[bb].terminator {
                     let succs = term.successors().into_owned().into_iter();
                     self.visit_stack.push((bb, succs));
                 }
@@ -209,10 +208,7 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
             self.traverse_successor();
         }
 
-        next.map(|(bb, _)| {
-            let data = self.mir.basic_block_data(bb);
-            (bb, data)
-        })
+        next.map(|(bb, _)| (bb, &self.mir[bb]))
     }
 }
 
@@ -278,9 +274,6 @@ impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> {
         if self.idx == 0 { return None; }
         self.idx -= 1;
 
-        self.blocks.get(self.idx).map(|&bb| {
-            let data = self.mir.basic_block_data(bb);
-            (bb, data)
-        })
+        self.blocks.get(self.idx).map(|&bb| (bb, &self.mir[bb]))
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 5c9582b945b..bc45a730c2e 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -15,6 +15,7 @@ use ty::{ClosureSubsts, FnOutput, Region, Ty};
 use mir::repr::*;
 use rustc_const_math::ConstUsize;
 use rustc_data_structures::tuple_slice::TupleSlice;
+use rustc_data_structures::indexed_vec::Idx;
 use syntax::codemap::Span;
 
 // # The MIR Visitor
@@ -97,9 +98,9 @@ macro_rules! make_mir_visitor {
                 self.super_basic_block_data(block, data);
             }
 
-            fn visit_scope_data(&mut self,
-                                scope_data: & $($mutability)* ScopeData) {
-                self.super_scope_data(scope_data);
+            fn visit_visibility_scope_data(&mut self,
+                                           scope_data: & $($mutability)* VisibilityScopeData) {
+                self.super_visibility_scope_data(scope_data);
             }
 
             fn visit_statement(&mut self,
@@ -186,6 +187,11 @@ macro_rules! make_mir_visitor {
                 self.super_span(span);
             }
 
+            fn visit_source_info(&mut self,
+                                 source_info: & $($mutability)* SourceInfo) {
+                self.super_source_info(source_info);
+            }
+
             fn visit_fn_output(&mut self,
                                fn_output: & $($mutability)* FnOutput<'tcx>) {
                 self.super_fn_output(fn_output);
@@ -236,9 +242,9 @@ macro_rules! make_mir_visitor {
                 self.super_arg_decl(arg_decl);
             }
 
-            fn visit_scope_id(&mut self,
-                              scope_id: & $($mutability)* ScopeId) {
-                self.super_scope_id(scope_id);
+            fn visit_visibility_scope(&mut self,
+                                      scope: & $($mutability)* VisibilityScope) {
+                self.super_visibility_scope(scope);
             }
 
             // The `super_xxx` methods comprise the default behavior and are
@@ -246,42 +252,30 @@ macro_rules! make_mir_visitor {
 
             fn super_mir(&mut self,
                          mir: & $($mutability)* Mir<'tcx>) {
-                let Mir {
-                    ref $($mutability)* basic_blocks,
-                    ref $($mutability)* scopes,
-                    promoted: _, // Visited by passes separately.
-                    ref $($mutability)* return_ty,
-                    ref $($mutability)* var_decls,
-                    ref $($mutability)* arg_decls,
-                    ref $($mutability)* temp_decls,
-                    upvar_decls: _,
-                    ref $($mutability)* span,
-                } = *mir;
-
-                for (index, data) in basic_blocks.into_iter().enumerate() {
+                for index in 0..mir.basic_blocks().len() {
                     let block = BasicBlock::new(index);
-                    self.visit_basic_block_data(block, data);
+                    self.visit_basic_block_data(block, &$($mutability)* mir[block]);
                 }
 
-                for scope in scopes {
-                    self.visit_scope_data(scope);
+                for scope in &$($mutability)* mir.visibility_scopes {
+                    self.visit_visibility_scope_data(scope);
                 }
 
-                self.visit_fn_output(return_ty);
+                self.visit_fn_output(&$($mutability)* mir.return_ty);
 
-                for var_decl in var_decls {
+                for var_decl in &$($mutability)* mir.var_decls {
                     self.visit_var_decl(var_decl);
                 }
 
-                for arg_decl in arg_decls {
+                for arg_decl in &$($mutability)* mir.arg_decls {
                     self.visit_arg_decl(arg_decl);
                 }
 
-                for temp_decl in temp_decls {
+                for temp_decl in &$($mutability)* mir.temp_decls {
                     self.visit_temp_decl(temp_decl);
                 }
 
-                self.visit_span(span);
+                self.visit_span(&$($mutability)* mir.span);
             }
 
             fn super_basic_block_data(&mut self,
@@ -302,16 +296,16 @@ macro_rules! make_mir_visitor {
                 }
             }
 
-            fn super_scope_data(&mut self,
-                                scope_data: & $($mutability)* ScopeData) {
-                let ScopeData {
+            fn super_visibility_scope_data(&mut self,
+                                           scope_data: & $($mutability)* VisibilityScopeData) {
+                let VisibilityScopeData {
                     ref $($mutability)* span,
                     ref $($mutability)* parent_scope,
                 } = *scope_data;
 
                 self.visit_span(span);
                 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
-                    self.visit_scope_id(parent_scope);
+                    self.visit_visibility_scope(parent_scope);
                 }
             }
 
@@ -319,13 +313,11 @@ macro_rules! make_mir_visitor {
                                block: BasicBlock,
                                statement: & $($mutability)* Statement<'tcx>) {
                 let Statement {
-                    ref $($mutability)* span,
-                    ref $($mutability)* scope,
+                    ref $($mutability)* source_info,
                     ref $($mutability)* kind,
                 } = *statement;
 
-                self.visit_span(span);
-                self.visit_scope_id(scope);
+                self.visit_source_info(source_info);
                 match *kind {
                     StatementKind::Assign(ref $($mutability)* lvalue,
                                           ref $($mutability)* rvalue) => {
@@ -346,13 +338,11 @@ macro_rules! make_mir_visitor {
                                 block: BasicBlock,
                                 terminator: &$($mutability)* Terminator<'tcx>) {
                 let Terminator {
-                    ref $($mutability)* span,
-                    ref $($mutability)* scope,
+                    ref $($mutability)* source_info,
                     ref $($mutability)* kind,
                 } = *terminator;
 
-                self.visit_span(span);
-                self.visit_scope_id(scope);
+                self.visit_source_info(source_info);
                 self.visit_terminator_kind(block, kind);
             }
 
@@ -396,7 +386,8 @@ macro_rules! make_mir_visitor {
                     }
 
                     TerminatorKind::Resume |
-                    TerminatorKind::Return => {
+                    TerminatorKind::Return |
+                    TerminatorKind::Unreachable => {
                     }
 
                     TerminatorKind::Drop { ref $($mutability)* location,
@@ -532,15 +523,6 @@ macro_rules! make_mir_visitor {
                         }
                     }
 
-                    Rvalue::Slice { ref $($mutability)* input,
-                                    from_start,
-                                    from_end } => {
-                        self.visit_lvalue(input, LvalueContext::Slice {
-                            from_start: from_start,
-                            from_end: from_end,
-                        });
-                    }
-
                     Rvalue::InlineAsm { ref $($mutability)* outputs,
                                         ref $($mutability)* inputs,
                                         asm: _ } => {
@@ -601,6 +583,8 @@ macro_rules! make_mir_visitor {
                 match *proj {
                     ProjectionElem::Deref => {
                     }
+                    ProjectionElem::Subslice { from: _, to: _ } => {
+                    }
                     ProjectionElem::Field(_field, ref $($mutability)* ty) => {
                         self.visit_ty(ty);
                     }
@@ -622,13 +606,11 @@ macro_rules! make_mir_visitor {
                     mutability: _,
                     name: _,
                     ref $($mutability)* ty,
-                    ref $($mutability)* scope,
-                    ref $($mutability)* span,
+                    ref $($mutability)* source_info,
                 } = *var_decl;
 
                 self.visit_ty(ty);
-                self.visit_scope_id(scope);
-                self.visit_span(span);
+                self.visit_source_info(source_info);
             }
 
             fn super_temp_decl(&mut self,
@@ -651,8 +633,8 @@ macro_rules! make_mir_visitor {
                 self.visit_ty(ty);
             }
 
-            fn super_scope_id(&mut self,
-                              _scope_id: & $($mutability)* ScopeId) {
+            fn super_visibility_scope(&mut self,
+                                      _scope: & $($mutability)* VisibilityScope) {
             }
 
             fn super_branch(&mut self,
@@ -707,6 +689,16 @@ macro_rules! make_mir_visitor {
             fn super_span(&mut self, _span: & $($mutability)* Span) {
             }
 
+            fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
+                let SourceInfo {
+                    ref $($mutability)* span,
+                    ref $($mutability)* scope,
+                } = *source_info;
+
+                self.visit_span(span);
+                self.visit_visibility_scope(scope);
+            }
+
             fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
                 match *fn_output {
                     FnOutput::FnConverging(ref $($mutability)* ty) => {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index d58128b1c4a..7a1ac7c218c 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -112,7 +112,6 @@ pub struct Options {
     // with additional crate configurations during the compile process
     pub crate_types: Vec<CrateType>,
 
-    pub gc: bool,
     pub optimize: OptLevel,
     pub debug_assertions: bool,
     pub debuginfo: DebugInfoLevel,
@@ -242,7 +241,6 @@ pub fn host_triple() -> &'static str {
 pub fn basic_options() -> Options {
     Options {
         crate_types: Vec::new(),
-        gc: false,
         optimize: OptLevel::No,
         debuginfo: NoDebugInfo,
         lint_opts: Vec::new(),
@@ -632,14 +630,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "omit landing pads for unwinding"),
     debug_llvm: bool = (false, parse_bool,
         "enable debug output from LLVM"),
-    count_type_sizes: bool = (false, parse_bool,
-        "count the sizes of aggregate types"),
     meta_stats: bool = (false, parse_bool,
         "gather metadata statistics"),
     print_link_args: bool = (false, parse_bool,
         "print the arguments passed to the linker"),
-    gc: bool = (false, parse_bool,
-        "garbage collect shared data (experimental)"),
     print_llvm_passes: bool = (false, parse_bool,
         "prints the llvm optimization passes being run"),
     ast_json: bool = (false, parse_bool,
@@ -1189,7 +1183,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         }
     };
     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
-    let gc = debugging_opts.gc;
     let debuginfo = if matches.opt_present("g") {
         if cg.debuginfo.is_some() {
             early_error(error_format, "-g and -C debuginfo both provided");
@@ -1272,7 +1265,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     Options {
         crate_types: crate_types,
-        gc: gc,
         optimize: opt_level,
         debuginfo: debuginfo,
         lint_opts: lint_opts,
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 100b204b501..d60c31369d0 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -284,9 +284,6 @@ impl Session {
     pub fn count_llvm_insns(&self) -> bool {
         self.opts.debugging_opts.count_llvm_insns
     }
-    pub fn count_type_sizes(&self) -> bool {
-        self.opts.debugging_opts.count_type_sizes
-    }
     pub fn time_llvm_passes(&self) -> bool {
         self.opts.debugging_opts.time_llvm_passes
     }
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index b12581b3400..44b450784ed 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -187,7 +187,7 @@ impl FlagComputation {
             }
             ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
             ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
-            ty::ReStatic => {}
+            ty::ReStatic | ty::ReErased => {}
             _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
         }
 
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index f76f4c01df3..1a944e04eff 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -421,12 +421,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         collector.regions
     }
 
-    /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
+    /// Replace any late-bound regions bound in `value` with `'erased`. Useful in trans but also
     /// method lookup and a few other places where precise region relationships are not required.
     pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
         where T : TypeFoldable<'tcx>
     {
-        self.replace_late_bound_regions(value, |_| ty::ReStatic).0
+        self.replace_late_bound_regions(value, |_| ty::ReErased).0
     }
 
     /// Rewrite any late-bound regions so that they are anonymous.  Region numbers are
@@ -547,15 +547,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             fn fold_region(&mut self, r: ty::Region) -> ty::Region {
                 // because late-bound regions affect subtyping, we can't
                 // erase the bound/free distinction, but we can replace
-                // all free regions with 'static.
+                // all free regions with 'erased.
                 //
                 // Note that we *CAN* replace early-bound regions -- the
                 // type system never "sees" those, they get substituted
-                // away. In trans, they will always be erased to 'static
+                // away. In trans, they will always be erased to 'erased
                 // whenever a substitution occurs.
                 match r {
                     ty::ReLateBound(..) => r,
-                    _ => ty::ReStatic
+                    _ => ty::ReErased
                 }
             }
         }
@@ -651,7 +651,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
             // does this represent a region that cannot be named
             // in a global way? used in fulfillment caching.
             match r {
-                ty::ReStatic | ty::ReEmpty => {}
+                ty::ReStatic | ty::ReEmpty | ty::ReErased => {}
                 _ => return true,
             }
         }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 07156c67a22..d305a772ae5 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -17,6 +17,8 @@ use session::Session;
 use traits;
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 
+use util::common::slice_pat;
+
 use syntax::ast::{FloatTy, IntTy, UintTy};
 use syntax::attr;
 use syntax::codemap::DUMMY_SP;
@@ -98,17 +100,17 @@ impl TargetDataLayout {
 
         let mut dl = TargetDataLayout::default();
         for spec in sess.target.target.data_layout.split("-") {
-            match &spec.split(":").collect::<Vec<_>>()[..] {
-                ["e"] => dl.endian = Endian::Little,
-                ["E"] => dl.endian = Endian::Big,
-                ["a", a..] => dl.aggregate_align = align(a, "a"),
-                ["f32", a..] => dl.f32_align = align(a, "f32"),
-                ["f64", a..] => dl.f64_align = align(a, "f64"),
-                [p @ "p", s, a..] | [p @ "p0", s, a..] => {
+            match slice_pat(&&spec.split(":").collect::<Vec<_>>()[..]) {
+                &["e"] => dl.endian = Endian::Little,
+                &["E"] => dl.endian = Endian::Big,
+                &["a", ref a..] => dl.aggregate_align = align(a, "a"),
+                &["f32", ref a..] => dl.f32_align = align(a, "f32"),
+                &["f64", ref a..] => dl.f64_align = align(a, "f64"),
+                &[p @ "p", s, ref a..] | &[p @ "p0", s, ref a..] => {
                     dl.pointer_size = size(s, p);
                     dl.pointer_align = align(a, p);
                 }
-                [s, a..] if s.starts_with("i") => {
+                &[s, ref a..] if s.starts_with("i") => {
                     let ty_align = match s[1..].parse::<u64>() {
                         Ok(1) => &mut dl.i8_align,
                         Ok(8) => &mut dl.i8_align,
@@ -123,7 +125,7 @@ impl TargetDataLayout {
                     };
                     *ty_align = align(a, s);
                 }
-                [s, a..] if s.starts_with("v") => {
+                &[s, ref a..] if s.starts_with("v") => {
                     let v_size = size(&s[1..], "v");
                     let a = align(a, s);
                     if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 3ab7d90bf8c..28266809266 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -22,7 +22,7 @@ use dep_graph::{self, DepNode};
 use hir::map as ast_map;
 use middle;
 use middle::cstore::{self, LOCAL_CRATE};
-use hir::def::{self, Def, ExportMap};
+use hir::def::{Def, PathResolution, ExportMap};
 use hir::def_id::DefId;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
@@ -308,13 +308,11 @@ impl Visibility {
         match *visibility {
             hir::Public => Visibility::Public,
             hir::Visibility::Crate => Visibility::Restricted(ast::CRATE_NODE_ID),
-            hir::Visibility::Restricted { id, .. } => match tcx.def_map.borrow().get(&id) {
-                Some(resolution) => Visibility::Restricted({
-                    tcx.map.as_local_node_id(resolution.base_def.def_id()).unwrap()
-                }),
+            hir::Visibility::Restricted { id, .. } => match tcx.expect_def(id) {
                 // 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.
-                None => Visibility::Public,
+                Def::Err => Visibility::Public,
+                def => Visibility::Restricted(tcx.map.as_local_node_id(def.def_id()).unwrap()),
             },
             hir::Inherited => Visibility::Restricted(tcx.map.get_module_parent(id)),
         }
@@ -2249,34 +2247,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn resolve_expr(self, expr: &hir::Expr) -> Def {
-        match self.def_map.borrow().get(&expr.id) {
-            Some(def) => def.full_def(),
-            None => {
-                span_bug!(expr.span, "no def-map entry for expr {}", expr.id);
-            }
-        }
-    }
-
     pub fn expr_is_lval(self, expr: &hir::Expr) -> bool {
          match expr.node {
             hir::ExprPath(..) => {
-                // We can't use resolve_expr here, as this needs to run on broken
-                // programs. We don't need to through - associated items are all
-                // rvalues.
-                match self.def_map.borrow().get(&expr.id) {
-                    Some(&def::PathResolution {
-                        base_def: Def::Static(..), ..
-                    }) | Some(&def::PathResolution {
-                        base_def: Def::Upvar(..), ..
-                    }) | Some(&def::PathResolution {
-                        base_def: Def::Local(..), ..
-                    }) => {
-                        true
-                    }
-                    Some(&def::PathResolution { base_def: Def::Err, .. })=> true,
-                    Some(..) => false,
-                    None => span_bug!(expr.span, "no def for path {}", expr.id)
+                // This function can be used during type checking when not all paths are
+                // fully resolved. Partially resolved paths in expressions can only legally
+                // refer to associated items which are always rvalues.
+                match self.expect_resolution(expr.id).base_def {
+                    Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true,
+                    _ => false,
                 }
             }
 
@@ -2459,8 +2438,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn trait_ref_to_def_id(self, tr: &hir::TraitRef) -> DefId {
-        self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id()
+    /// Returns a path resolution for node id if it exists, panics otherwise.
+    pub fn expect_resolution(self, id: NodeId) -> PathResolution {
+        *self.def_map.borrow().get(&id).expect("no def-map entry for node id")
+    }
+
+    /// Returns a fully resolved definition for node id if it exists, panics otherwise.
+    pub fn expect_def(self, id: NodeId) -> Def {
+        self.expect_resolution(id).full_def()
+    }
+
+    /// Returns a fully resolved definition for node id if it exists, or none if no
+    /// definition exists, panics on partial resolutions to catch errors.
+    pub fn expect_def_or_none(self, id: NodeId) -> Option<Def> {
+        self.def_map.borrow().get(&id).map(|resolution| resolution.full_def())
     }
 
     pub fn def_key(self, id: DefId) -> ast_map::DefKey {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 2bb88e52f88..7c69618068a 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -492,6 +492,13 @@ impl<'tcx> FnOutput<'tcx> {
             ty::FnDiverging => def
         }
     }
+
+    pub fn maybe_converging(self) -> Option<Ty<'tcx>> {
+        match self {
+            ty::FnConverging(t) => Some(t),
+            ty::FnDiverging => None
+        }
+    }
 }
 
 pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
@@ -705,6 +712,9 @@ pub enum Region {
     /// The only way to get an instance of ReEmpty is to have a region
     /// variable with no constraints.
     ReEmpty,
+
+    /// Erased region, used by trait selection, in MIR and during trans.
+    ReErased,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 2db9ceb8a05..fbc565ca847 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
 
     pub fn erase_regions(self) -> Substs<'tcx> {
         let Substs { types, regions } = self;
-        let regions = regions.map(|_| ty::ReStatic);
+        let regions = regions.map(|_| ty::ReErased);
         Substs { types: types, regions: regions }
     }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 416347919a8..7745f00c2eb 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -348,7 +348,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
             let region = |state: &mut SipHasher, r: ty::Region| {
                 match r {
-                    ty::ReStatic => {}
+                    ty::ReStatic | ty::ReErased => {}
                     ty::ReLateBound(db, ty::BrAnon(i)) => {
                         db.hash(state);
                         i.hash(state);
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index bdfb97549d5..57c429152c8 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -247,3 +247,15 @@ pub fn path2cstr(p: &Path) -> CString {
 pub fn path2cstr(p: &Path) -> CString {
     CString::new(p.to_str().unwrap()).unwrap()
 }
+
+// FIXME(stage0): remove this
+// HACK: this is needed because the interpretation of slice
+// patterns changed between stage0 and now.
+#[cfg(stage0)]
+pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] {
+    t
+}
+#[cfg(not(stage0))]
+pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] {
+    *t
+}
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index e600e7b72da..0bfb7c1ed55 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -148,28 +148,36 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
             write!(f, "{}", cont)
         }
     };
-    let print_region = |f: &mut fmt::Formatter, region: &ty::Region| -> _ {
-        if verbose {
-            write!(f, "{:?}", region)
-        } else {
-            let s = region.to_string();
-            if s.is_empty() {
-                // This happens when the value of the region
-                // parameter is not easily serialized. This may be
-                // because the user omitted it in the first place,
-                // or because it refers to some block in the code,
-                // etc. I'm not sure how best to serialize this.
-                write!(f, "'_")
+
+    let print_regions = |f: &mut fmt::Formatter, start: &str, regions: &[ty::Region]| {
+        // Don't print any regions if they're all erased.
+        if regions.iter().all(|r| *r == ty::ReErased) {
+            return Ok(());
+        }
+
+        for region in regions {
+            start_or_continue(f, start, ", ")?;
+            if verbose {
+                write!(f, "{:?}", region)?;
             } else {
-                write!(f, "{}", s)
+                let s = region.to_string();
+                if s.is_empty() {
+                    // This happens when the value of the region
+                    // parameter is not easily serialized. This may be
+                    // because the user omitted it in the first place,
+                    // or because it refers to some block in the code,
+                    // etc. I'm not sure how best to serialize this.
+                    write!(f, "'_")?;
+                } else {
+                    write!(f, "{}", s)?;
+                }
             }
         }
+
+        Ok(())
     };
 
-    for region in substs.regions.get_slice(subst::TypeSpace) {
-        start_or_continue(f, "<", ", ")?;
-        print_region(f, region)?;
-    }
+    print_regions(f, "<", substs.regions.get_slice(subst::TypeSpace))?;
 
     let num_supplied_defaults = if verbose {
         0
@@ -211,10 +219,7 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
             write!(f, "::{}", item_name)?;
         }
 
-        for region in substs.regions.get_slice(subst::FnSpace) {
-            start_or_continue(f, "::<", ", ")?;
-            print_region(f, region)?;
-        }
+        print_regions(f, "::<", substs.regions.get_slice(subst::FnSpace))?;
 
         // FIXME: consider being smart with defaults here too
         for ty in substs.types.get_slice(subst::FnSpace) {
@@ -536,7 +541,9 @@ impl fmt::Debug for ty::Region {
                 write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
             }
 
-            ty::ReEmpty => write!(f, "ReEmpty")
+            ty::ReEmpty => write!(f, "ReEmpty"),
+
+            ty::ReErased => write!(f, "ReErased")
         }
     }
 }
@@ -600,7 +607,8 @@ impl fmt::Display for ty::Region {
                 write!(f, "{}", br)
             }
             ty::ReScope(_) |
-            ty::ReVar(_) => Ok(()),
+            ty::ReVar(_) |
+            ty::ReErased => Ok(()),
             ty::ReStatic => write!(f, "'static"),
             ty::ReEmpty => write!(f, "'<empty>"),
         }
diff --git a/src/librustc_bitflags/lib.rs b/src/librustc_bitflags/lib.rs
index e2025eaa8ee..afc2e04d446 100644
--- a/src/librustc_bitflags/lib.rs
+++ b/src/librustc_bitflags/lib.rs
@@ -291,8 +291,8 @@ macro_rules! bitflags {
 #[cfg(test)]
 #[allow(non_upper_case_globals)]
 mod tests {
-    use std::hash::{Hasher, Hash, SipHasher};
-    use std::option::Option::{Some, None};
+    use std::hash::{Hash, Hasher, SipHasher};
+    use std::option::Option::{None, Some};
 
     bitflags! {
         #[doc = "> The first principle is that you must not fool yourself — and"]
diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml
index fbc267aaa6a..c8a71ea3505 100644
--- a/src/librustc_borrowck/Cargo.toml
+++ b/src/librustc_borrowck/Cargo.toml
@@ -14,4 +14,5 @@ log = { path = "../liblog" }
 syntax = { path = "../libsyntax" }
 graphviz = { path = "../libgraphviz" }
 rustc = { path = "../librustc" }
+rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_mir = { path = "../librustc_mir" }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 8682661d35a..64f35aed23f 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -122,15 +122,12 @@ fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
     let potentially_illegal_move =
                 check_and_get_illegal_move_origin(bccx, &move_info.cmt);
-    match potentially_illegal_move {
-        Some(illegal_move_origin) => {
-            debug!("illegal_move_origin={:?}", illegal_move_origin);
-            let error = MoveError::with_move_info(illegal_move_origin,
-                                                  move_info.span_path_opt);
-            move_error_collector.add_error(error);
-            return
-        }
-        None => ()
+    if let Some(illegal_move_origin) = potentially_illegal_move {
+        debug!("illegal_move_origin={:?}", illegal_move_origin);
+        let error = MoveError::with_move_info(illegal_move_origin,
+                                              move_info.span_path_opt);
+        move_error_collector.add_error(error);
+        return;
     }
 
     match opt_loan_path(&move_info.cmt) {
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 7d4f02bfe11..7f814f5dfaa 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -369,7 +369,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                     ty::ReLateBound(..) |
                     ty::ReEarlyBound(..) |
                     ty::ReVar(..) |
-                    ty::ReSkolemized(..) => {
+                    ty::ReSkolemized(..) |
+                    ty::ReErased => {
                         span_bug!(
                             cmt.span,
                             "invalid borrow lifetime: {:?}",
diff --git a/src/librustc_borrowck/borrowck/mir/abs_domain.rs b/src/librustc_borrowck/borrowck/mir/abs_domain.rs
index aa885eb4742..155b615d83c 100644
--- a/src/librustc_borrowck/borrowck/mir/abs_domain.rs
+++ b/src/librustc_borrowck/borrowck/mir/abs_domain.rs
@@ -49,6 +49,8 @@ impl<'tcx> Lift for LvalueElem<'tcx> {
                 ProjectionElem::Field(f.clone(), ty.clone()),
             ProjectionElem::Index(ref i) =>
                 ProjectionElem::Index(i.lift()),
+            ProjectionElem::Subslice {from, to} =>
+                ProjectionElem::Subslice { from: from, to: to },
             ProjectionElem::ConstantIndex {offset,min_length,from_end} =>
                 ProjectionElem::ConstantIndex {
                     offset: offset,
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs
index 63c11fb3545..91be50d11f9 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs
@@ -12,6 +12,7 @@
 
 use syntax::ast::NodeId;
 use rustc::mir::repr::{BasicBlock, Mir};
+use rustc_data_structures::indexed_vec::Idx;
 
 use dot;
 use dot::IntoCow;
@@ -27,7 +28,7 @@ use std::path::Path;
 use super::super::MoveDataParamEnv;
 use super::super::MirBorrowckCtxtPreDataflow;
 use bitslice::bits_to_string;
-use indexed_set::{Idx, IdxSet};
+use indexed_set::{IdxSet};
 use super::{BitDenotation, DataflowState};
 
 impl<O: BitDenotation> DataflowState<O> {
@@ -126,7 +127,7 @@ pub type Node = BasicBlock;
 pub struct Edge { source: BasicBlock, index: usize }
 
 fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
-    let succ_len = mir.basic_block_data(bb).terminator().successors().len();
+    let succ_len = mir[bb].terminator().successors().len();
     (0..succ_len).map(|index| Edge { source: bb, index: index}).collect()
 }
 
@@ -312,17 +313,20 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
     type Node = Node;
     type Edge = Edge;
     fn nodes(&self) -> dot::Nodes<Node> {
-        self.mbcx.mir().all_basic_blocks().into_cow()
+        self.mbcx.mir()
+            .basic_blocks()
+            .indices()
+            .collect::<Vec<_>>()
+            .into_cow()
     }
 
     fn edges(&self) -> dot::Edges<Edge> {
         let mir = self.mbcx.mir();
-        let blocks = mir.all_basic_blocks();
         // base initial capacity on assumption every block has at
         // least one outgoing edge (Which should be true for all
         // blocks but one, the exit-block).
-        let mut edges = Vec::with_capacity(blocks.len());
-        for bb in blocks {
+        let mut edges = Vec::with_capacity(mir.basic_blocks().len());
+        for bb in mir.basic_blocks().indices() {
             let outgoing = outgoing(mir, bb);
             edges.extend(outgoing.into_iter());
         }
@@ -335,6 +339,6 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
 
     fn target(&self, edge: &Edge) -> Node {
         let mir = self.mbcx.mir();
-        mir.basic_block_data(edge.source).terminator().successors()[edge.index]
+        mir[edge.source].terminator().successors()[edge.index]
     }
 }
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs
index e3435ed9905..932b7485201 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs
@@ -10,6 +10,7 @@
 
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::{self, Mir};
+use rustc_data_structures::indexed_vec::Idx;
 
 use super::super::gather_moves::{Location};
 use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
@@ -23,7 +24,7 @@ use super::{BitDenotation, BlockSets, DataflowOperator};
 
 use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
 use bitslice::{BitwiseOperator};
-use indexed_set::{Idx, IdxSet};
+use indexed_set::{IdxSet};
 
 // Dataflow analyses are built upon some interpretation of the
 // bitvectors attached to each basic block, represented via a
@@ -425,7 +426,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
                         bb: repr::BasicBlock,
                         idx: usize) {
         let (tcx, mir, move_data) = (self.tcx, self.mir, &ctxt.move_data);
-        let stmt = &mir.basic_block_data(bb).statements[idx];
+        let stmt = &mir[bb].statements[idx];
         let loc_map = &move_data.loc_map;
         let path_map = &move_data.path_map;
         let rev_lookup = &move_data.rev_lookup;
@@ -451,7 +452,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
                                      move_data,
                                      move_path_index,
                                      |mpi| for moi in &path_map[mpi] {
-                                         assert!(moi.idx() < bits_per_block);
+                                         assert!(moi.index() < bits_per_block);
                                          sets.kill_set.add(&moi);
                                      });
             }
@@ -465,14 +466,14 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
                          statements_len: usize)
     {
         let (mir, move_data) = (self.mir, &ctxt.move_data);
-        let term = mir.basic_block_data(bb).terminator.as_ref().unwrap();
+        let term = mir[bb].terminator();
         let loc_map = &move_data.loc_map;
         let loc = Location { block: bb, index: statements_len };
         debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
                term, loc, &loc_map[loc]);
         let bits_per_block = self.bits_per_block(ctxt);
         for move_index in &loc_map[loc] {
-            assert!(move_index.idx() < bits_per_block);
+            assert!(move_index.index() < bits_per_block);
             zero_to_one(sets.gen_set.words_mut(), *move_index);
         }
     }
@@ -493,14 +494,14 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
                              move_data,
                              move_path_index,
                              |mpi| for moi in &path_map[mpi] {
-                                 assert!(moi.idx() < bits_per_block);
+                                 assert!(moi.index() < bits_per_block);
                                  in_out.remove(&moi);
                              });
     }
 }
 
 fn zero_to_one(bitvec: &mut [usize], move_index: MoveOutIndex) {
-    let retval = bitvec.set_bit(move_index.idx());
+    let retval = bitvec.set_bit(move_index.index());
     assert!(retval);
 }
 
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs
index 81655b5e386..a9b4de45096 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc_data_structures::indexed_vec::Idx;
+
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::{self, Mir};
 
@@ -21,7 +23,7 @@ use super::MirBorrowckCtxtPreDataflow;
 use super::MoveDataParamEnv;
 
 use bitslice::{bitwise, BitwiseOperator};
-use indexed_set::{Idx, IdxSet, IdxSetBuf};
+use indexed_set::{IdxSet, IdxSetBuf};
 
 pub use self::sanity_check::sanity_check_via_rustc_peek;
 pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
@@ -81,11 +83,10 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD>
             self.flow_state.operator.start_block_effect(&self.ctxt, sets);
         }
 
-        for bb in self.mir.all_basic_blocks() {
+        for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
             let &repr::BasicBlockData { ref statements,
                                         ref terminator,
-                                        is_cleanup: _ } =
-                self.mir.basic_block_data(bb);
+                                        is_cleanup: _ } = data;
 
             let sets = &mut self.flow_state.sets.for_block(bb.index());
             for j_stmt in 0..statements.len() {
@@ -112,7 +113,7 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD>
 
     fn walk_cfg(&mut self, in_out: &mut IdxSet<BD::Idx>) {
         let mir = self.builder.mir;
-        for (bb_idx, bb_data) in mir.basic_blocks.iter().enumerate() {
+        for (bb_idx, bb_data) in mir.basic_blocks().iter().enumerate() {
             let builder = &mut self.builder;
             {
                 let sets = builder.flow_state.sets.for_block(bb_idx);
@@ -396,7 +397,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
         // (now rounded up to multiple of word size)
         let bits_per_block = words_per_block * usize_bits;
 
-        let num_blocks = mir.basic_blocks.len();
+        let num_blocks = mir.basic_blocks().len();
         let num_overall = num_blocks * bits_per_block;
 
         let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall));
@@ -448,7 +449,8 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
     {
         match bb_data.terminator().kind {
             repr::TerminatorKind::Return |
-            repr::TerminatorKind::Resume => {}
+            repr::TerminatorKind::Resume |
+            repr::TerminatorKind::Unreachable => {}
             repr::TerminatorKind::Goto { ref target } |
             repr::TerminatorKind::Assert { ref target, cleanup: None, .. } |
             repr::TerminatorKind::Drop { ref target, location: _, unwind: None } |
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
index 74dc921b0bb..c8d3ff01b6c 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
@@ -14,6 +14,7 @@ use syntax::codemap::Span;
 
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::repr::{self, Mir};
+use rustc_data_structures::indexed_vec::Idx;
 
 use super::super::gather_moves::{MovePathIndex};
 use super::super::MoveDataParamEnv;
@@ -49,8 +50,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // `dataflow::build_sets`. (But note it is doing non-standard
     // stuff, so such generalization may not be realistic.)
 
-    let blocks = mir.all_basic_blocks();
-    'next_block: for bb in blocks {
+    for bb in mir.basic_blocks().indices() {
         each_block(tcx, mir, flow_ctxt, results, bb);
     }
 }
@@ -63,10 +63,9 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
 {
     let move_data = &ctxt.move_data;
-    let bb_data = mir.basic_block_data(bb);
-    let &repr::BasicBlockData { ref statements,
-                                ref terminator,
-                                is_cleanup: _ } = bb_data;
+    let repr::BasicBlockData { ref statements,
+                               ref terminator,
+                               is_cleanup: _ } = mir[bb];
 
     let (args, span) = match is_rustc_peek(tcx, terminator) {
         Some(args_and_span) => args_and_span,
@@ -151,7 +150,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            terminator: &'a Option<repr::Terminator<'tcx>>)
                            -> Option<(&'a [repr::Operand<'tcx>], Span)> {
-    if let Some(repr::Terminator { ref kind, span, .. }) = *terminator {
+    if let Some(repr::Terminator { ref kind, source_info, .. }) = *terminator {
         if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
         {
             if let repr::Operand::Constant(ref func) = *oper
@@ -161,7 +160,7 @@ fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     let name = tcx.item_name(def_id);
                     if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                         if name.as_str() == "rustc_peek" {
-                            return Some((args, span));
+                            return Some((args, source_info.span));
                         }
                     }
                 }
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index e783420fa06..065cbbf76b3 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -22,7 +22,7 @@ use rustc::mir::transform::{Pass, MirPass, MirSource};
 use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items;
 use rustc::util::nodemap::FnvHashMap;
-use rustc_mir::pretty;
+use rustc_data_structures::indexed_vec::Idx;
 use syntax::codemap::Span;
 
 use std::fmt;
@@ -65,9 +65,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
                 patch: MirPatch::new(mir),
             }.elaborate()
         };
-        pretty::dump_mir(tcx, "elaborate_drops", &0, src, mir, None);
         elaborate_patch.apply(mir);
-        pretty::dump_mir(tcx, "elaborate_drops", &1, src, mir, None);
     }
 }
 
@@ -118,14 +116,13 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
     env: &'a MoveDataParamEnv<'tcx>,
     flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx>>,
     flow_uninits:  DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>,
-    drop_flags: FnvHashMap<MovePathIndex, u32>,
+    drop_flags: FnvHashMap<MovePathIndex, Temp>,
     patch: MirPatch<'tcx>,
 }
 
 #[derive(Copy, Clone, Debug)]
 struct DropCtxt<'a, 'tcx: 'a> {
-    span: Span,
-    scope: ScopeId,
+    source_info: SourceInfo,
     is_cleanup: bool,
 
     init_data: &'a InitializationData,
@@ -198,35 +195,24 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     }
 
     /// Returns whether this lvalue is tracked by drop elaboration. This
-    /// includes all lvalues, except these behind references or arrays.
-    ///
-    /// Lvalues behind references or arrays are not tracked by elaboration
-    /// and are always assumed to be initialized when accessible. As
-    /// references and indexes can be reseated, trying to track them
-    /// can only lead to trouble.
+    /// includes all lvalues, except these (1.) behind references or arrays,
+    ///  or (2.) behind ADT's with a Drop impl.
     fn lvalue_is_tracked(&self, lv: &Lvalue<'tcx>) -> bool
     {
+        // `lvalue_contents_drop_state_cannot_differ` only compares
+        // the `lv` to its immediate contents, while this recursively
+        // follows parent chain formed by `base` of each projection.
         if let &Lvalue::Projection(ref data) = lv {
-            self.lvalue_contents_are_tracked(&data.base)
+            !super::lvalue_contents_drop_state_cannot_differ(self.tcx, self.mir, &data.base) &&
+                self.lvalue_is_tracked(&data.base)
         } else {
             true
         }
     }
 
-    fn lvalue_contents_are_tracked(&self, lv: &Lvalue<'tcx>) -> bool {
-        let ty = self.mir.lvalue_ty(self.tcx, lv).to_ty(self.tcx);
-        match ty.sty {
-            ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
-                false
-            }
-            _ => self.lvalue_is_tracked(lv)
-        }
-    }
-
     fn collect_drop_flags(&mut self)
     {
-        for bb in self.mir.all_basic_blocks() {
-            let data = self.mir.basic_block_data(bb);
+        for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
             let terminator = data.terminator();
             let location = match terminator.kind {
                 TerminatorKind::Drop { ref location, .. } |
@@ -262,8 +248,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
     fn elaborate_drops(&mut self)
     {
-        for bb in self.mir.all_basic_blocks() {
-            let data = self.mir.basic_block_data(bb);
+        for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
             let loc = Location { block: bb, index: data.statements.len() };
             let terminator = data.terminator();
 
@@ -273,8 +258,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                     let init_data = self.initialization_data_at(loc);
                     let path = self.move_data().rev_lookup.find(location);
                     self.elaborate_drop(&DropCtxt {
-                        span: terminator.span,
-                        scope: terminator.scope,
+                        source_info: terminator.source_info,
                         is_cleanup: data.is_cleanup,
                         init_data: &init_data,
                         lvalue: location,
@@ -324,13 +308,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         unwind: Option<BasicBlock>)
     {
         let bb = loc.block;
-        let data = self.mir.basic_block_data(bb);
+        let data = &self.mir[bb];
         let terminator = data.terminator();
 
         let assign = Statement {
             kind: StatementKind::Assign(location.clone(), Rvalue::Use(value.clone())),
-            span: terminator.span,
-            scope: terminator.scope
+            source_info: terminator.source_info
         };
 
         let unwind = unwind.unwrap_or(self.patch.resume_block());
@@ -367,8 +350,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             let path = self.move_data().rev_lookup.find(location);
 
             self.elaborate_drop(&DropCtxt {
-                span: terminator.span,
-                scope: terminator.scope,
+                source_info: terminator.source_info,
                 is_cleanup: data.is_cleanup,
                 init_data: &init_data,
                 lvalue: location,
@@ -513,8 +495,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                     debug!("drop_ladder: for std field {} ({:?})", i, lv);
 
                     self.elaborated_drop_block(&DropCtxt {
-                        span: c.span,
-                        scope: c.scope,
+                        source_info: c.source_info,
                         is_cleanup: is_cleanup,
                         init_data: c.init_data,
                         lvalue: lv,
@@ -527,8 +508,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                     debug!("drop_ladder: for rest field {} ({:?})", i, lv);
 
                     let blk = self.complete_drop(&DropCtxt {
-                        span: c.span,
-                        scope: c.scope,
+                        source_info: c.source_info,
                         is_cleanup: is_cleanup,
                         init_data: c.init_data,
                         lvalue: lv,
@@ -568,17 +548,26 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     ///     ELAB(drop location.2 [target=`c.unwind])
     fn drop_ladder<'a>(&mut self,
                        c: &DropCtxt<'a, 'tcx>,
-                       fields: &[(Lvalue<'tcx>, Option<MovePathIndex>)])
+                       fields: Vec<(Lvalue<'tcx>, Option<MovePathIndex>)>)
                        -> BasicBlock
     {
         debug!("drop_ladder({:?}, {:?})", c, fields);
+
+        let mut fields = fields;
+        fields.retain(|&(ref lvalue, _)| {
+            let ty = self.mir.lvalue_ty(self.tcx, lvalue).to_ty(self.tcx);
+            self.tcx.type_needs_drop_given_env(ty, self.param_env())
+        });
+
+        debug!("drop_ladder - fields needing drop: {:?}", fields);
+
         let unwind_ladder = if c.is_cleanup {
             None
         } else {
             Some(self.drop_halfladder(c, None, c.unwind.unwrap(), &fields, true))
         };
 
-        self.drop_halfladder(c, unwind_ladder, c.succ, fields, c.is_cleanup)
+        self.drop_halfladder(c, unwind_ladder, c.succ, &fields, c.is_cleanup)
             .last().cloned().unwrap_or(c.succ)
     }
 
@@ -587,7 +576,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     {
         debug!("open_drop_for_tuple({:?}, {:?})", c, tys);
 
-        let fields: Vec<_> = tys.iter().enumerate().map(|(i, &ty)| {
+        let fields = tys.iter().enumerate().map(|(i, &ty)| {
             (c.lvalue.clone().field(Field::new(i), ty),
              super::move_path_children_matching(
                  &self.move_data().move_paths, c.path, |proj| match proj {
@@ -599,7 +588,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             ))
         }).collect();
 
-        self.drop_ladder(c, &fields)
+        self.drop_ladder(c, fields)
     }
 
     fn open_drop_for_box<'a>(&mut self, c: &DropCtxt<'a, 'tcx>, ty: Ty<'tcx>)
@@ -654,7 +643,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 variant_path,
                 &adt.variants[variant_index],
                 substs);
-            self.drop_ladder(c, &fields)
+            self.drop_ladder(c, fields)
         } else {
             // variant not found - drop the entire enum
             if let None = *drop_block {
@@ -679,7 +668,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                     &adt.variants[0],
                     substs
                 );
-                self.drop_ladder(c, &fields)
+                self.drop_ladder(c, fields)
             }
             _ => {
                 let variant_drops : Vec<BasicBlock> =
@@ -785,7 +774,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         self.patch.new_block(BasicBlockData {
             statements: vec![],
             terminator: Some(Terminator {
-                scope: c.scope, span: c.span, kind: k
+                source_info: c.source_info, kind: k
             }),
             is_cleanup: is_cleanup
         })
@@ -858,11 +847,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         let mut statements = vec![];
         if let Some(&flag) = self.drop_flags.get(&c.path) {
             statements.push(Statement {
-                span: c.span,
-                scope: c.scope,
+                source_info: c.source_info,
                 kind: StatementKind::Assign(
                     Lvalue::Temp(flag),
-                    self.constant_bool(c.span, false)
+                    self.constant_bool(c.source_info.span, false)
                 )
             });
         }
@@ -880,9 +868,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         self.patch.new_block(BasicBlockData {
             statements: statements,
             terminator: Some(Terminator {
-                scope: c.scope, span: c.span, kind: TerminatorKind::Call {
+                source_info: c.source_info, kind: TerminatorKind::Call {
                     func: Operand::Constant(Constant {
-                        span: c.span,
+                        span: c.source_info.span,
                         ty: fty,
                         literal: Literal::Item {
                             def_id: free_func,
@@ -910,7 +898,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
                 if def.has_dtor() {
                     self.tcx.sess.span_warn(
-                        c.span,
+                        c.source_info.span,
                         &format!("dataflow bug??? moving out of type with dtor {:?}",
                                  c));
                     true
@@ -932,7 +920,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
     fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) {
         if let Some(&flag) = self.drop_flags.get(&path) {
-            let span = self.patch.context_for_location(self.mir, loc).0;
+            let span = self.patch.source_info_for_location(self.mir, loc).span;
             let val = self.constant_bool(span, val.value());
             self.patch.add_assign(loc, Lvalue::Temp(flag), val);
         }
@@ -940,7 +928,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
     fn drop_flags_on_init(&mut self) {
         let loc = Location { block: START_BLOCK, index: 0 };
-        let span = self.patch.context_for_location(self.mir, loc).0;
+        let span = self.patch.source_info_for_location(self.mir, loc).span;
         let false_ = self.constant_bool(span, false);
         for flag in self.drop_flags.values() {
             self.patch.add_assign(loc, Lvalue::Temp(*flag), false_.clone());
@@ -948,8 +936,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     }
 
     fn drop_flags_for_fn_rets(&mut self) {
-        for bb in self.mir.all_basic_blocks() {
-            let data = self.mir.basic_block_data(bb);
+        for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
             if let TerminatorKind::Call {
                 destination: Some((ref lv, tgt)), cleanup: Some(_), ..
             } = data.terminator().kind {
@@ -981,8 +968,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         // drop flags by themselves, to avoid the drop flags being
         // clobbered before they are read.
 
-        for bb in self.mir.all_basic_blocks() {
-            let data = self.mir.basic_block_data(bb);
+        for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
             debug!("drop_flags_for_locs({:?})", data);
             for i in 0..(data.statements.len()+1) {
                 debug!("drop_flag_for_locs: stmt {}", i);
diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs
index 27d208240ac..05412216d48 100644
--- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs
@@ -12,6 +12,7 @@
 use rustc::ty::{FnOutput, TyCtxt};
 use rustc::mir::repr::*;
 use rustc::util::nodemap::FnvHashMap;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 
 use std::cell::{Cell};
 use std::collections::hash_map::Entry;
@@ -20,7 +21,6 @@ use std::iter;
 use std::ops::Index;
 
 use super::abs_domain::{AbstractElem, Lift};
-use indexed_set::{Idx};
 
 // This submodule holds some newtype'd Index wrappers that are using
 // NonZero to ensure that Option<Index> occupies only a single word.
@@ -29,7 +29,7 @@ use indexed_set::{Idx};
 // (which is likely to yield a subtle off-by-one error).
 mod indexes {
     use core::nonzero::NonZero;
-    use indexed_set::Idx;
+    use rustc_data_structures::indexed_vec::Idx;
 
     macro_rules! new_index {
         ($Index:ident) => {
@@ -43,7 +43,7 @@ mod indexes {
                 fn new(idx: usize) -> Self {
                     unsafe { $Index(NonZero::new(idx + 1)) }
                 }
-                fn idx(&self) -> usize {
+                fn index(self) -> usize {
                     *self.0 - 1
                 }
             }
@@ -62,7 +62,7 @@ pub use self::indexes::MoveOutIndex;
 
 impl self::indexes::MoveOutIndex {
     pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex {
-        move_data.moves[self.idx()].path
+        move_data.moves[self.index()].path
     }
 }
 
@@ -176,7 +176,7 @@ pub struct PathMap {
 impl Index<MovePathIndex> for PathMap {
     type Output = [MoveOutIndex];
     fn index(&self, index: MovePathIndex) -> &Self::Output {
-        &self.map[index.idx()]
+        &self.map[index.index()]
     }
 }
 
@@ -196,7 +196,7 @@ pub struct MoveOut {
 
 impl fmt::Debug for MoveOut {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        write!(fmt, "p{}@{:?}", self.path.idx(), self.source)
+        write!(fmt, "p{}@{:?}", self.path.index(), self.source)
     }
 }
 
@@ -227,14 +227,10 @@ impl<'tcx> MovePathData<'tcx> {
 impl<'tcx> Index<MovePathIndex> for MovePathData<'tcx> {
     type Output = MovePath<'tcx>;
     fn index(&self, i: MovePathIndex) -> &MovePath<'tcx> {
-        &self.move_paths[i.idx()]
+        &self.move_paths[i.index()]
     }
 }
 
-/// MovePathInverseMap maps from a uint in an lvalue-category to the
-/// MovePathIndex for the MovePath for that lvalue.
-type MovePathInverseMap = Vec<Option<MovePathIndex>>;
-
 struct MovePathDataBuilder<'a, 'tcx: 'a> {
     mir: &'a Mir<'tcx>,
     pre_move_paths: Vec<PreMovePath<'tcx>>,
@@ -244,9 +240,9 @@ struct MovePathDataBuilder<'a, 'tcx: 'a> {
 /// Tables mapping from an l-value to its MovePathIndex.
 #[derive(Debug)]
 pub struct MovePathLookup<'tcx> {
-    vars: MovePathInverseMap,
-    temps: MovePathInverseMap,
-    args: MovePathInverseMap,
+    vars: IndexVec<Var, Option<MovePathIndex>>,
+    temps: IndexVec<Temp, Option<MovePathIndex>>,
+    args: IndexVec<Arg, Option<MovePathIndex>>,
 
     /// The move path representing the return value is constructed
     /// lazily when we first encounter it in the input MIR.
@@ -295,15 +291,15 @@ enum LookupKind { Generate, Reuse }
 struct Lookup<T>(LookupKind, T);
 
 impl Lookup<MovePathIndex> {
-    fn idx(&self) -> usize { (self.1).idx() }
+    fn index(&self) -> usize { (self.1).index() }
 }
 
 impl<'tcx> MovePathLookup<'tcx> {
-    fn new() -> Self {
+    fn new(mir: &Mir) -> Self {
         MovePathLookup {
-            vars: vec![],
-            temps: vec![],
-            args: vec![],
+            vars: IndexVec::from_elem(None, &mir.var_decls),
+            temps: IndexVec::from_elem(None, &mir.temp_decls),
+            args: IndexVec::from_elem(None, &mir.arg_decls),
             statics: None,
             return_ptr: None,
             projections: vec![],
@@ -313,15 +309,14 @@ impl<'tcx> MovePathLookup<'tcx> {
 
     fn next_index(next: &mut MovePathIndex) -> MovePathIndex {
         let i = *next;
-        *next = MovePathIndex::new(i.idx() + 1);
+        *next = MovePathIndex::new(i.index() + 1);
         i
     }
 
-    fn lookup_or_generate(vec: &mut Vec<Option<MovePathIndex>>,
-                          idx: u32,
-                          next_index: &mut MovePathIndex) -> Lookup<MovePathIndex> {
-        let idx = idx as usize;
-        vec.fill_to_with(idx, None);
+    fn lookup_or_generate<I: Idx>(vec: &mut IndexVec<I, Option<MovePathIndex>>,
+                                  idx: I,
+                                  next_index: &mut MovePathIndex)
+                                  -> Lookup<MovePathIndex> {
         let entry = &mut vec[idx];
         match *entry {
             None => {
@@ -335,19 +330,19 @@ impl<'tcx> MovePathLookup<'tcx> {
         }
     }
 
-    fn lookup_var(&mut self, var_idx: u32) -> Lookup<MovePathIndex> {
+    fn lookup_var(&mut self, var_idx: Var) -> Lookup<MovePathIndex> {
         Self::lookup_or_generate(&mut self.vars,
                                  var_idx,
                                  &mut self.next_index)
     }
 
-    fn lookup_temp(&mut self, temp_idx: u32) -> Lookup<MovePathIndex> {
+    fn lookup_temp(&mut self, temp_idx: Temp) -> Lookup<MovePathIndex> {
         Self::lookup_or_generate(&mut self.temps,
                                  temp_idx,
                                  &mut self.next_index)
     }
 
-    fn lookup_arg(&mut self, arg_idx: u32) -> Lookup<MovePathIndex> {
+    fn lookup_arg(&mut self, arg_idx: Arg) -> Lookup<MovePathIndex> {
         Self::lookup_or_generate(&mut self.args,
                                  arg_idx,
                                  &mut self.next_index)
@@ -384,8 +379,8 @@ impl<'tcx> MovePathLookup<'tcx> {
                    base: MovePathIndex) -> Lookup<MovePathIndex> {
         let MovePathLookup { ref mut projections,
                              ref mut next_index, .. } = *self;
-        projections.fill_to(base.idx());
-        match projections[base.idx()].entry(proj.elem.lift()) {
+        projections.fill_to(base.index());
+        match projections[base.index()].entry(proj.elem.lift()) {
             Entry::Occupied(ent) => {
                 Lookup(LookupKind::Reuse, *ent.get())
             }
@@ -404,14 +399,14 @@ impl<'tcx> MovePathLookup<'tcx> {
     // unknown l-value; it will simply panic.
     pub fn find(&self, lval: &Lvalue<'tcx>) -> MovePathIndex {
         match *lval {
-            Lvalue::Var(var_idx) => self.vars[var_idx as usize].unwrap(),
-            Lvalue::Temp(temp_idx) => self.temps[temp_idx as usize].unwrap(),
-            Lvalue::Arg(arg_idx) => self.args[arg_idx as usize].unwrap(),
+            Lvalue::Var(var) => self.vars[var].unwrap(),
+            Lvalue::Temp(temp) => self.temps[temp].unwrap(),
+            Lvalue::Arg(arg) => self.args[arg].unwrap(),
             Lvalue::Static(ref _def_id) => self.statics.unwrap(),
             Lvalue::ReturnPointer => self.return_ptr.unwrap(),
             Lvalue::Projection(ref proj) => {
                 let base_index = self.find(&proj.base);
-                self.projections[base_index.idx()][&proj.elem.lift()]
+                self.projections[base_index.index()][&proj.elem.lift()]
             }
         }
     }
@@ -451,7 +446,7 @@ impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> {
 
         // `lookup` is either the previously assigned index or a
         // newly-allocated one.
-        debug_assert!(lookup.idx() <= self.pre_move_paths.len());
+        debug_assert!(lookup.index() <= self.pre_move_paths.len());
 
         if let Lookup(LookupKind::Generate, mpi) = lookup {
             let parent;
@@ -482,7 +477,7 @@ impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> {
                     let idx = self.move_path_for(&proj.base);
                     parent = Some(idx);
 
-                    let parent_move_path = &mut self.pre_move_paths[idx.idx()];
+                    let parent_move_path = &mut self.pre_move_paths[idx.index()];
 
                     // At last: Swap in the new first_child.
                     sibling = parent_move_path.first_child.get();
@@ -524,9 +519,9 @@ enum StmtKind {
 fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveData<'tcx> {
     use self::StmtKind as SK;
 
-    let bbs = mir.all_basic_blocks();
-    let mut moves = Vec::with_capacity(bbs.len());
-    let mut loc_map: Vec<_> = iter::repeat(Vec::new()).take(bbs.len()).collect();
+    let bb_count = mir.basic_blocks().len();
+    let mut moves = vec![];
+    let mut loc_map: Vec<_> = iter::repeat(Vec::new()).take(bb_count).collect();
     let mut path_map = Vec::new();
 
     // this is mutable only because we will move it to and fro' the
@@ -535,7 +530,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
     let mut builder = MovePathDataBuilder {
         mir: mir,
         pre_move_paths: Vec::new(),
-        rev_lookup: MovePathLookup::new(),
+        rev_lookup: MovePathLookup::new(mir),
     };
 
     // Before we analyze the program text, we create the MovePath's
@@ -546,22 +541,21 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
     assert!(mir.var_decls.len() <= ::std::u32::MAX as usize);
     assert!(mir.arg_decls.len() <= ::std::u32::MAX as usize);
     assert!(mir.temp_decls.len() <= ::std::u32::MAX as usize);
-    for var_idx in 0..mir.var_decls.len() {
-        let path_idx = builder.move_path_for(&Lvalue::Var(var_idx as u32));
-        path_map.fill_to(path_idx.idx());
+    for var in mir.var_decls.indices() {
+        let path_idx = builder.move_path_for(&Lvalue::Var(var));
+        path_map.fill_to(path_idx.index());
     }
-    for arg_idx in 0..mir.arg_decls.len() {
-        let path_idx = builder.move_path_for(&Lvalue::Arg(arg_idx as u32));
-        path_map.fill_to(path_idx.idx());
+    for arg in mir.arg_decls.indices() {
+        let path_idx = builder.move_path_for(&Lvalue::Arg(arg));
+        path_map.fill_to(path_idx.index());
     }
-    for temp_idx in 0..mir.temp_decls.len() {
-        let path_idx = builder.move_path_for(&Lvalue::Temp(temp_idx as u32));
-        path_map.fill_to(path_idx.idx());
+    for temp in mir.temp_decls.indices() {
+        let path_idx = builder.move_path_for(&Lvalue::Temp(temp));
+        path_map.fill_to(path_idx.index());
     }
 
-    for bb in bbs {
+    for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
         let loc_map_bb = &mut loc_map[bb.index()];
-        let bb_data = mir.basic_block_data(bb);
 
         debug_assert!(loc_map_bb.len() == 0);
         let len = bb_data.statements.len();
@@ -585,7 +579,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
                     // Ensure that the path_map contains entries even
                     // if the lvalue is assigned and never read.
                     let assigned_path = bb_ctxt.builder.move_path_for(lval);
-                    bb_ctxt.path_map.fill_to(assigned_path.idx());
+                    bb_ctxt.path_map.fill_to(assigned_path.index());
 
                     match *rval {
                         Rvalue::Use(ref operand) => {
@@ -620,22 +614,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
                         Rvalue::Ref(..) |
                         Rvalue::Len(..) |
                         Rvalue::InlineAsm { .. } => {}
-
-                        Rvalue::Slice {..} => {
-                            // A slice pattern `x..` binds `x` to a
-                            // reference; thus no move occurs.
-                            //
-                            // FIXME: I recall arielb1 questioning
-                            // whether this is even a legal thing to
-                            // have as an R-value. The particular
-                            // example where I am seeing this arise is
-                            // `TargetDataLayout::parse(&Session)` in
-                            // `rustc::ty::layout`.
-                            //
-                            // this should be removed soon.
-                            debug!("encountered Rvalue::Slice as RHS of Assign, source: {:?}",
-                                   source);
-                        }
                     }
                 }
             }
@@ -643,7 +621,9 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
 
         debug!("gather_moves({:?})", bb_data.terminator());
         match bb_data.terminator().kind {
-            TerminatorKind::Goto { target: _ } | TerminatorKind::Resume => { }
+            TerminatorKind::Goto { target: _ } |
+            TerminatorKind::Resume |
+            TerminatorKind::Unreachable => { }
 
             TerminatorKind::Return => {
                 let source = Location { block: bb,
@@ -695,7 +675,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
             }
             TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
                 let assigned_path = bb_ctxt.builder.move_path_for(location);
-                bb_ctxt.path_map.fill_to(assigned_path.idx());
+                bb_ctxt.path_map.fill_to(assigned_path.index());
 
                 let source = Location { block: bb,
                                         index: bb_data.statements.len() };
@@ -715,7 +695,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
                     // Ensure that the path_map contains entries even
                     // if the lvalue is assigned and never read.
                     let assigned_path = bb_ctxt.builder.move_path_for(destination);
-                    bb_ctxt.path_map.fill_to(assigned_path.idx());
+                    bb_ctxt.path_map.fill_to(assigned_path.index());
 
                     bb_ctxt.builder.create_move_path(destination);
                 }
@@ -745,8 +725,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
         let mut seen: Vec<_> = move_paths.iter().map(|_| false).collect();
         for (j, &MoveOut { ref path, ref source }) in moves.iter().enumerate() {
             debug!("MovePathData moves[{}]: MoveOut {{ path: {:?} = {:?}, source: {:?} }}",
-                   j, path, move_paths[path.idx()], source);
-            seen[path.idx()] = true;
+                   j, path, move_paths[path.index()], source);
+            seen[path.index()] = true;
         }
         for (j, path) in move_paths.iter().enumerate() {
             if !seen[j] {
@@ -783,7 +763,7 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> {
 
         let path = self.builder.move_path_for(lval);
         self.moves.push(MoveOut { path: path, source: source.clone() });
-        self.path_map.fill_to(path.idx());
+        self.path_map.fill_to(path.index());
 
         debug!("ctxt: {:?} add consume of lval: {:?} \
                 at index: {:?} \
@@ -791,12 +771,12 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> {
                 to loc_map for loc: {:?}",
                stmt_kind, lval, index, path, source);
 
-        debug_assert!(path.idx() < self.path_map.len());
+        debug_assert!(path.index() < self.path_map.len());
         // this is actually a questionable assert; at the very
         // least, incorrect input code can probably cause it to
         // fire.
-        assert!(self.path_map[path.idx()].iter().find(|idx| **idx == index).is_none());
-        self.path_map[path.idx()].push(index);
+        assert!(self.path_map[path.index()].iter().find(|idx| **idx == index).is_none());
+        self.path_map[path.index()].push(index);
 
         debug_assert!(i < self.loc_map_bb.len());
         debug_assert!(self.loc_map_bb[i].iter().find(|idx| **idx == index).is_none());
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index 007cde156f4..36f7c11c8cb 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -111,7 +111,7 @@ pub fn borrowck_mir<'a, 'tcx: 'a>(
         flow_uninits: flow_uninits,
     };
 
-    for bb in mir.all_basic_blocks() {
+    for bb in mir.basic_blocks().indices() {
         mbcx.process_basic_block(bb);
     }
 
@@ -180,8 +180,8 @@ pub struct MirBorrowckCtxt<'b, 'a: 'b, 'tcx: 'a> {
 
 impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> {
     fn process_basic_block(&mut self, bb: BasicBlock) {
-        let &BasicBlockData { ref statements, ref terminator, is_cleanup: _ } =
-            self.mir.basic_block_data(bb);
+        let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } =
+            self.mir[bb];
         for stmt in statements {
             self.process_statement(bb, stmt);
         }
@@ -235,6 +235,45 @@ fn move_path_children_matching<'tcx, F>(move_paths: &MovePathData<'tcx>,
     None
 }
 
+/// When enumerating the child fragments of a path, don't recurse into
+/// paths (1.) past arrays, slices, and pointers, nor (2.) into a type
+/// that implements `Drop`.
+///
+/// Lvalues behind references or arrays are not tracked by elaboration
+/// and are always assumed to be initialized when accessible. As
+/// references and indexes can be reseated, trying to track them can
+/// only lead to trouble.
+///
+/// Lvalues behind ADT's with a Drop impl are not tracked by
+/// elaboration since they can never have a drop-flag state that
+/// differs from that of the parent with the Drop impl.
+///
+/// In both cases, the contents can only be accessed if and only if
+/// their parents are initialized. This implies for example that there
+/// is no need to maintain separate drop flags to track such state.
+///
+/// FIXME: we have to do something for moving slice patterns.
+fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                                      mir: &Mir<'tcx>,
+                                                      lv: &repr::Lvalue<'tcx>) -> bool {
+    let ty = mir.lvalue_ty(tcx, lv).to_ty(tcx);
+    match ty.sty {
+        ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
+            debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => false",
+                   lv, ty);
+            true
+        }
+        ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
+            debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false",
+                   lv, ty);
+            true
+        }
+        _ => {
+            false
+        }
+    }
+}
+
 fn on_all_children_bits<'a, 'tcx, F>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     mir: &Mir<'tcx>,
@@ -251,17 +290,7 @@ fn on_all_children_bits<'a, 'tcx, F>(
     {
         match move_data.move_paths[path].content {
             MovePathContent::Lvalue(ref lvalue) => {
-                match mir.lvalue_ty(tcx, lvalue).to_ty(tcx).sty {
-                    // don't trace paths past arrays, slices, and
-                    // pointers. They can only be accessed while
-                    // their parents are initialized.
-                    //
-                    // FIXME: we have to do something for moving
-                    // slice patterns.
-                    ty::TyArray(..) | ty::TySlice(..) |
-                    ty::TyRef(..) | ty::TyRawPtr(..) => true,
-                    _ => false
-                }
+                lvalue_contents_drop_state_cannot_differ(tcx, mir, lvalue)
             }
             _ => true
         }
@@ -298,8 +327,8 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
     where F: FnMut(MovePathIndex, DropFlagState)
 {
     let move_data = &ctxt.move_data;
-    for i in 0..(mir.arg_decls.len() as u32) {
-        let lvalue = repr::Lvalue::Arg(i);
+    for (arg, _) in mir.arg_decls.iter_enumerated() {
+        let lvalue = repr::Lvalue::Arg(arg);
         let move_path_index = move_data.rev_lookup.find(&lvalue);
         on_all_children_bits(tcx, mir, move_data,
                              move_path_index,
@@ -337,8 +366,8 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
                              |moi| callback(moi, DropFlagState::Absent))
     }
 
-    let bb = mir.basic_block_data(loc.block);
-    match bb.statements.get(loc.index) {
+    let block = &mir[loc.block];
+    match block.statements.get(loc.index) {
         Some(stmt) => match stmt.kind {
             repr::StatementKind::Assign(ref lvalue, _) => {
                 debug!("drop_flag_effects: assignment {:?}", stmt);
@@ -348,8 +377,8 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
             }
         },
         None => {
-            debug!("drop_flag_effects: replace {:?}", bb.terminator());
-            match bb.terminator().kind {
+            debug!("drop_flag_effects: replace {:?}", block.terminator());
+            match block.terminator().kind {
                 repr::TerminatorKind::DropAndReplace { ref location, .. } => {
                     on_all_children_bits(tcx, mir, move_data,
                                          move_data.rev_lookup.find(location),
diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_borrowck/borrowck/mir/patch.rs
index b390c19af1a..417e719a9dc 100644
--- a/src/librustc_borrowck/borrowck/mir/patch.rs
+++ b/src/librustc_borrowck/borrowck/mir/patch.rs
@@ -11,32 +11,28 @@
 use super::gather_moves::Location;
 use rustc::ty::Ty;
 use rustc::mir::repr::*;
-use syntax::codemap::Span;
-
-use std::iter;
-use std::u32;
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 /// This struct represents a patch to MIR, which can add
 /// new statements and basic blocks and patch over block
 /// terminators.
 pub struct MirPatch<'tcx> {
-    patch_map: Vec<Option<TerminatorKind<'tcx>>>,
+    patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
     new_blocks: Vec<BasicBlockData<'tcx>>,
     new_statements: Vec<(Location, StatementKind<'tcx>)>,
     new_temps: Vec<TempDecl<'tcx>>,
     resume_block: BasicBlock,
-    next_temp: u32,
+    next_temp: usize,
 }
 
 impl<'tcx> MirPatch<'tcx> {
     pub fn new(mir: &Mir<'tcx>) -> Self {
         let mut result = MirPatch {
-            patch_map: iter::repeat(None)
-                .take(mir.basic_blocks.len()).collect(),
+            patch_map: IndexVec::from_elem(None, mir.basic_blocks()),
             new_blocks: vec![],
             new_temps: vec![],
             new_statements: vec![],
-            next_temp: mir.temp_decls.len() as u32,
+            next_temp: mir.temp_decls.len(),
             resume_block: START_BLOCK
         };
 
@@ -47,13 +43,12 @@ impl<'tcx> MirPatch<'tcx> {
 
         let mut resume_block = None;
         let mut resume_stmt_block = None;
-        for block in mir.all_basic_blocks() {
-            let data = mir.basic_block_data(block);
-            if let TerminatorKind::Resume = data.terminator().kind {
-                if data.statements.len() > 0 {
-                    resume_stmt_block = Some(block);
+        for (bb, block) in mir.basic_blocks().iter_enumerated() {
+            if let TerminatorKind::Resume = block.terminator().kind {
+                if block.statements.len() > 0 {
+                    resume_stmt_block = Some(bb);
                 } else {
-                    resume_block = Some(block);
+                    resume_block = Some(bb);
                 }
                 break
             }
@@ -62,8 +57,10 @@ impl<'tcx> MirPatch<'tcx> {
             result.new_block(BasicBlockData {
                 statements: vec![],
                 terminator: Some(Terminator {
-                    span: mir.span,
-                    scope: ScopeId::new(0),
+                    source_info: SourceInfo {
+                        span: mir.span,
+                        scope: ARGUMENT_VISIBILITY_SCOPE
+                    },
                     kind: TerminatorKind::Resume
                 }),
                 is_cleanup: true
@@ -82,13 +79,13 @@ impl<'tcx> MirPatch<'tcx> {
     }
 
     pub fn is_patched(&self, bb: BasicBlock) -> bool {
-        self.patch_map[bb.index()].is_some()
+        self.patch_map[bb].is_some()
     }
 
     pub fn terminator_loc(&self, mir: &Mir<'tcx>, bb: BasicBlock) -> Location {
-        let offset = match bb.index().checked_sub(mir.basic_blocks.len()) {
+        let offset = match bb.index().checked_sub(mir.basic_blocks().len()) {
             Some(index) => self.new_blocks[index].statements.len(),
-            None => mir.basic_block_data(bb).statements.len()
+            None => mir[bb].statements.len()
         };
         Location {
             block: bb,
@@ -96,12 +93,11 @@ impl<'tcx> MirPatch<'tcx> {
         }
     }
 
-    pub fn new_temp(&mut self, ty: Ty<'tcx>) -> u32 {
+    pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Temp {
         let index = self.next_temp;
-        assert!(self.next_temp < u32::MAX);
         self.next_temp += 1;
         self.new_temps.push(TempDecl { ty: ty });
-        index
+        Temp::new(index as usize)
     }
 
     pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
@@ -113,9 +109,9 @@ impl<'tcx> MirPatch<'tcx> {
     }
 
     pub fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) {
-        assert!(self.patch_map[block.index()].is_none());
+        assert!(self.patch_map[block].is_none());
         debug!("MirPatch: patch_terminator({:?}, {:?})", block, new);
-        self.patch_map[block.index()] = Some(new);
+        self.patch_map[block] = Some(new);
     }
 
     pub fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) {
@@ -131,13 +127,13 @@ impl<'tcx> MirPatch<'tcx> {
         debug!("MirPatch: {:?} new temps, starting from index {}: {:?}",
                self.new_temps.len(), mir.temp_decls.len(), self.new_temps);
         debug!("MirPatch: {} new blocks, starting from index {}",
-               self.new_blocks.len(), mir.basic_blocks.len());
-        mir.basic_blocks.extend(self.new_blocks);
+               self.new_blocks.len(), mir.basic_blocks().len());
+        mir.basic_blocks_mut().extend(self.new_blocks);
         mir.temp_decls.extend(self.new_temps);
-        for (src, patch) in self.patch_map.into_iter().enumerate() {
+        for (src, patch) in self.patch_map.into_iter_enumerated() {
             if let Some(patch) = patch {
                 debug!("MirPatch: patching block {:?}", src);
-                mir.basic_blocks[src].terminator_mut().kind = patch;
+                mir[src].terminator_mut().kind = patch;
             }
         }
 
@@ -154,31 +150,30 @@ impl<'tcx> MirPatch<'tcx> {
             debug!("MirPatch: adding statement {:?} at loc {:?}+{}",
                    stmt, loc, delta);
             loc.index += delta;
-            let (span, scope) = Self::context_for_index(
-                mir.basic_block_data(loc.block), loc
+            let source_info = Self::source_info_for_index(
+                &mir[loc.block], loc
             );
-            mir.basic_block_data_mut(loc.block).statements.insert(
+            mir[loc.block].statements.insert(
                 loc.index, Statement {
-                    span: span,
-                    scope: scope,
+                    source_info: source_info,
                     kind: stmt
                 });
             delta += 1;
         }
     }
 
-    pub fn context_for_index(data: &BasicBlockData, loc: Location) -> (Span, ScopeId) {
+    pub fn source_info_for_index(data: &BasicBlockData, loc: Location) -> SourceInfo {
         match data.statements.get(loc.index) {
-            Some(stmt) => (stmt.span, stmt.scope),
-            None => (data.terminator().span, data.terminator().scope)
+            Some(stmt) => stmt.source_info,
+            None => data.terminator().source_info
         }
     }
 
-    pub fn context_for_location(&self, mir: &Mir, loc: Location) -> (Span, ScopeId) {
-        let data = match loc.block.index().checked_sub(mir.basic_blocks.len()) {
+    pub fn source_info_for_location(&self, mir: &Mir, loc: Location) -> SourceInfo {
+        let data = match loc.block.index().checked_sub(mir.basic_blocks().len()) {
             Some(new) => &self.new_blocks[new],
-            None => mir.basic_block_data(loc.block)
+            None => &mir[loc.block]
         };
-        Self::context_for_index(data, loc)
+        Self::source_info_for_index(data, loc)
     }
 }
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index 0624d72dd59..400ae186010 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -516,8 +516,10 @@ fn foo(a: &mut i32) {
             //        as immutable
 }
 ```
+
 To fix this error, ensure that you don't have any other references to the
 variable before trying to access it mutably:
+
 ```
 fn bar(x: &mut i32) {}
 fn foo(a: &mut i32) {
@@ -525,10 +527,67 @@ fn foo(a: &mut i32) {
     let ref y = a; // ok!
 }
 ```
+
 For more information on the rust ownership system, take a look at
 https://doc.rust-lang.org/stable/book/references-and-borrowing.html.
 "##,
 
+E0503: r##"
+A value was used after it was mutably borrowed.
+
+Example of erroneous code:
+
+```compile_fail
+fn main() {
+    let mut value = 3;
+    // Create a mutable borrow of `value`. This borrow
+    // lives until the end of this function.
+    let _borrow = &mut value;
+    let _sum = value + 1; // error: cannot use `value` because
+                          //        it was mutably borrowed
+}
+```
+
+In this example, `value` is mutably borrowed by `borrow` and cannot be
+used to calculate `sum`. This is not possible because this would violate
+Rust's mutability rules.
+
+You can fix this error by limiting the scope of the borrow:
+
+```
+fn main() {
+    let mut value = 3;
+    // By creating a new block, you can limit the scope
+    // of the reference.
+    {
+        let _borrow = &mut value; // Use `_borrow` inside this block.
+    }
+    // The block has ended and with it the borrow.
+    // You can now use `value` again.
+    let _sum = value + 1;
+}
+```
+
+Or by cloning `value` before borrowing it:
+
+```
+fn main() {
+    let mut value = 3;
+    // We clone `value`, creating a copy.
+    let value_cloned = value.clone();
+    // The mutable borrow is a reference to `value` and
+    // not to `value_cloned`...
+    let _borrow = &mut value;
+    // ... which means we can still use `value_cloned`,
+    let _sum = value_cloned + 1;
+    // even though the borrow only ends here.
+}
+```
+
+You can find more information about borrowing in the rust-book:
+http://doc.rust-lang.org/stable/book/references-and-borrowing.html
+"##,
+
 E0504: r##"
 This error occurs when an attempt is made to move a borrowed variable into a
 closure.
@@ -911,6 +970,50 @@ You can find more information about borrowing in the rust-book:
 http://doc.rust-lang.org/stable/book/references-and-borrowing.html
 "##,
 
+E0508: r##"
+A value was moved out of a non-copy fixed-size array.
+
+Example of erroneous code:
+
+```compile_fail
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`,
+                           //        a non-copy fixed-size array
+}
+```
+
+The first element was moved out of the array, but this is not
+possible because `NonCopy` does not implement the `Copy` trait.
+
+Consider borrowing the element instead of moving it:
+
+```
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = &array[0]; // Borrowing is allowed, unlike moving.
+}
+```
+
+Alternatively, if your type implements `Clone` and you need to own the value,
+consider borrowing and then cloning:
+
+```
+#[derive(Clone)]
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    // Now you can clone the array element.
+    let _value = array[0].clone();
+}
+```
+"##,
+
 E0509: r##"
 This error occurs when an attempt is made to move out of a value whose type
 implements the `Drop` trait.
@@ -1011,7 +1114,5 @@ fn main() {
 register_diagnostics! {
     E0385, // {} in an aliasable location
     E0388, // {} in a static location
-    E0503, // cannot use `..` because it was mutably borrowed
-    E0508, // cannot move out of type `..`, a non-copy fixed-size array
     E0524, // two closures require unique access to `..` at the same time
 }
diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs
index 3fee1dbc056..671aff97d20 100644
--- a/src/librustc_borrowck/indexed_set.rs
+++ b/src/librustc_borrowck/indexed_set.rs
@@ -17,13 +17,7 @@ use std::ops::{Deref, DerefMut, Range};
 use bitslice::{BitSlice, Word};
 use bitslice::{bitwise, Union, Subtract};
 
-/// Represents some newtyped `usize` wrapper.
-///
-/// (purpose: avoid mixing indexes for different bitvector domains.)
-pub trait Idx: 'static {
-    fn new(usize) -> Self;
-    fn idx(&self) -> usize;
-}
+use rustc_data_structures::indexed_vec::Idx;
 
 /// Represents a set (or packed family of sets), of some element type
 /// E, where each E is identified by some unique index type `T`.
@@ -120,27 +114,27 @@ impl<T: Idx> IdxSet<T> {
 
     /// Removes `elem` from the set `self`; returns true iff this changed `self`.
     pub fn remove(&mut self, elem: &T) -> bool {
-        self.bits.clear_bit(elem.idx())
+        self.bits.clear_bit(elem.index())
     }
 
     /// Adds `elem` to the set `self`; returns true iff this changed `self`.
     pub fn add(&mut self, elem: &T) -> bool {
-        self.bits.set_bit(elem.idx())
+        self.bits.set_bit(elem.index())
     }
 
     pub fn range(&self, elems: &Range<T>) -> &Self {
-        let elems = elems.start.idx()..elems.end.idx();
+        let elems = elems.start.index()..elems.end.index();
         unsafe { Self::from_slice(&self.bits[elems]) }
     }
 
     pub fn range_mut(&mut self, elems: &Range<T>) -> &mut Self {
-        let elems = elems.start.idx()..elems.end.idx();
+        let elems = elems.start.index()..elems.end.index();
         unsafe { Self::from_slice_mut(&mut self.bits[elems]) }
     }
 
     /// Returns true iff set `self` contains `elem`.
     pub fn contains(&self, elem: &T) -> bool {
-        self.bits.get_bit(elem.idx())
+        self.bits.get_bit(elem.index())
     }
 
     pub fn words(&self) -> &[Word] {
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index cc694c59245..f3c39bd5fd1 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -34,6 +34,7 @@
 extern crate graphviz as dot;
 #[macro_use]
 extern crate rustc;
+extern crate rustc_data_structures;
 extern crate rustc_mir;
 extern crate core; // for NonZero
 
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 49fa1896ff8..dbca15ffd34 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -42,6 +42,7 @@ use rustc::hir::fold::{Folder, noop_fold_pat};
 use rustc::hir::print::pat_to_string;
 use syntax::ptr::P;
 use rustc::util::nodemap::FnvHashMap;
+use rustc::util::common::slice_pat;
 
 pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
     id: DUMMY_NODE_ID,
@@ -49,7 +50,7 @@ pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
     span: DUMMY_SP
 };
 
-struct Matrix<'a>(Vec<Vec<&'a Pat>>);
+struct Matrix<'a, 'tcx>(Vec<Vec<(&'a Pat, Option<Ty<'tcx>>)>>);
 
 /// Pretty-printer for matrices of patterns, example:
 /// ++++++++++++++++++++++++++
@@ -63,14 +64,14 @@ struct Matrix<'a>(Vec<Vec<&'a Pat>>);
 /// ++++++++++++++++++++++++++
 /// + _     + [_, _, ..tail] +
 /// ++++++++++++++++++++++++++
-impl<'a> fmt::Debug for Matrix<'a> {
+impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "\n")?;
 
         let &Matrix(ref m) = self;
         let pretty_printed_matrix: Vec<Vec<String>> = m.iter().map(|row| {
             row.iter()
-               .map(|&pat| pat_to_string(&pat))
+               .map(|&(pat,ty)| format!("{}: {:?}", pat_to_string(&pat), ty))
                .collect::<Vec<String>>()
         }).collect();
 
@@ -97,8 +98,10 @@ impl<'a> fmt::Debug for Matrix<'a> {
     }
 }
 
-impl<'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> {
-    fn from_iter<T: IntoIterator<Item=Vec<&'a Pat>>>(iter: T) -> Matrix<'a> {
+impl<'a, 'tcx> FromIterator<Vec<(&'a Pat, Option<Ty<'tcx>>)>> for Matrix<'a, 'tcx> {
+    fn from_iter<T: IntoIterator<Item=Vec<(&'a Pat, Option<Ty<'tcx>>)>>>(iter: T)
+                                                                         -> Self
+    {
         Matrix(iter.into_iter().collect())
     }
 }
@@ -109,7 +112,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
     pub param_env: ParameterEnvironment<'tcx>,
 }
 
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum Constructor {
     /// The constructor of all patterns that don't vary by constructor,
     /// e.g. struct patterns and fixed-length arrays.
@@ -229,7 +232,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
                 .iter()
                 .filter(|&&(_, guard)| guard.is_none())
                 .flat_map(|arm| &arm.0)
-                .map(|pat| vec![&**pat])
+                .map(|pat| vec![wrap_pat(cx, &pat)])
                 .collect();
             check_exhaustive(cx, ex.span, &matrix, source);
         },
@@ -242,11 +245,9 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
         if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node {
             let pat_ty = cx.tcx.pat_ty(p);
             if let ty::TyEnum(edef, _) = pat_ty.sty {
-                let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
-                if let Some(Def::Local(..)) = def {
+                if let Def::Local(..) = cx.tcx.expect_def(p.id) {
                     if edef.variants.iter().any(|variant|
-                        variant.name == name.node.unhygienize()
-                            && variant.kind() == VariantKind::Unit
+                        variant.name == name.node && variant.kind() == VariantKind::Unit
                     ) {
                         let ty_path = cx.tcx.item_path_str(edef.did);
                         let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
@@ -301,7 +302,7 @@ fn check_arms(cx: &MatchCheckCtxt,
     let mut printed_if_let_err = false;
     for &(ref pats, guard) in arms {
         for pat in pats {
-            let v = vec![&**pat];
+            let v = vec![wrap_pat(cx, &pat)];
 
             match is_useful(cx, &seen, &v[..], LeaveOutWitness) {
                 NotUseful => {
@@ -341,8 +342,9 @@ fn check_arms(cx: &MatchCheckCtxt,
                                                            "unreachable pattern");
                             // if we had a catchall pattern, hint at that
                             for row in &seen.0 {
-                                if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0]) {
-                                    span_note!(err, row[0].span, "this pattern matches any value");
+                                if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) {
+                                    span_note!(err, row[0].0.span,
+                                               "this pattern matches any value");
                                 }
                             }
                             err.emit();
@@ -383,20 +385,23 @@ fn raw_pat(p: &Pat) -> &Pat {
     }
 }
 
-fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir::MatchSource) {
-    match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) {
+fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
+                              sp: Span,
+                              matrix: &Matrix<'a, 'tcx>,
+                              source: hir::MatchSource) {
+    match is_useful(cx, matrix, &[(DUMMY_WILD_PAT, None)], ConstructWitness) {
         UsefulWithWitness(pats) => {
             let witnesses = if pats.is_empty() {
                 vec![DUMMY_WILD_PAT]
             } else {
-                pats.iter().map(|w| &**w ).collect()
+                pats.iter().map(|w| &**w).collect()
             };
             match source {
                 hir::MatchSource::ForLoopDesugar => {
                     // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
                     let witness = match witnesses[0].node {
-                        PatKind::TupleStruct(_, ref pats, _) => match &pats[..] {
-                            [ref pat] => &**pat,
+                        PatKind::TupleStruct(_, ref pats, _) => match slice_pat(&&pats[..]) {
+                            &[ref pat] => &**pat,
                             _ => bug!(),
                         },
                         _ => bug!(),
@@ -485,9 +490,8 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
     fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
         return match pat.node {
             PatKind::Path(..) | PatKind::QPath(..) => {
-                let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
-                match def {
-                    Some(Def::AssociatedConst(did)) | Some(Def::Const(did)) => {
+                match self.tcx.expect_def(pat.id) {
+                    Def::AssociatedConst(did) | Def::Const(did) => {
                         let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
                         if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) {
                             match const_expr_to_pat(self.tcx, const_expr, pat.id, pat.span) {
@@ -584,31 +588,19 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
             }
         }
 
-        ty::TyRef(_, ty::TypeAndMut { ty, mutbl }) => {
-            match ty.sty {
-               ty::TyArray(_, n) => match ctor {
-                    &Single => {
-                        assert_eq!(pats_len, n);
-                        PatKind::Vec(pats.collect(), None, hir::HirVec::new())
-                    },
-                    _ => bug!()
-                },
-                ty::TySlice(_) => match ctor {
-                    &Slice(n) => {
-                        assert_eq!(pats_len, n);
-                        PatKind::Vec(pats.collect(), None, hir::HirVec::new())
-                    },
-                    _ => bug!()
-                },
-                ty::TyStr => PatKind::Wild,
-
-                _ => {
-                    assert_eq!(pats_len, 1);
-                    PatKind::Ref(pats.nth(0).unwrap(), mutbl)
-                }
-            }
+        ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => {
+            assert_eq!(pats_len, 1);
+            PatKind::Ref(pats.nth(0).unwrap(), mutbl)
         }
 
+        ty::TySlice(_) => match ctor {
+            &Slice(n) => {
+                assert_eq!(pats_len, n);
+                PatKind::Vec(pats.collect(), None, hir::HirVec::new())
+            },
+            _ => unreachable!()
+        },
+
         ty::TyArray(_, len) => {
             assert_eq!(pats_len, len);
             PatKind::Vec(pats.collect(), None, hir::HirVec::new())
@@ -643,7 +635,7 @@ impl Constructor {
 fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
                        left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
     let used_constructors: Vec<Constructor> = rows.iter()
-        .flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
+        .flat_map(|row| pat_constructors(cx, row[0].0, left_ty, max_slice_length))
         .collect();
     all_constructors(cx, left_ty, max_slice_length)
         .into_iter()
@@ -660,13 +652,8 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty,
     match left_ty.sty {
         ty::TyBool =>
             [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
-
-        ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty {
-            ty::TySlice(_) =>
-                (0..max_slice_length+1).map(|length| Slice(length)).collect(),
-            _ => vec![Single]
-        },
-
+        ty::TySlice(_) =>
+            (0..max_slice_length+1).map(|length| Slice(length)).collect(),
         ty::TyEnum(def, _) => def.variants.iter().map(|v| Variant(v.did)).collect(),
         _ => vec![Single]
     }
@@ -685,13 +672,13 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty,
 
 // Note: is_useful doesn't work on empty types, as the paper notes.
 // So it assumes that v is non-empty.
-fn is_useful(cx: &MatchCheckCtxt,
-             matrix: &Matrix,
-             v: &[&Pat],
-             witness: WitnessPreference)
-             -> Usefulness {
+fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
+                       matrix: &Matrix<'a, 'tcx>,
+                       v: &[(&Pat, Option<Ty<'tcx>>)],
+                       witness: WitnessPreference)
+                       -> Usefulness {
     let &Matrix(ref rows) = matrix;
-    debug!("{:?}", matrix);
+    debug!("is_useful({:?}, {:?})", matrix, v);
     if rows.is_empty() {
         return match witness {
             ConstructWitness => UsefulWithWitness(vec!()),
@@ -702,32 +689,25 @@ fn is_useful(cx: &MatchCheckCtxt,
         return NotUseful;
     }
     assert!(rows.iter().all(|r| r.len() == v.len()));
-    let real_pat = match rows.iter().find(|r| (*r)[0].id != DUMMY_NODE_ID) {
-        Some(r) => raw_pat(r[0]),
-        None if v.is_empty() => return NotUseful,
-        None => v[0]
-    };
-    let left_ty = if real_pat.id == DUMMY_NODE_ID {
-        cx.tcx.mk_nil()
-    } else {
-        let left_ty = cx.tcx.pat_ty(&real_pat);
-
-        match real_pat.node {
-            PatKind::Binding(hir::BindByRef(..), _, _) => {
-                left_ty.builtin_deref(false, NoPreference).unwrap().ty
-            }
-            _ => left_ty,
+    let left_ty = match rows.iter().filter_map(|r| r[0].1).next().or_else(|| v[0].1) {
+        Some(ty) => ty,
+        None => {
+            // all patterns are wildcards - we can pick any type we want
+            cx.tcx.types.bool
         }
     };
 
-    let max_slice_length = rows.iter().filter_map(|row| match row[0].node {
+    let max_slice_length = rows.iter().filter_map(|row| match row[0].0.node {
         PatKind::Vec(ref before, _, ref after) => Some(before.len() + after.len()),
         _ => None
     }).max().map_or(0, |v| v + 1);
 
-    let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
+    let constructors = pat_constructors(cx, v[0].0, left_ty, max_slice_length);
+    debug!("is_useful - pat_constructors = {:?} left_ty = {:?}", constructors,
+           left_ty);
     if constructors.is_empty() {
         let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length);
+        debug!("is_useful - missing_constructors = {:?}", constructors);
         if constructors.is_empty() {
             all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
                 match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
@@ -748,7 +728,7 @@ fn is_useful(cx: &MatchCheckCtxt,
             }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
         } else {
             let matrix = rows.iter().filter_map(|r| {
-                match raw_pat(r[0]).node {
+                match raw_pat(r[0].0).node {
                     PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()),
                     _ => None,
                 }
@@ -773,9 +753,14 @@ fn is_useful(cx: &MatchCheckCtxt,
     }
 }
 
-fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix,
-                         v: &[&Pat], ctor: Constructor, lty: Ty,
-                         witness: WitnessPreference) -> Usefulness {
+fn is_useful_specialized<'a, 'tcx>(
+    cx: &MatchCheckCtxt<'a, 'tcx>,
+    &Matrix(ref m): &Matrix<'a, 'tcx>,
+    v: &[(&Pat, Option<Ty<'tcx>>)],
+    ctor: Constructor,
+    lty: Ty<'tcx>,
+    witness: WitnessPreference) -> Usefulness
+{
     let arity = constructor_arity(cx, &ctor, lty);
     let matrix = Matrix(m.iter().filter_map(|r| {
         specialize(cx, &r[..], &ctor, 0, arity)
@@ -800,7 +785,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
     let pat = raw_pat(p);
     match pat.node {
         PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
-            match cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def() {
+            match cx.tcx.expect_def(pat.id) {
                 Def::Const(..) | Def::AssociatedConst(..) =>
                     span_bug!(pat.span, "const pattern should've \
                                          been rewritten"),
@@ -818,13 +803,14 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
         PatKind::Vec(ref before, ref slice, ref after) =>
             match left_ty.sty {
                 ty::TyArray(_, _) => vec![Single],
-                _                      => if slice.is_some() {
+                ty::TySlice(_) if slice.is_some() => {
                     (before.len() + after.len()..max_slice_length+1)
                         .map(|length| Slice(length))
                         .collect()
-                } else {
-                    vec![Slice(before.len() + after.len())]
                 }
+                ty::TySlice(_) => vec!(Slice(before.len() + after.len())),
+                _ => span_bug!(pat.span, "pat_constructors: unexpected \
+                                          slice pattern type {:?}", left_ty)
             },
         PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) =>
             vec![Single],
@@ -839,18 +825,16 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
 /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
 /// A struct pattern's arity is the number of fields it contains, etc.
 pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
+    debug!("constructor_arity({:?}, {:?})", ctor, ty);
     match ty.sty {
         ty::TyTuple(ref fs) => fs.len(),
         ty::TyBox(_) => 1,
-        ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty {
-            ty::TySlice(_) => match *ctor {
-                Slice(length) => length,
-                ConstantValue(_) => 0,
-                _ => bug!()
-            },
-            ty::TyStr => 0,
-            _ => 1
+        ty::TySlice(_) => match *ctor {
+            Slice(length) => length,
+            ConstantValue(_) => 0,
+            _ => bug!()
         },
+        ty::TyRef(..) => 1,
         ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
             ctor.variant_for_adt(adt).fields.len()
         }
@@ -877,6 +861,19 @@ fn range_covered_by_constructor(ctor: &Constructor,
     }
 }
 
+fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
+                          pat: &'a Pat)
+                          -> (&'a Pat, Option<Ty<'tcx>>)
+{
+    let pat_ty = cx.tcx.pat_ty(pat);
+    (pat, Some(match pat.node {
+        PatKind::Binding(hir::BindByRef(..), _, _) => {
+            pat_ty.builtin_deref(false, NoPreference).unwrap().ty
+        }
+        _ => pat_ty
+    }))
+}
+
 /// This is the main specialization step. It expands the first pattern in the given row
 /// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
 /// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
@@ -885,31 +882,37 @@ fn range_covered_by_constructor(ctor: &Constructor,
 /// different patterns.
 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
 /// fields filled with wild patterns.
-pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
-                      constructor: &Constructor, col: usize, arity: usize) -> Option<Vec<&'a Pat>> {
+pub fn specialize<'a, 'b, 'tcx>(
+    cx: &MatchCheckCtxt<'b, 'tcx>,
+    r: &[(&'a Pat, Option<Ty<'tcx>>)],
+    constructor: &Constructor, col: usize, arity: usize)
+    -> Option<Vec<(&'a Pat, Option<Ty<'tcx>>)>>
+{
+    let pat = raw_pat(r[col].0);
     let &Pat {
         id: pat_id, ref node, span: pat_span
-    } = raw_pat(r[col]);
-    let head: Option<Vec<&Pat>> = match *node {
+    } = pat;
+    let wpat = |pat: &'a Pat| wrap_pat(cx, pat);
+    let dummy_pat = (DUMMY_WILD_PAT, None);
+
+    let head: Option<Vec<(&Pat, Option<Ty>)>> = match *node {
         PatKind::Binding(..) | PatKind::Wild =>
-            Some(vec![DUMMY_WILD_PAT; arity]),
+            Some(vec![dummy_pat; arity]),
 
         PatKind::Path(..) => {
-            let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
-            match def {
+            match cx.tcx.expect_def(pat_id) {
                 Def::Const(..) | Def::AssociatedConst(..) =>
                     span_bug!(pat_span, "const pattern should've \
                                          been rewritten"),
                 Def::Variant(_, id) if *constructor != Variant(id) => None,
                 Def::Variant(..) | Def::Struct(..) => Some(Vec::new()),
-                _ => span_bug!(pat_span, "specialize: unexpected \
+                def => span_bug!(pat_span, "specialize: unexpected \
                                           definition {:?}", def),
             }
         }
 
         PatKind::TupleStruct(_, ref args, ddpos) => {
-            let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
-            match def {
+            match cx.tcx.expect_def(pat_id) {
                 Def::Const(..) | Def::AssociatedConst(..) =>
                     span_bug!(pat_span, "const pattern should've \
                                          been rewritten"),
@@ -917,12 +920,14 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
                 Def::Variant(..) | Def::Struct(..) => {
                     match ddpos {
                         Some(ddpos) => {
-                            let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect();
-                            pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len()));
-                            pats.extend(args[ddpos..].iter().map(|p| &**p));
+                            let mut pats: Vec<_> = args[..ddpos].iter().map(|p| {
+                                wpat(p)
+                            }).collect();
+                            pats.extend(repeat((DUMMY_WILD_PAT, None)).take(arity - args.len()));
+                            pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
                             Some(pats)
                         }
-                        None => Some(args.iter().map(|p| &**p).collect())
+                        None => Some(args.iter().map(|p| wpat(p)).collect())
                     }
                 }
                 _ => None
@@ -934,15 +939,14 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         }
 
         PatKind::Struct(_, ref pattern_fields, _) => {
-            let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap();
             let variant = constructor.variant_for_adt(adt);
-            let def_variant = adt.variant_of_def(def);
+            let def_variant = adt.variant_of_def(cx.tcx.expect_def(pat_id));
             if variant.did == def_variant.did {
                 Some(variant.fields.iter().map(|sf| {
                     match pattern_fields.iter().find(|f| f.node.name == sf.name) {
-                        Some(ref f) => &*f.node.pat,
-                        _ => DUMMY_WILD_PAT
+                        Some(ref f) => wpat(&f.node.pat),
+                        _ => dummy_pat
                     }
                 }).collect())
             } else {
@@ -951,25 +955,32 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         }
 
         PatKind::Tuple(ref args, Some(ddpos)) => {
-            let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect();
-            pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len()));
-            pats.extend(args[ddpos..].iter().map(|p| &**p));
+            let mut pats: Vec<_> = args[..ddpos].iter().map(|p| wpat(p)).collect();
+            pats.extend(repeat(dummy_pat).take(arity - args.len()));
+            pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
             Some(pats)
         }
         PatKind::Tuple(ref args, None) =>
-            Some(args.iter().map(|p| &**p).collect()),
+            Some(args.iter().map(|p| wpat(&**p)).collect()),
 
         PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) =>
-            Some(vec![&**inner]),
+            Some(vec![wpat(&**inner)]),
 
         PatKind::Lit(ref expr) => {
-            let expr_value = eval_const_expr(cx.tcx, &expr);
-            match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
-                Some(true) => Some(vec![]),
-                Some(false) => None,
-                None => {
-                    span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
-                    None
+            if let Some(&ty::TyS { sty: ty::TyRef(_, mt), .. }) = r[col].1 {
+                // HACK: handle string literals. A string literal pattern
+                // serves both as an unary reference pattern and as a
+                // nullary value pattern, depending on the type.
+                Some(vec![(pat, Some(mt.ty))])
+            } else {
+                let expr_value = eval_const_expr(cx.tcx, &expr);
+                match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
+                    Some(true) => Some(vec![]),
+                    Some(false) => None,
+                    None => {
+                        span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
+                        None
+                    }
                 }
             }
         }
@@ -988,37 +999,45 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         }
 
         PatKind::Vec(ref before, ref slice, ref after) => {
+            let pat_len = before.len() + after.len();
             match *constructor {
-                // Fixed-length vectors.
                 Single => {
-                    let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
-                    pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len()));
-                    pats.extend(after.iter().map(|p| &**p));
-                    Some(pats)
-                },
-                Slice(length) if before.len() + after.len() <= length && slice.is_some() => {
-                    let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
-                    pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len()));
-                    pats.extend(after.iter().map(|p| &**p));
-                    Some(pats)
-                },
-                Slice(length) if before.len() + after.len() == length => {
-                    let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
-                    pats.extend(after.iter().map(|p| &**p));
-                    Some(pats)
+                    // Fixed-length vectors.
+                    Some(
+                        before.iter().map(|p| wpat(p)).chain(
+                        repeat(dummy_pat).take(arity - pat_len).chain(
+                        after.iter().map(|p| wpat(p))
+                    )).collect())
                 },
+                Slice(length) if pat_len <= length && slice.is_some() => {
+                    Some(
+                        before.iter().map(|p| wpat(p)).chain(
+                        repeat(dummy_pat).take(arity - pat_len).chain(
+                        after.iter().map(|p| wpat(p))
+                    )).collect())
+                }
+                Slice(length) if pat_len == length => {
+                    Some(
+                        before.iter().map(|p| wpat(p)).chain(
+                        after.iter().map(|p| wpat(p))
+                    ).collect())
+                }
                 SliceWithSubslice(prefix, suffix)
                     if before.len() == prefix
                         && after.len() == suffix
                         && slice.is_some() => {
-                    let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
-                    pats.extend(after.iter().map(|p| &**p));
+                    // this is used by trans::_match only
+                    let mut pats: Vec<_> = before.iter()
+                        .map(|p| (&**p, None)).collect();
+                    pats.extend(after.iter().map(|p| (&**p, None)));
                     Some(pats)
                 }
                 _ => None
             }
         }
     };
+    debug!("specialize({:?}, {:?}) = {:?}", r[col], arity, head);
+
     head.map(|mut head| {
         head.extend_from_slice(&r[..col]);
         head.extend_from_slice(&r[col + 1..]);
@@ -1076,8 +1095,8 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) {
 fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option<A> where
     F: FnOnce(&Pat) -> A,
 {
-    let pats = Matrix(vec!(vec!(pat)));
-    match is_useful(cx, &pats, &[DUMMY_WILD_PAT], ConstructWitness) {
+    let pats = Matrix(vec!(vec!(wrap_pat(cx, pat))));
+    match is_useful(cx, &pats, &[(DUMMY_WILD_PAT, None)], ConstructWitness) {
         UsefulWithWitness(pats) => Some(refutable(&pats[0])),
         NotUseful => None,
         Useful => bug!()
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 5637b44335e..7551bc5c234 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -19,7 +19,7 @@ use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::cstore::{self, InlinedItem};
 use rustc::traits;
-use rustc::hir::def::Def;
+use rustc::hir::def::{Def, PathResolution};
 use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util::def_to_path;
 use rustc::ty::{self, Ty, TyCtxt, subst};
@@ -276,11 +276,11 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      .collect()), None),
 
         hir::ExprCall(ref callee, ref args) => {
-            let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
+            let def = tcx.expect_def(callee.id);
             if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
-               entry.insert(def);
+               entry.insert(PathResolution::new(def));
             }
-            let path = match def.full_def() {
+            let path = match def {
                 Def::Struct(def_id) => def_to_path(tcx, def_id),
                 Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
                 Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat {
@@ -322,12 +322,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         hir::ExprPath(_, ref path) => {
-            let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def());
-            match opt_def {
-                Some(Def::Struct(..)) | Some(Def::Variant(..)) =>
-                    PatKind::Path(path.clone()),
-                Some(Def::Const(def_id)) |
-                Some(Def::AssociatedConst(def_id)) => {
+            match tcx.expect_def(expr.id) {
+                Def::Struct(..) | Def::Variant(..) => PatKind::Path(path.clone()),
+                Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                     let substs = Some(tcx.node_id_item_substs(expr.id).substs);
                     let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
                     return const_expr_to_pat(tcx, expr, pat_id, span);
@@ -714,21 +711,13 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
       }
       hir::ExprPath(..) => {
-          let opt_def = if let Some(def) = tcx.def_map.borrow().get(&e.id) {
-              // After type-checking, def_map contains definition of the
-              // item referred to by the path. During type-checking, it
-              // can contain the raw output of path resolution, which
-              // might be a partially resolved path.
-              // FIXME: There's probably a better way to make sure we don't
-              // panic here.
-              if def.depth != 0 {
-                  signal!(e, UnresolvedPath);
-              }
-              def.full_def()
-          } else {
-              signal!(e, NonConstPath);
-          };
-          match opt_def {
+          // This function can be used before type checking when not all paths are fully resolved.
+          // FIXME: There's probably a better way to make sure we don't panic here.
+          let resolution = tcx.expect_resolution(e.id);
+          if resolution.depth != 0 {
+              signal!(e, UnresolvedPath);
+          }
+          match resolution.base_def {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
                   let substs = if let ExprTypeChecked = ty_hint {
@@ -956,10 +945,7 @@ fn infer<'a, 'tcx>(i: ConstInt,
         (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i64 as i32)),
         (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i64)),
         (&ty::TyInt(IntTy::Is), Infer(i)) => {
-            match ConstIsize::new(i as i64, tcx.sess.target.int_type) {
-                Ok(val) => Ok(Isize(val)),
-                Err(_) => Ok(Isize(ConstIsize::Is32(i as i64 as i32))),
-            }
+            Ok(Isize(ConstIsize::new_truncating(i as i64, tcx.sess.target.int_type)))
         },
 
         (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
@@ -967,10 +953,7 @@ fn infer<'a, 'tcx>(i: ConstInt,
         (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
         (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i)),
         (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
-            match ConstIsize::new(i, tcx.sess.target.int_type) {
-                Ok(val) => Ok(Isize(val)),
-                Err(_) => Ok(Isize(ConstIsize::Is32(i as i32))),
-            }
+            Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type)))
         },
 
         (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
@@ -978,10 +961,7 @@ fn infer<'a, 'tcx>(i: ConstInt,
         (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
         (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i)),
         (&ty::TyUint(UintTy::Us), Infer(i)) => {
-            match ConstUsize::new(i, tcx.sess.target.uint_type) {
-                Ok(val) => Ok(Usize(val)),
-                Err(_) => Ok(Usize(ConstUsize::Us32(i as u32))),
-            }
+            Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type)))
         },
         (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative),
 
@@ -1063,20 +1043,14 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::
         ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i64 as i32))),
         ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))),
         ty::TyInt(ast::IntTy::Is) => {
-            match ConstIsize::new(v as i64, tcx.sess.target.int_type) {
-                Ok(val) => Ok(Integral(Isize(val))),
-                Err(_) => Ok(Integral(Isize(ConstIsize::Is32(v as i64 as i32)))),
-            }
+            Ok(Integral(Isize(ConstIsize::new_truncating(v as i64, tcx.sess.target.int_type))))
         },
         ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
         ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
         ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
         ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v))),
         ty::TyUint(ast::UintTy::Us) => {
-            match ConstUsize::new(v, tcx.sess.target.uint_type) {
-                Ok(val) => Ok(Integral(Usize(val))),
-                Err(_) => Ok(Integral(Usize(ConstUsize::Us32(v as u32)))),
-            }
+            Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
         },
         ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
             Infer(u) => Ok(Float(F64(u as f64))),
diff --git a/src/librustc_const_math/is.rs b/src/librustc_const_math/is.rs
index 4d2db355eb0..ef92b628523 100644
--- a/src/librustc_const_math/is.rs
+++ b/src/librustc_const_math/is.rs
@@ -27,7 +27,8 @@ impl ConstIsize {
             (Is16(i), ast::IntTy::I16) => i as i64,
             (Is32(i), ast::IntTy::I32) => i as i64,
             (Is64(i), ast::IntTy::I64) => i,
-            _ => panic!("got invalid isize size for target"),
+            _ => panic!("unable to convert self ({:?}) to target isize ({:?})",
+                        self, target_int_ty),
         }
     }
     pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
@@ -40,4 +41,12 @@ impl ConstIsize {
             _ => unreachable!(),
         }
     }
+    pub fn new_truncating(i: i64, target_int_ty: ast::IntTy) -> Self {
+        match target_int_ty {
+            ast::IntTy::I16 => Is16(i as i16),
+            ast::IntTy::I32 => Is32(i as i32),
+            ast::IntTy::I64 => Is64(i),
+            _ => unreachable!(),
+        }
+    }
 }
diff --git a/src/librustc_const_math/us.rs b/src/librustc_const_math/us.rs
index 2b224d06466..bf73ff03c98 100644
--- a/src/librustc_const_math/us.rs
+++ b/src/librustc_const_math/us.rs
@@ -27,7 +27,8 @@ impl ConstUsize {
             (Us16(i), ast::UintTy::U16) => i as u64,
             (Us32(i), ast::UintTy::U32) => i as u64,
             (Us64(i), ast::UintTy::U64) => i,
-            _ => panic!("got invalid usize size for target"),
+            _ => panic!("unable to convert self ({:?}) to target usize ({:?})",
+                        self, target_uint_ty),
         }
     }
     pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
@@ -40,4 +41,12 @@ impl ConstUsize {
             _ => unreachable!(),
         }
     }
+    pub fn new_truncating(i: u64, target_uint_ty: ast::UintTy) -> Self {
+        match target_uint_ty {
+            ast::UintTy::U16 => Us16(i as u16),
+            ast::UintTy::U32 => Us32(i as u32),
+            ast::UintTy::U64 => Us64(i),
+            _ => unreachable!(),
+        }
+    }
 }
diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs
index 79d3f0cf688..2c3a2e8ef6c 100644
--- a/src/librustc_data_structures/bitvec.rs
+++ b/src/librustc_data_structures/bitvec.rs
@@ -237,23 +237,9 @@ fn bitvec_iter_works() {
                [1, 10, 19, 62, 63, 64, 65, 66, 99]);
 }
 
-#[test]
-fn bitvec_iter_works_2() {
-    let mut bitvec = BitVector::new(300);
-    bitvec.insert(1);
-    bitvec.insert(10);
-    bitvec.insert(19);
-    bitvec.insert(62);
-    bitvec.insert(66);
-    bitvec.insert(99);
-    bitvec.insert(299);
-    assert_eq!(bitvec.iter().collect::<Vec<_>>(),
-               [1, 10, 19, 62, 66, 99, 299]);
-
-}
 
 #[test]
-fn bitvec_iter_works_3() {
+fn bitvec_iter_works_2() {
     let mut bitvec = BitVector::new(319);
     bitvec.insert(0);
     bitvec.insert(127);
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
new file mode 100644
index 00000000000..db054477f75
--- /dev/null
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -0,0 +1,228 @@
+// 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::iter::{self, FromIterator};
+use std::slice;
+use std::marker::PhantomData;
+use std::ops::{Index, IndexMut, Range};
+use std::fmt;
+use std::vec;
+
+use rustc_serialize as serialize;
+
+/// Represents some newtyped `usize` wrapper.
+///
+/// (purpose: avoid mixing indexes for different bitvector domains.)
+pub trait Idx: Copy + 'static {
+    fn new(usize) -> Self;
+    fn index(self) -> usize;
+}
+
+impl Idx for usize {
+    fn new(idx: usize) -> Self { idx }
+    fn index(self) -> usize { self }
+}
+
+#[derive(Clone)]
+pub struct IndexVec<I: Idx, T> {
+    pub raw: Vec<T>,
+    _marker: PhantomData<Fn(&I)>
+}
+
+impl<I: Idx, T: serialize::Encodable> serialize::Encodable for IndexVec<I, T> {
+    fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        serialize::Encodable::encode(&self.raw, s)
+    }
+}
+
+impl<I: Idx, T: serialize::Decodable> serialize::Decodable for IndexVec<I, T> {
+    fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+        serialize::Decodable::decode(d).map(|v| {
+            IndexVec { raw: v, _marker: PhantomData }
+        })
+    }
+}
+
+impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.raw, fmt)
+    }
+}
+
+pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
+
+impl<I: Idx, T> IndexVec<I, T> {
+    #[inline]
+    pub fn new() -> Self {
+        IndexVec { raw: Vec::new(), _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Self {
+        IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn from_elem<S>(elem: T, universe: &IndexVec<I, S>) -> Self
+        where T: Clone
+    {
+        IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn push(&mut self, d: T) -> I {
+        let idx = I::new(self.len());
+        self.raw.push(d);
+        idx
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.raw.len()
+    }
+
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.raw.is_empty()
+    }
+
+    #[inline]
+    pub fn into_iter(self) -> vec::IntoIter<T> {
+        self.raw.into_iter()
+    }
+
+    #[inline]
+    pub fn into_iter_enumerated(self) -> Enumerated<I, vec::IntoIter<T>>
+    {
+        self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn iter(&self) -> slice::Iter<T> {
+        self.raw.iter()
+    }
+
+    #[inline]
+    pub fn iter_enumerated(&self) -> Enumerated<I, slice::Iter<T>>
+    {
+        self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn indices(&self) -> iter::Map<Range<usize>, IntoIdx<I>> {
+        (0..self.len()).map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn iter_mut(&mut self) -> slice::IterMut<T> {
+        self.raw.iter_mut()
+    }
+
+    #[inline]
+    pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<T>>
+    {
+        self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn last(&self) -> Option<I> {
+        self.len().checked_sub(1).map(I::new)
+    }
+}
+
+impl<I: Idx, T> Index<I> for IndexVec<I, T> {
+    type Output = T;
+
+    #[inline]
+    fn index(&self, index: I) -> &T {
+        &self.raw[index.index()]
+    }
+}
+
+impl<I: Idx, T> IndexMut<I> for IndexVec<I, T> {
+    #[inline]
+    fn index_mut(&mut self, index: I) -> &mut T {
+        &mut self.raw[index.index()]
+    }
+}
+
+impl<I: Idx, T> Extend<T> for IndexVec<I, T> {
+    #[inline]
+    fn extend<J: IntoIterator<Item = T>>(&mut self, iter: J) {
+        self.raw.extend(iter);
+    }
+}
+
+impl<I: Idx, T> FromIterator<T> for IndexVec<I, T> {
+    #[inline]
+    fn from_iter<J>(iter: J) -> Self where J: IntoIterator<Item=T> {
+        IndexVec { raw: FromIterator::from_iter(iter), _marker: PhantomData }
+    }
+}
+
+impl<I: Idx, T> IntoIterator for IndexVec<I, T> {
+    type Item = T;
+    type IntoIter = vec::IntoIter<T>;
+
+    #[inline]
+    fn into_iter(self) -> vec::IntoIter<T> {
+        self.raw.into_iter()
+    }
+
+}
+
+impl<'a, I: Idx, T> IntoIterator for &'a IndexVec<I, T> {
+    type Item = &'a T;
+    type IntoIter = slice::Iter<'a, T>;
+
+    #[inline]
+    fn into_iter(self) -> slice::Iter<'a, T> {
+        self.raw.iter()
+    }
+}
+
+impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> {
+    type Item = &'a mut T;
+    type IntoIter = slice::IterMut<'a, T>;
+
+    #[inline]
+    fn into_iter(mut self) -> slice::IterMut<'a, T> {
+        self.raw.iter_mut()
+    }
+}
+
+pub struct IntoIdx<I: Idx> { _marker: PhantomData<fn(&I)> }
+impl<I: Idx, T> FnOnce<((usize, T),)> for IntoIdx<I> {
+    type Output = (I, T);
+
+    extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output {
+        (I::new(n), t)
+    }
+}
+
+impl<I: Idx, T> FnMut<((usize, T),)> for IntoIdx<I> {
+    extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output {
+        (I::new(n), t)
+    }
+}
+
+impl<I: Idx> FnOnce<(usize,)> for IntoIdx<I> {
+    type Output = I;
+
+    extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output {
+        I::new(n)
+    }
+}
+
+impl<I: Idx> FnMut<(usize,)> for IntoIdx<I> {
+    extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output {
+        I::new(n)
+    }
+}
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 00f797d1b90..9370ad016ef 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -41,6 +41,7 @@ extern crate serialize as rustc_serialize; // used by deriving
 pub mod bitvec;
 pub mod graph;
 pub mod ivar;
+pub mod indexed_vec;
 pub mod obligation_forest;
 pub mod snapshot_map;
 pub mod snapshot_vec;
diff --git a/src/librustc_data_structures/tuple_slice.rs b/src/librustc_data_structures/tuple_slice.rs
index 9a90ab8c09d..b7c71dd3664 100644
--- a/src/librustc_data_structures/tuple_slice.rs
+++ b/src/librustc_data_structures/tuple_slice.rs
@@ -46,15 +46,25 @@ impl_tuple_slice!((T, T, T, T, T, T, T, T), 8);
 
 #[test]
 fn test_sliced_tuples() {
-    let t2 = (100i32, 101i32);
-    assert_eq!(t2.as_slice(), &[100i32, 101i32]);
+    let t2 = (100, 101);
+    assert_eq!(t2.as_slice(), &[100, 101]);
 
-    let t3 = (102i32, 103i32, 104i32);
-    assert_eq!(t3.as_slice(), &[102i32, 103i32, 104i32]);
+    let t3 = (102, 103, 104);
+    assert_eq!(t3.as_slice(), &[102, 103, 104]);
 
-    let t4 = (105i32, 106i32, 107i32, 108i32);
-    assert_eq!(t4.as_slice(), &[105i32, 106i32, 107i32, 108i32]);
+    let t4 = (105, 106, 107, 108);
+    assert_eq!(t4.as_slice(), &[105, 106, 107, 108]);
+
+    let t5 = (109, 110, 111, 112, 113);
+    assert_eq!(t5.as_slice(), &[109, 110, 111, 112, 113]);
+
+    let t6 = (114, 115, 116, 117, 118, 119);
+    assert_eq!(t6.as_slice(), &[114, 115, 116, 117, 118, 119]);
+
+    let t7 = (120, 121, 122, 123, 124, 125, 126);
+    assert_eq!(t7.as_slice(), &[120, 121, 122, 123, 124, 125, 126]);
+
+    let t8 = (127, 128, 129, 130, 131, 132, 133, 134);
+    assert_eq!(t8.as_slice(), &[127, 128, 129, 130, 131, 132, 133, 134]);
 
-    let t5 = (109i32, 110i32, 111i32, 112i32, 113i32);
-    assert_eq!(t5.as_slice(), &[109i32, 110i32, 111i32, 112i32, 113i32]);
 }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index b28d203ed8d..e31a1f1624f 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -577,14 +577,13 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
     //
     // baz! should not use this definition unless foo is enabled.
 
-    let mut feature_gated_cfgs = vec![];
-    krate = time(time_passes, "configuration 1", || {
-        sess.track_errors(|| {
-            syntax::config::strip_unconfigured_items(sess.diagnostic(),
-                                                     krate,
-                                                     &mut feature_gated_cfgs)
-        })
-    })?;
+    krate = time(time_passes, "configuration", || {
+        let (krate, features) =
+            syntax::config::strip_unconfigured_items(krate, &sess.parse_sess, sess.opts.test);
+        // these need to be set "early" so that expansion sees `quote` if enabled.
+        *sess.features.borrow_mut() = features;
+        krate
+    });
 
     *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
     sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess)));
@@ -593,21 +592,11 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
         middle::recursion_limit::update_recursion_limit(sess, &krate);
     });
 
-    // these need to be set "early" so that expansion sees `quote` if enabled.
-    sess.track_errors(|| {
-        *sess.features.borrow_mut() =
-            syntax::feature_gate::get_features(&sess.parse_sess.span_diagnostic,
-                                               &krate);
-    })?;
-
     krate = time(time_passes, "crate injection", || {
-        syntax::std_inject::maybe_inject_crates_ref(krate, sess.opts.alt_std_name.clone())
+        let alt_std_name = sess.opts.alt_std_name.clone();
+        syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name)
     });
 
-    let macros = time(time_passes,
-                      "macro loading",
-                      || macro_import::read_macro_defs(sess, &cstore, &krate, crate_name));
-
     let mut addl_plugins = Some(addl_plugins);
     let registrars = time(time_passes, "plugin loading", || {
         plugin::load::load_plugins(sess,
@@ -669,12 +658,24 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
         // dependent dlls. Note that this uses cfg!(windows) as opposed to
         // targ_cfg because syntax extensions are always loaded for the host
         // compiler, not for the target.
-        let mut _old_path = OsString::new();
+        //
+        // This is somewhat of an inherently racy operation, however, as
+        // multiple threads calling this function could possibly continue
+        // extending PATH far beyond what it should. To solve this for now we
+        // just don't add any new elements to PATH which are already there
+        // within PATH. This is basically a targeted fix at #17360 for rustdoc
+        // which runs rustc in parallel but has been seen (#33844) to cause
+        // problems with PATH becoming too long.
+        let mut old_path = OsString::new();
         if cfg!(windows) {
-            _old_path = env::var_os("PATH").unwrap_or(_old_path);
+            old_path = env::var_os("PATH").unwrap_or(old_path);
             let mut new_path = sess.host_filesearch(PathKind::All)
                                    .get_dylib_search_paths();
-            new_path.extend(env::split_paths(&_old_path));
+            for path in env::split_paths(&old_path) {
+                if !new_path.contains(&path) {
+                    new_path.push(path);
+                }
+            }
             env::set_var("PATH", &env::join_paths(new_path).unwrap());
         }
         let features = sess.features.borrow();
@@ -683,36 +684,24 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
             features: Some(&features),
             recursion_limit: sess.recursion_limit.get(),
             trace_mac: sess.opts.debugging_opts.trace_macros,
+            should_test: sess.opts.test,
         };
+        let mut loader = macro_import::MacroLoader::new(sess, &cstore, crate_name);
         let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess,
                                                       krate.config.clone(),
                                                       cfg,
-                                                      &mut feature_gated_cfgs);
+                                                      &mut loader);
         syntax_ext::register_builtins(&mut ecx.syntax_env);
         let (ret, macro_names) = syntax::ext::expand::expand_crate(ecx,
-                                                                   macros,
                                                                    syntax_exts,
                                                                    krate);
         if cfg!(windows) {
-            env::set_var("PATH", &_old_path);
+            env::set_var("PATH", &old_path);
         }
         *sess.available_macros.borrow_mut() = macro_names;
         ret
     });
 
-    krate = sess.track_errors(|| {
-        time(time_passes, "gated configuration checking", || {
-            let features = sess.features.borrow();
-            feature_gated_cfgs.sort();
-            feature_gated_cfgs.dedup();
-            for cfg in &feature_gated_cfgs {
-                cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap());
-            }
-        });
-
-        krate
-    })?;
-
     krate = time(time_passes, "maybe building test harness", || {
         syntax::test::modify_for_testing(&sess.parse_sess,
                                          sess.opts.test,
@@ -720,10 +709,6 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
                                          sess.diagnostic())
     });
 
-    krate = time(time_passes,
-                 "prelude injection",
-                 || syntax::std_inject::maybe_inject_prelude(&sess.parse_sess, krate));
-
     time(time_passes,
          "checking for inline asm in case the target doesn't support it",
          || no_asm::check_crate(sess, &krate));
@@ -731,12 +716,11 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
     // Needs to go *after* expansion to be able to check the results of macro expansion.
     time(time_passes, "complete gated feature checking", || {
         sess.track_errors(|| {
-            let features = syntax::feature_gate::check_crate(sess.codemap(),
-                                                             &sess.parse_sess.span_diagnostic,
-                                                             &krate,
-                                                             &attributes,
-                                                             sess.opts.unstable_features);
-            *sess.features.borrow_mut() = features;
+            syntax::feature_gate::check_crate(&krate,
+                                              &sess.parse_sess,
+                                              &sess.features.borrow(),
+                                              &attributes,
+                                              sess.opts.unstable_features);
         })
     })?;
 
@@ -964,11 +948,13 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
         time(time_passes, "MIR passes", || {
             let mut passes = sess.mir_passes.borrow_mut();
             // Push all the built-in passes.
-            passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
+            passes.push_hook(box mir::transform::dump_mir::DumpMir);
+            passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("initial"));
             passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
             passes.push_pass(box mir::transform::type_check::TypeckMir);
-            passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg);
-            passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
+            passes.push_pass(
+                box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
+            passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("qualify-consts"));
             // And run everything.
             passes.run_passes(tcx, &mut mir_map);
         });
@@ -1034,15 +1020,20 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // to LLVM code.
     time(time_passes, "Prepare MIR codegen passes", || {
         let mut passes = ::rustc::mir::transform::Passes::new();
+        passes.push_hook(box mir::transform::dump_mir::DumpMir);
         passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
-        passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
+        passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads"));
+
         passes.push_pass(box mir::transform::erase_regions::EraseRegions);
+
         passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
         passes.push_pass(box borrowck::ElaborateDrops);
         passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
-        passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg);
+        passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops"));
+
         passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
-        passes.push_pass(box mir::transform::dump_mir::DumpMir("pre_trans"));
+        passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans"));
+
         passes.run_passes(tcx, &mut mir_map);
     });
 
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 4c4dea406ba..54e5824cbc7 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -276,7 +276,7 @@ impl LateLintPass for NonSnakeCase {
     fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
         if let &PatKind::Binding(_, ref path1, _) = &p.node {
             // Exclude parameter names from foreign functions (they have no `Def`)
-            if cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()).is_some() {
+            if cx.tcx.expect_def_or_none(p.id).is_some() {
                 self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
             }
         }
@@ -362,8 +362,7 @@ impl LateLintPass for NonUpperCaseGlobals {
         // Lint for constants that look like binding identifiers (#7526)
         if let PatKind::Path(ref path) = p.node {
             if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
-                if let Some(Def::Const(..)) = cx.tcx.def_map.borrow().get(&p.id)
-                                                                     .map(|d| d.full_def()) {
+                if let Def::Const(..) = cx.tcx.expect_def(p.id) {
                     NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
                                                           path.segments[0].name, path.span);
                 }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3005f564ff4..3ceca9218bd 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -157,22 +157,13 @@ impl LintPass for NonShorthandFieldPatterns {
 
 impl LateLintPass for NonShorthandFieldPatterns {
     fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
-        let def_map = cx.tcx.def_map.borrow();
-        if let PatKind::Struct(_, ref v, _) = pat.node {
-            let field_pats = v.iter().filter(|fieldpat| {
+        if let PatKind::Struct(_, ref field_pats, _) = pat.node {
+            for fieldpat in field_pats {
                 if fieldpat.node.is_shorthand {
-                    return false;
-                }
-                let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def());
-                if let Some(def_id) = cx.tcx.map.opt_local_def_id(fieldpat.node.pat.id) {
-                    def == Some(Def::Local(def_id, fieldpat.node.pat.id))
-                } else {
-                    false
+                    continue;
                 }
-            });
-            for fieldpat in field_pats {
                 if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node {
-                    if ident.node.unhygienize() == fieldpat.node.name {
+                    if ident.node == fieldpat.node.name {
                         cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span,
                                      &format!("the `{}:` in this pattern is redundant and can \
                                               be removed", ident.node))
@@ -377,7 +368,7 @@ impl LateLintPass for MissingDoc {
             hir::ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) => {
                 // If the trait is private, add the impl items to private_traits so they don't get
                 // reported for missing docs.
-                let real_trait = cx.tcx.trait_ref_to_def_id(trait_ref);
+                let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
                 if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) {
                     match cx.tcx.map.find(node_id) {
                         Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
@@ -780,11 +771,9 @@ impl LateLintPass for UnconditionalRecursion {
                                   id: ast::NodeId) -> bool {
             match tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
-                    tcx.def_map
-                       .borrow()
-                       .get(&callee.id)
-                       .map_or(false,
-                               |def| def.def_id() == tcx.map.local_def_id(fn_id))
+                    tcx.expect_def_or_none(callee.id).map_or(false, |def| {
+                        def.def_id() == tcx.map.local_def_id(fn_id)
+                    })
                 }
                 _ => false
             }
@@ -820,7 +809,9 @@ impl LateLintPass for UnconditionalRecursion {
             // Check for calls to methods via explicit paths (e.g. `T::method()`).
             match tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
-                    match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) {
+                    // The callee is an arbitrary expression,
+                    // it doesn't necessarily have a definition.
+                    match tcx.expect_def_or_none(callee.id) {
                         Some(Def::Method(def_id)) => {
                             let item_substs = tcx.node_id_item_substs(callee.id);
                             method_call_refers_to_method(
@@ -1057,7 +1048,7 @@ impl LateLintPass for MutableTransmutes {
                 hir::ExprPath(..) => (),
                 _ => return None
             }
-            if let Def::Fn(did) = cx.tcx.resolve_expr(expr) {
+            if let Def::Fn(did) = cx.tcx.expect_def(expr.id) {
                 if !def_id_is_transmute(cx, did) {
                     return None;
                 }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 892924db6fa..b7f14fffafb 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -16,6 +16,7 @@ use rustc::ty::{self, Ty, TyCtxt};
 use middle::const_val::ConstVal;
 use rustc_const_eval::eval_const_expr_partial;
 use rustc_const_eval::EvalHint::ExprTypeChecked;
+use util::common::slice_pat;
 use util::nodemap::{FnvHashSet};
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
@@ -459,8 +460,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 // Check for a repr() attribute to specify the size of the
                 // discriminant.
                 let repr_hints = cx.lookup_repr_hints(def.did);
-                match &**repr_hints {
-                    [] => {
+                match slice_pat(&&**repr_hints) {
+                    &[] => {
                         // Special-case types like `Option<extern fn()>`.
                         if !is_repr_nullable_ptr(cx, def, substs) {
                             return FfiUnsafe(
@@ -470,7 +471,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                                  the type")
                         }
                     }
-                    [ref hint] => {
+                    &[ref hint] => {
                         if !hint.is_ffi_safe() {
                             // FIXME: This shouldn't be reachable: we should check
                             // this earlier.
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index ea0d8eae75d..e757201c886 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -54,6 +54,7 @@ pub use self::DiagnosticSeverity::*;
 pub use self::Linkage::*;
 pub use self::DLLStorageClassTypes::*;
 
+use std::str::FromStr;
 use std::ffi::{CString, CStr};
 use std::cell::RefCell;
 use std::slice;
@@ -426,6 +427,20 @@ pub enum ArchiveKind {
     K_COFF,
 }
 
+impl FromStr for ArchiveKind {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "gnu" => Ok(ArchiveKind::K_GNU),
+            "mips64" => Ok(ArchiveKind::K_MIPS64),
+            "bsd" => Ok(ArchiveKind::K_BSD),
+            "coff" => Ok(ArchiveKind::K_COFF),
+            _ => Err(()),
+        }
+    }
+}
+
 /// Represents the different LLVM passes Rust supports
 #[derive(Copy, Clone, PartialEq, Debug)]
 #[repr(C)]
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index ad0e8e1c376..78825aca418 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -719,7 +719,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
 
     debug!("Encoding side tables for id {}", id);
 
-    if let Some(def) = tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
+    if let Some(def) = tcx.expect_def_or_none(id) {
         rbml_w.tag(c::tag_table_def, |rbml_w| {
             rbml_w.id(id);
             def.encode(rbml_w).unwrap();
@@ -1133,10 +1133,7 @@ fn decode_side_tables(dcx: &DecodeContext,
                 match value {
                     c::tag_table_def => {
                         let def = decode_def(dcx, val_dsr);
-                        dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution {
-                            base_def: def,
-                            depth: 0
-                        });
+                        dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def));
                     }
                     c::tag_table_node_type => {
                         let ty = val_dsr.read_ty(dcx);
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 2025045cc8f..6c24384cddc 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -929,29 +929,26 @@ impl<'a> LocalCrateReader<'a> {
                     return;
                 }
 
-                match self.creader.extract_crate_info(i) {
-                    Some(info) => {
-                        let (cnum, _, _) = self.creader.resolve_crate(&None,
-                                                                      &info.ident,
-                                                                      &info.name,
-                                                                      None,
-                                                                      i.span,
-                                                                      PathKind::Crate,
-                                                                      true);
-
-                        let def_id = self.definitions.opt_local_def_id(i.id).unwrap();
-                        let len = self.definitions.def_path(def_id.index).data.len();
-
-                        self.creader.update_extern_crate(cnum,
-                                                         ExternCrate {
-                                                             def_id: def_id,
-                                                             span: i.span,
-                                                             direct: true,
-                                                             path_len: len,
-                                                         });
-                        self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
-                    }
-                    None => ()
+                if let Some(info) = self.creader.extract_crate_info(i) {
+                    let (cnum, _, _) = self.creader.resolve_crate(&None,
+                                                                  &info.ident,
+                                                                  &info.name,
+                                                                  None,
+                                                                  i.span,
+                                                                  PathKind::Crate,
+                                                                  true);
+
+                    let def_id = self.definitions.opt_local_def_id(i.id).unwrap();
+                    let len = self.definitions.def_path(def_id.index).data.len();
+
+                    self.creader.update_extern_crate(cnum,
+                                                     ExternCrate {
+                                                         def_id: def_id,
+                                                         span: i.span,
+                                                         direct: true,
+                                                         path_len: len,
+                                                     });
+                    self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
                 }
             }
             ast::ItemKind::ForeignMod(ref fm) => self.process_foreign_mod(i, fm),
@@ -1081,6 +1078,7 @@ pub fn import_codemap(local_codemap: &codemap::CodeMap,
                 // containing the information we need.
                 let codemap::FileMap {
                     name,
+                    abs_path,
                     start_pos,
                     end_pos,
                     lines,
@@ -1105,6 +1103,7 @@ pub fn import_codemap(local_codemap: &codemap::CodeMap,
                 }
 
                 let local_version = local_codemap.new_imported_filemap(name,
+                                                                       abs_path,
                                                                        source_length,
                                                                        lines,
                                                                        multibyte_chars);
diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs
index 911ca7e315c..1c7d37709c2 100644
--- a/src/librustc_metadata/macro_import.rs
+++ b/src/librustc_metadata/macro_import.rs
@@ -20,24 +20,19 @@ use syntax::codemap::Span;
 use syntax::parse::token;
 use syntax::ast;
 use syntax::attr;
-use syntax::visit;
-use syntax::visit::Visitor;
 use syntax::attr::AttrMetaMethods;
+use syntax::ext;
 
-struct MacroLoader<'a> {
+pub struct MacroLoader<'a> {
     sess: &'a Session,
-    span_whitelist: HashSet<Span>,
     reader: CrateReader<'a>,
-    macros: Vec<ast::MacroDef>,
 }
 
 impl<'a> MacroLoader<'a> {
-    fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> {
+    pub fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> {
         MacroLoader {
             sess: sess,
-            span_whitelist: HashSet::new(),
             reader: CrateReader::new(sess, cstore, crate_name),
-            macros: vec![],
         }
     }
 }
@@ -46,48 +41,15 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) {
     span_err!(a, b, E0467, "bad macro reexport");
 }
 
-/// Read exported macros.
-pub fn read_macro_defs(sess: &Session,
-                       cstore: &CStore,
-                       krate: &ast::Crate,
-                       crate_name: &str)
-                       -> Vec<ast::MacroDef>
-{
-    let mut loader = MacroLoader::new(sess, cstore, crate_name);
-
-    // We need to error on `#[macro_use] extern crate` when it isn't at the
-    // crate root, because `$crate` won't work properly. Identify these by
-    // spans, because the crate map isn't set up yet.
-    for item in &krate.module.items {
-        if let ast::ItemKind::ExternCrate(_) = item.node {
-            loader.span_whitelist.insert(item.span);
-        }
-    }
-
-    visit::walk_crate(&mut loader, krate);
-
-    loader.macros
-}
-
 pub type MacroSelection = HashMap<token::InternedString, Span>;
 
-// note that macros aren't expanded yet, and therefore macros can't add macro imports.
-impl<'a, 'v> Visitor<'v> for MacroLoader<'a> {
-    fn visit_item(&mut self, item: &ast::Item) {
-        // We're only interested in `extern crate`.
-        match item.node {
-            ast::ItemKind::ExternCrate(_) => {}
-            _ => {
-                visit::walk_item(self, item);
-                return;
-            }
-        }
-
+impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
+    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef> {
         // Parse the attributes relating to macros.
         let mut import = Some(HashMap::new());  // None => load all
         let mut reexport = HashMap::new();
 
-        for attr in &item.attrs {
+        for attr in &extern_crate.attrs {
             let mut used = true;
             match &attr.name()[..] {
                 "macro_use" => {
@@ -130,36 +92,33 @@ impl<'a, 'v> Visitor<'v> for MacroLoader<'a> {
             }
         }
 
-        self.load_macros(item, import, reexport)
-    }
-
-    fn visit_mac(&mut self, _: &ast::Mac) {
-        // bummer... can't see macro imports inside macros.
-        // do nothing.
+        self.load_macros(extern_crate, allows_macros, import, reexport)
     }
 }
 
 impl<'a> MacroLoader<'a> {
     fn load_macros<'b>(&mut self,
                        vi: &ast::Item,
+                       allows_macros: bool,
                        import: Option<MacroSelection>,
-                       reexport: MacroSelection) {
+                       reexport: MacroSelection)
+                       -> Vec<ast::MacroDef> {
         if let Some(sel) = import.as_ref() {
             if sel.is_empty() && reexport.is_empty() {
-                return;
+                return Vec::new();
             }
         }
 
-        if !self.span_whitelist.contains(&vi.span) {
+        if !allows_macros {
             span_err!(self.sess, vi.span, E0468,
                       "an `extern crate` loading macros must be at the crate root");
-            return;
+            return Vec::new();
         }
 
-        let macros = self.reader.read_exported_macros(vi);
+        let mut macros = Vec::new();
         let mut seen = HashSet::new();
 
-        for mut def in macros {
+        for mut def in self.reader.read_exported_macros(vi) {
             let name = def.ident.name.as_str();
 
             def.use_locally = match import.as_ref() {
@@ -170,7 +129,7 @@ impl<'a> MacroLoader<'a> {
             def.allow_internal_unstable = attr::contains_name(&def.attrs,
                                                               "allow_internal_unstable");
             debug!("load_macros: loaded: {:?}", def);
-            self.macros.push(def);
+            macros.push(def);
             seen.insert(name);
         }
 
@@ -189,5 +148,7 @@ impl<'a> MacroLoader<'a> {
                           "reexported macro not found");
             }
         }
+
+        macros
     }
 }
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index 797af8964a1..d96996a0179 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -221,12 +221,9 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 assert_eq!(self.next(), '|');
                 ty::ReScope(scope)
             }
-            't' => {
-                ty::ReStatic
-            }
-            'e' => {
-                ty::ReStatic
-            }
+            't' => ty::ReStatic,
+            'e' => ty::ReEmpty,
+            'E' => ty::ReErased,
             _ => bug!("parse_region: bad input")
         }
     }
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index 87a2e50bb25..48811c68f58 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -283,6 +283,9 @@ pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: ty::Region) {
         ty::ReEmpty => {
             write!(w, "e");
         }
+        ty::ReErased => {
+            write!(w, "E");
+        }
         ty::ReVar(_) | ty::ReSkolemized(..) => {
             // these should not crop up after typeck
             bug!("cannot encode region variables");
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index c1626b93f0c..7e650c5bd3d 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -22,7 +22,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                      ast_block: &'tcx hir::Block)
                      -> BlockAnd<()> {
         let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
-        self.in_scope(extent, block, move |this, _| {
+        self.in_scope(extent, block, move |this| {
             // This convoluted structure is to avoid using recursion as we walk down a list
             // of statements. Basically, the structure we get back is something like:
             //
@@ -40,27 +40,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             //
             // First we build all the statements in the block.
             let mut let_extent_stack = Vec::with_capacity(8);
+            let outer_visibility_scope = this.visibility_scope;
             for stmt in stmts {
                 let Stmt { span: _, kind } = this.hir.mirror(stmt);
                 match kind {
                     StmtKind::Expr { scope, expr } => {
-                        unpack!(block = this.in_scope(scope, block, |this, _| {
+                        unpack!(block = this.in_scope(scope, block, |this| {
                             let expr = this.hir.mirror(expr);
                             this.stmt_expr(block, expr)
                         }));
                     }
                     StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
-                        let remainder_scope_id = this.push_scope(remainder_scope, block);
+                        let tcx = this.hir.tcx();
+
+                        // Enter the remainder scope, i.e. the bindings' destruction scope.
+                        this.push_scope(remainder_scope, block);
                         let_extent_stack.push(remainder_scope);
-                        unpack!(block = this.in_scope(init_scope, block, move |this, _| {
-                            // FIXME #30046                              ^~~~
-                            if let Some(init) = initializer {
-                                this.expr_into_pattern(block, remainder_scope_id, pattern, init)
-                            } else {
-                                this.declare_bindings(remainder_scope_id, &pattern);
-                                block.unit()
-                            }
-                        }));
+
+                        // Declare the bindings, which may create a visibility scope.
+                        let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.map);
+                        let remainder_span = remainder_span.unwrap_or(span);
+                        let scope = this.declare_bindings(None, remainder_span, &pattern);
+
+                        // Evaluate the initializer, if present.
+                        if let Some(init) = initializer {
+                            unpack!(block = this.in_scope(init_scope, block, move |this| {
+                                // FIXME #30046                              ^~~~
+                                this.expr_into_pattern(block, pattern, init)
+                            }));
+                        }
+
+                        // Enter the visibility scope, after evaluating the initializer.
+                        if let Some(visibility_scope) = scope {
+                            this.visibility_scope = visibility_scope;
+                        }
                     }
                 }
             }
@@ -70,14 +83,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 unpack!(block = this.into(destination, block, expr));
             } else if dest_is_unit {
                 // FIXME(#31472)
-                let scope_id = this.innermost_scope_id();
-                this.cfg.push_assign_unit(block, scope_id, span, destination);
+                let source_info = this.source_info(span);
+                this.cfg.push_assign_unit(block, source_info, destination);
             }
             // Finally, we pop all the let scopes before exiting out from the scope of block
             // itself.
             for extent in let_extent_stack.into_iter().rev() {
                 unpack!(block = this.pop_scope(extent, block));
             }
+            // Restore the original visibility scope.
+            this.visibility_scope = outer_visibility_scope;
             block.unit()
         })
     }
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 4859257f291..83f8c3b42c8 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -15,21 +15,18 @@
 
 use build::{CFG, Location};
 use rustc::mir::repr::*;
-use syntax::codemap::Span;
 
 impl<'tcx> CFG<'tcx> {
     pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
-        &self.basic_blocks[blk.index()]
+        &self.basic_blocks[blk]
     }
 
     pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
-        &mut self.basic_blocks[blk.index()]
+        &mut self.basic_blocks[blk]
     }
 
     pub fn start_new_block(&mut self) -> BasicBlock {
-        let node_index = self.basic_blocks.len();
-        self.basic_blocks.push(BasicBlockData::new(None));
-        BasicBlock::new(node_index)
+        self.basic_blocks.push(BasicBlockData::new(None))
     }
 
     pub fn start_new_cleanup_block(&mut self) -> BasicBlock {
@@ -50,47 +47,44 @@ impl<'tcx> CFG<'tcx> {
 
     pub fn push_assign(&mut self,
                        block: BasicBlock,
-                       scope: ScopeId,
-                       span: Span,
+                       source_info: SourceInfo,
                        lvalue: &Lvalue<'tcx>,
                        rvalue: Rvalue<'tcx>) {
         self.push(block, Statement {
-            scope: scope,
-            span: span,
+            source_info: source_info,
             kind: StatementKind::Assign(lvalue.clone(), rvalue)
         });
     }
 
     pub fn push_assign_constant(&mut self,
                                 block: BasicBlock,
-                                scope: ScopeId,
-                                span: Span,
+                                source_info: SourceInfo,
                                 temp: &Lvalue<'tcx>,
                                 constant: Constant<'tcx>) {
-        self.push_assign(block, scope, span, temp,
+        self.push_assign(block, source_info, temp,
                          Rvalue::Use(Operand::Constant(constant)));
     }
 
     pub fn push_assign_unit(&mut self,
                             block: BasicBlock,
-                            scope: ScopeId,
-                            span: Span,
+                            source_info: SourceInfo,
                             lvalue: &Lvalue<'tcx>) {
-        self.push_assign(block, scope, span, lvalue, Rvalue::Aggregate(
+        self.push_assign(block, source_info, lvalue, Rvalue::Aggregate(
             AggregateKind::Tuple, vec![]
         ));
     }
 
     pub fn terminate(&mut self,
                      block: BasicBlock,
-                     scope: ScopeId,
-                     span: Span,
+                     source_info: SourceInfo,
                      kind: TerminatorKind<'tcx>) {
+        debug!("terminating block {:?} <- {:?}", block, kind);
         debug_assert!(self.block_data(block).terminator.is_none(),
-                      "terminate: block {:?} already has a terminator set", block);
+                      "terminate: block {:?}={:?} already has a terminator set",
+                      block,
+                      self.block_data(block));
         self.block_data_mut(block).terminator = Some(Terminator {
-            span: span,
-            scope: scope,
+            source_info: source_info,
             kind: kind,
         });
     }
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index bb5aca2d8d7..dd6c9c02f56 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -15,6 +15,8 @@ use build::expr::category::Category;
 use hair::*;
 use rustc::mir::repr::*;
 
+use rustc_data_structures::indexed_vec::Idx;
+
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, yielding an lvalue that we can move from etc.
     pub fn as_lvalue<M>(&mut self,
@@ -34,11 +36,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr);
 
         let this = self;
-        let scope_id = this.innermost_scope_id();
         let expr_span = expr.span;
+        let source_info = this.source_info(expr_span);
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this, _| this.as_lvalue(block, value))
+                this.in_scope(extent, block, |this| this.as_lvalue(block, value))
             }
             ExprKind::Field { lhs, name } => {
                 let lvalue = unpack!(block = this.as_lvalue(block, lhs));
@@ -59,9 +61,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 // bounds check:
                 let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
-                this.cfg.push_assign(block, scope_id, expr_span, // len = len(slice)
+                this.cfg.push_assign(block, source_info, // len = len(slice)
                                      &len, Rvalue::Len(slice.clone()));
-                this.cfg.push_assign(block, scope_id, expr_span, // lt = idx < len
+                this.cfg.push_assign(block, source_info, // lt = idx < len
                                      &lt, Rvalue::BinaryOp(BinOp::Lt,
                                                            idx.clone(),
                                                            Operand::Consume(len.clone())));
@@ -75,7 +77,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 success.and(slice.index(idx))
             }
             ExprKind::SelfRef => {
-                block.and(Lvalue::Arg(0))
+                block.and(Lvalue::Arg(Arg::new(0)))
             }
             ExprKind::VarRef { id } => {
                 let index = this.var_indices[&id];
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index a059f2bdde9..beb9ca256ab 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -35,7 +35,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let this = self;
 
         if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this, _| this.as_operand(block, value));
+            return this.in_scope(extent, block, |this| this.as_operand(block, value));
         }
 
         let category = Category::of(&expr.kind).unwrap();
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 67cf5473f79..ab7bc4eec91 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -14,6 +14,7 @@ use std;
 
 use rustc_const_math::{ConstMathErr, Op};
 use rustc_data_structures::fnv::FnvHashMap;
+use rustc_data_structures::indexed_vec::Idx;
 
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::{Category, RvalueFunc};
@@ -41,12 +42,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
 
         let this = self;
-        let scope_id = this.innermost_scope_id();
         let expr_span = expr.span;
+        let source_info = this.source_info(expr_span);
 
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this, _| this.as_rvalue(block, value))
+                this.in_scope(extent, block, |this| this.as_rvalue(block, value))
             }
             ExprKind::InlineAsm { asm, outputs, inputs } => {
                 let outputs = outputs.into_iter().map(|output| {
@@ -86,7 +87,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let minval = this.minval_literal(expr_span, expr.ty);
                     let is_min = this.temp(bool_ty);
 
-                    this.cfg.push_assign(block, scope_id, expr_span, &is_min,
+                    this.cfg.push_assign(block, source_info, &is_min,
                                          Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
 
                     let err = ConstMathErr::Overflow(Op::Neg);
@@ -99,8 +100,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let value = this.hir.mirror(value);
                 let result = this.temp(expr.ty);
                 // to start, malloc some memory of suitable type (thus far, uninitialized):
-                this.cfg.push_assign(block, scope_id, expr_span, &result, Rvalue::Box(value.ty));
-                this.in_scope(value_extents, block, |this, _| {
+                this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty));
+                this.in_scope(value_extents, block, |this| {
                     // schedule a shallow free of that memory, lest we unwind:
                     this.schedule_box_free(expr_span, value_extents, &result, value.ty);
                     // initialize the box contents:
@@ -245,13 +246,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn build_binary_op(&mut self, mut block: BasicBlock,
                            op: BinOp, span: Span, ty: ty::Ty<'tcx>,
                            lhs: Operand<'tcx>, rhs: Operand<'tcx>) -> BlockAnd<Rvalue<'tcx>> {
-        let scope_id = self.innermost_scope_id();
+        let source_info = self.source_info(span);
         let bool_ty = self.hir.bool_ty();
         if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
             let result_tup = self.hir.tcx().mk_tup(vec![ty, bool_ty]);
             let result_value = self.temp(result_tup);
 
-            self.cfg.push_assign(block, scope_id, span,
+            self.cfg.push_assign(block, source_info,
                                  &result_value, Rvalue::CheckedBinaryOp(op,
                                                                         lhs,
                                                                         rhs));
@@ -292,7 +293,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // Check for / 0
                 let is_zero = self.temp(bool_ty);
                 let zero = self.zero_literal(span, ty);
-                self.cfg.push_assign(block, scope_id, span, &is_zero,
+                self.cfg.push_assign(block, source_info, &is_zero,
                                      Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero));
 
                 block = self.assert(block, Operand::Consume(is_zero), false,
@@ -310,14 +311,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                     // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
 
-                    self.cfg.push_assign(block, scope_id, span, &is_neg_1,
+                    self.cfg.push_assign(block, source_info, &is_neg_1,
                                          Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), neg_1));
-                    self.cfg.push_assign(block, scope_id, span, &is_min,
+                    self.cfg.push_assign(block, source_info, &is_min,
                                          Rvalue::BinaryOp(BinOp::Eq, lhs.clone(), min));
 
                     let is_neg_1 = Operand::Consume(is_neg_1);
                     let is_min = Operand::Consume(is_min);
-                    self.cfg.push_assign(block, scope_id, span, &of,
+                    self.cfg.push_assign(block, source_info, &of,
                                          Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
 
                     block = self.assert(block, Operand::Consume(of), false,
@@ -367,6 +368,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     ast::IntTy::Is => {
                         let int_ty = self.hir.tcx().sess.target.int_type;
                         let min = match int_ty {
+                            ast::IntTy::I16 => std::i16::MIN as i64,
                             ast::IntTy::I32 => std::i32::MIN as i64,
                             ast::IntTy::I64 => std::i64::MIN,
                             _ => unreachable!()
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index f33d3dd5190..da128b8dd56 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -30,7 +30,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let this = self;
 
         if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this, _| this.as_temp(block, value));
+            return this.in_scope(extent, block, |this| this.as_temp(block, value));
         }
 
         let expr_ty = expr.ty.clone();
@@ -49,8 +49,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             Category::Lvalue => {
                 let lvalue = unpack!(block = this.as_lvalue(block, expr));
                 let rvalue = Rvalue::Use(Operand::Consume(lvalue));
-                let scope_id = this.innermost_scope_id();
-                this.cfg.push_assign(block, scope_id, expr_span, &temp, rvalue);
+                let source_info = this.source_info(expr_span);
+                this.cfg.push_assign(block, source_info, &temp, rvalue);
             }
             _ => {
                 unpack!(block = this.into(&temp, block, expr));
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 41610c90377..fd9ddc05ab5 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -33,11 +33,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // just use the name `this` uniformly
         let this = self;
         let expr_span = expr.span;
-        let scope_id = this.innermost_scope_id();
+        let source_info = this.source_info(expr_span);
 
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this, _| this.into(destination, block, value))
+                this.in_scope(extent, block, |this| this.into(destination, block, value))
             }
             ExprKind::Block { body: ast_block } => {
                 this.ast_block(destination, expr.ty.is_nil(), block, ast_block)
@@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 let mut then_block = this.cfg.start_new_block();
                 let mut else_block = this.cfg.start_new_block();
-                this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::If {
+                this.cfg.terminate(block, source_info, TerminatorKind::If {
                     cond: operand,
                     targets: (then_block, else_block)
                 });
@@ -61,19 +61,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 } else {
                     // Body of the `if` expression without an `else` clause must return `()`, thus
                     // we implicitly generate a `else {}` if it is not specified.
-                    let scope_id = this.innermost_scope_id();
-                    this.cfg.push_assign_unit(else_block, scope_id, expr_span, destination);
+                    this.cfg.push_assign_unit(else_block, source_info, destination);
                     else_block
                 };
 
                 let join_block = this.cfg.start_new_block();
-                this.cfg.terminate(then_block,
-                                   scope_id,
-                                   expr_span,
+                this.cfg.terminate(then_block, source_info,
                                    TerminatorKind::Goto { target: join_block });
-                this.cfg.terminate(else_block,
-                                   scope_id,
-                                   expr_span,
+                this.cfg.terminate(else_block, source_info,
                                    TerminatorKind::Goto { target: join_block });
 
                 join_block.unit()
@@ -100,19 +95,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     LogicalOp::And => (else_block, false_block),
                     LogicalOp::Or => (true_block, else_block),
                 };
-                this.cfg.terminate(block,
-                                   scope_id,
-                                   expr_span,
+                this.cfg.terminate(block, source_info,
                                    TerminatorKind::If { cond: lhs, targets: blocks });
 
                 let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
-                this.cfg.terminate(else_block, scope_id, expr_span, TerminatorKind::If {
+                this.cfg.terminate(else_block, source_info, TerminatorKind::If {
                     cond: rhs,
                     targets: (true_block, false_block)
                 });
 
                 this.cfg.push_assign_constant(
-                    true_block, scope_id, expr_span, destination,
+                    true_block, source_info, destination,
                     Constant {
                         span: expr_span,
                         ty: this.hir.bool_ty(),
@@ -120,20 +113,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     });
 
                 this.cfg.push_assign_constant(
-                    false_block, scope_id, expr_span, destination,
+                    false_block, source_info, destination,
                     Constant {
                         span: expr_span,
                         ty: this.hir.bool_ty(),
                         literal: this.hir.false_literal(),
                     });
 
-                this.cfg.terminate(true_block,
-                                   scope_id,
-                                   expr_span,
+                this.cfg.terminate(true_block, source_info,
                                    TerminatorKind::Goto { target: join_block });
-                this.cfg.terminate(false_block,
-                                   scope_id,
-                                   expr_span,
+                this.cfg.terminate(false_block, source_info,
                                    TerminatorKind::Goto { target: join_block });
 
                 join_block.unit()
@@ -158,9 +147,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let exit_block = this.cfg.start_new_block();
 
                 // start the loop
-                this.cfg.terminate(block,
-                                   scope_id,
-                                   expr_span,
+                this.cfg.terminate(block, source_info,
                                    TerminatorKind::Goto { target: loop_block });
 
                 let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
@@ -173,9 +160,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         let loop_block_end;
                         let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
                         body_block = this.cfg.start_new_block();
-                        this.cfg.terminate(loop_block_end,
-                                           scope_id,
-                                           expr_span,
+                        this.cfg.terminate(loop_block_end, source_info,
                                            TerminatorKind::If {
                                                cond: cond,
                                                targets: (body_block, exit_block)
@@ -192,15 +177,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let tmp = this.get_unit_temp();
                     // Execute the body, branching back to the test.
                     let body_block_end = unpack!(this.into(&tmp, body_block, body));
-                    this.cfg.terminate(body_block_end,
-                                       scope_id,
-                                       expr_span,
+                    this.cfg.terminate(body_block_end, source_info,
                                        TerminatorKind::Goto { target: loop_block });
                 });
                 // If the loop may reach its exit_block, we assign an empty tuple to the
                 // destination to keep the MIR well-formed.
                 if might_break {
-                    this.cfg.push_assign_unit(exit_block, scope_id, expr_span, destination);
+                    this.cfg.push_assign_unit(exit_block, source_info, destination);
                 }
                 exit_block.unit()
             }
@@ -219,7 +202,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 let success = this.cfg.start_new_block();
                 let cleanup = this.diverge_cleanup();
-                this.cfg.terminate(block, scope_id, expr_span, TerminatorKind::Call {
+                this.cfg.terminate(block, source_info, TerminatorKind::Call {
                     func: fun,
                     args: args,
                     cleanup: cleanup,
@@ -269,7 +252,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 });
 
                 let rvalue = unpack!(block = this.as_rvalue(block, expr));
-                this.cfg.push_assign(block, scope_id, expr_span, destination, rvalue);
+                this.cfg.push_assign(block, source_info, destination, rvalue);
                 block.unit()
             }
         }
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index 24369aaff3f..ad55a3d8b73 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -20,18 +20,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> {
         let this = self;
         let expr_span = expr.span;
-        let scope_id = this.innermost_scope_id();
+        let source_info = this.source_info(expr.span);
         // Handle a number of expressions that don't need a destination at all. This
         // avoids needing a mountain of temporary `()` variables.
         match expr.kind {
             ExprKind::Scope { extent, value } => {
                 let value = this.hir.mirror(value);
-                this.in_scope(extent, block, |this, _| this.stmt_expr(block, value))
+                this.in_scope(extent, block, |this| this.stmt_expr(block, value))
             }
             ExprKind::Assign { lhs, rhs } => {
                 let lhs = this.hir.mirror(lhs);
                 let rhs = this.hir.mirror(rhs);
-                let scope_id = this.innermost_scope_id();
                 let lhs_span = lhs.span;
 
                 // Note: we evaluate assignments right-to-left. This
@@ -50,7 +49,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 } else {
                     let rhs = unpack!(block = this.as_rvalue(block, rhs));
                     let lhs = unpack!(block = this.as_lvalue(block, lhs));
-                    this.cfg.push_assign(block, scope_id, expr_span, &lhs, rhs);
+                    this.cfg.push_assign(block, source_info, &lhs, rhs);
                     block.unit()
                 }
             }
@@ -75,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // (overloaded ops should be desugared into a call).
                 let result = unpack!(block = this.build_binary_op(block, op, expr_span, lhs_ty,
                                                   Operand::Consume(lhs.clone()), rhs));
-                this.cfg.push_assign(block, scope_id, expr_span, &lhs, result);
+                this.cfg.push_assign(block, source_info, &lhs, result);
 
                 block.unit()
             }
@@ -93,8 +92,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 block = match value {
                     Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
                     None => {
-                        this.cfg.push_assign_unit(block, scope_id,
-                                                  expr_span, &Lvalue::ReturnPointer);
+                        this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer);
                         block
                     }
                 };
@@ -104,7 +102,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 this.cfg.start_new_block().unit()
             }
             _ => {
-                let expr_span = expr.span;
                 let expr_ty = expr.ty;
                 let temp = this.temp(expr.ty.clone());
                 unpack!(block = this.into(&temp, block, expr));
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 88d7e41bc61..b3315ab7d29 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -44,21 +44,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         .collect(),
         };
 
-        // Get the body expressions and their scopes, while declaring bindings.
-        let arm_bodies: Vec<_> = arms.iter().enumerate().map(|(i, arm)| {
-            // Assume that all expressions are wrapped in Scope.
+        // Get the arm bodies and their scopes, while declaring bindings.
+        let arm_bodies: Vec<_> = arms.iter().map(|arm| {
             let body = self.hir.mirror(arm.body.clone());
-            match body.kind {
-                ExprKind::Scope { extent, value } => {
-                    let scope_id = self.push_scope(extent, arm_blocks.blocks[i]);
-                    self.declare_bindings(scope_id, &arm.patterns[0]);
-                    (extent, self.scopes.pop().unwrap(), value)
-                }
-                _ => {
-                    span_bug!(body.span, "arm body is not wrapped in Scope {:?}",
-                              body.kind);
-                }
-            }
+            let scope = self.declare_bindings(None, body.span, &arm.patterns[0]);
+            (body, scope.unwrap_or(self.visibility_scope))
         }).collect();
 
         // assemble a list of candidates: there is one candidate per
@@ -88,74 +78,66 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // branch to the appropriate arm block
         let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block);
 
-        // because all matches are exhaustive, in principle we expect
-        // an empty vector to be returned here, but the algorithm is
-        // not entirely precise
         if !otherwise.is_empty() {
-            let join_block = self.join_otherwise_blocks(span, otherwise);
-            self.panic(join_block, "something about matches algorithm not being precise", span);
+            // All matches are exhaustive. However, because some matches
+            // only have exponentially-large exhaustive decision trees, we
+            // sometimes generate an inexhaustive decision tree.
+            //
+            // In that case, the inexhaustive tips of the decision tree
+            // can't be reached - terminate them with an `unreachable`.
+            let source_info = self.source_info(span);
+
+            let mut otherwise = otherwise;
+            otherwise.sort();
+            otherwise.dedup(); // variant switches can introduce duplicate target blocks
+            for block in otherwise {
+                self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
+            }
         }
 
         // all the arm blocks will rejoin here
         let end_block = self.cfg.start_new_block();
 
-        let scope_id = self.innermost_scope_id();
-        for (arm_index, (extent, scope, body)) in arm_bodies.into_iter().enumerate() {
+        let outer_source_info = self.source_info(span);
+        for (arm_index, (body, visibility_scope)) in arm_bodies.into_iter().enumerate() {
             let mut arm_block = arm_blocks.blocks[arm_index];
-            // Re-enter the scope we created the bindings in.
-            self.scopes.push(scope);
+            // Re-enter the visibility scope we created the bindings in.
+            self.visibility_scope = visibility_scope;
             unpack!(arm_block = self.into(destination, arm_block, body));
-            unpack!(arm_block = self.pop_scope(extent, arm_block));
-            self.cfg.terminate(arm_block,
-                               scope_id,
-                               span,
+            self.cfg.terminate(arm_block, outer_source_info,
                                TerminatorKind::Goto { target: end_block });
         }
+        self.visibility_scope = outer_source_info.scope;
 
         end_block.unit()
     }
 
     pub fn expr_into_pattern(&mut self,
                              mut block: BasicBlock,
-                             var_scope_id: ScopeId, // lifetime of vars
                              irrefutable_pat: Pattern<'tcx>,
                              initializer: ExprRef<'tcx>)
                              -> BlockAnd<()> {
         // optimize the case of `let x = ...`
         match *irrefutable_pat.kind {
-            PatternKind::Binding { mutability,
-                                   name,
-                                   mode: BindingMode::ByValue,
+            PatternKind::Binding { mode: BindingMode::ByValue,
                                    var,
-                                   ty,
-                                   subpattern: None } => {
-                let index = self.declare_binding(var_scope_id,
-                                                 mutability,
-                                                 name,
-                                                 var,
-                                                 ty,
-                                                 irrefutable_pat.span);
-                let lvalue = Lvalue::Var(index);
+                                   subpattern: None, .. } => {
+                let lvalue = Lvalue::Var(self.var_indices[&var]);
                 return self.into(&lvalue, block, initializer);
             }
             _ => {}
         }
         let lvalue = unpack!(block = self.as_lvalue(block, initializer));
         self.lvalue_into_pattern(block,
-                                 var_scope_id,
                                  irrefutable_pat,
                                  &lvalue)
     }
 
     pub fn lvalue_into_pattern(&mut self,
                                mut block: BasicBlock,
-                               var_scope_id: ScopeId,
                                irrefutable_pat: Pattern<'tcx>,
                                initializer: &Lvalue<'tcx>)
                                -> BlockAnd<()> {
-        // first, creating the bindings
-        self.declare_bindings(var_scope_id, &irrefutable_pat);
-
         // create a dummy candidate
         let mut candidate = Candidate {
             span: irrefutable_pat.span,
@@ -182,32 +164,47 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         block.unit()
     }
 
-    pub fn declare_bindings(&mut self, var_scope_id: ScopeId, pattern: &Pattern<'tcx>) {
+    /// Declares the bindings of the given pattern and returns the visibility scope
+    /// for the bindings in this patterns, if such a scope had to be created.
+    /// NOTE: Declaring the bindings should always be done in their drop scope.
+    pub fn declare_bindings(&mut self,
+                            mut var_scope: Option<VisibilityScope>,
+                            scope_span: Span,
+                            pattern: &Pattern<'tcx>)
+                            -> Option<VisibilityScope> {
         match *pattern.kind {
             PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => {
-                self.declare_binding(var_scope_id, mutability, name, var, ty, pattern.span);
+                if var_scope.is_none() {
+                    var_scope = Some(self.new_visibility_scope(scope_span));
+                }
+                let source_info = SourceInfo {
+                    span: pattern.span,
+                    scope: var_scope.unwrap()
+                };
+                self.declare_binding(source_info, mutability, name, var, ty);
                 if let Some(subpattern) = subpattern.as_ref() {
-                    self.declare_bindings(var_scope_id, subpattern);
+                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
                 }
             }
             PatternKind::Array { ref prefix, ref slice, ref suffix } |
             PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
                 for subpattern in prefix.iter().chain(slice).chain(suffix) {
-                    self.declare_bindings(var_scope_id, subpattern);
+                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
                 }
             }
             PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
             }
             PatternKind::Deref { ref subpattern } => {
-                self.declare_bindings(var_scope_id, subpattern);
+                var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
             }
             PatternKind::Leaf { ref subpatterns } |
             PatternKind::Variant { ref subpatterns, .. } => {
                 for subpattern in subpatterns {
-                    self.declare_bindings(var_scope_id, &subpattern.pattern);
+                    var_scope = self.declare_bindings(var_scope, scope_span, &subpattern.pattern);
                 }
             }
         }
+        var_scope
     }
 }
 
@@ -396,17 +393,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                              mut otherwise: Vec<BasicBlock>)
                              -> BasicBlock
     {
+        let source_info = self.source_info(span);
         otherwise.sort();
         otherwise.dedup(); // variant switches can introduce duplicate target blocks
-        let scope_id = self.innermost_scope_id();
         if otherwise.len() == 1 {
             otherwise[0]
         } else {
             let join_block = self.cfg.start_new_block();
             for block in otherwise {
-                self.cfg.terminate(block,
-                                   scope_id,
-                                   span,
+                self.cfg.terminate(block, source_info,
                                    TerminatorKind::Goto { target: join_block });
             }
             join_block
@@ -443,42 +438,87 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// simpler (and, in fact, irrefutable).
     ///
     /// But there may also be candidates that the test just doesn't
-    /// apply to. For example, consider the case of #29740:
+    /// apply to. The classical example involves wildcards:
     ///
     /// ```rust,ignore
+    /// match (x, y, z) {
+    ///     (true, _, true) => true,    // (0)
+    ///     (_, true, _) => true,       // (1)
+    ///     (false, false, _) => false, // (2)
+    ///     (true, _, false) => false,  // (3)
+    /// }
+    /// ```
+    ///
+    /// In that case, after we test on `x`, there are 2 overlapping candidate
+    /// sets:
+    ///
+    /// - If the outcome is that `x` is true, candidates 0, 1, and 3
+    /// - If the outcome is that `x` is false, candidates 1 and 2
+    ///
+    /// Here, the traditional "decision tree" method would generate 2
+    /// separate code-paths for the 2 separate cases.
+    ///
+    /// In some cases, this duplication can create an exponential amount of
+    /// code. This is most easily seen by noticing that this method terminates
+    /// with precisely the reachable arms being reachable - but that problem
+    /// is trivially NP-complete:
+    ///
+    /// ```rust
+    ///     match (var0, var1, var2, var3, ..) {
+    ///         (true, _, _, false, true, ...) => false,
+    ///         (_, true, true, false, _, ...) => false,
+    ///         (false, _, false, false, _, ...) => false,
+    ///         ...
+    ///         _ => true
+    ///     }
+    /// ```
+    ///
+    /// Here the last arm is reachable only if there is an assignment to
+    /// the variables that does not match any of the literals. Therefore,
+    /// compilation would take an exponential amount of time in some cases.
+    ///
+    /// That kind of exponential worst-case might not occur in practice, but
+    /// our simplistic treatment of constants and guards would make it occur
+    /// in very common situations - for example #29740:
+    ///
+    /// ```rust
     /// match x {
-    ///     "foo" => ...,
-    ///     "bar" => ...,
-    ///     "baz" => ...,
-    ///     _ => ...,
+    ///     "foo" if foo_guard => ...,
+    ///     "bar" if bar_guard => ...,
+    ///     "baz" if baz_guard => ...,
+    ///     ...
     /// }
     /// ```
     ///
-    /// Here the match-pair we are testing will be `x @ "foo"`, and we
-    /// will generate an `Eq` test. Because `"bar"` and `"baz"` are different
-    /// constants, we will decide that these later candidates are just not
-    /// informed by the eq test. So we'll wind up with three candidate sets:
+    /// Here we first test the match-pair `x @ "foo"`, which is an `Eq` test.
     ///
-    /// - If outcome is that `x == "foo"` (one candidate, derived from `x @ "foo"`)
-    /// - If outcome is that `x != "foo"` (empty list of candidates)
-    /// - Otherwise (three candidates, `x @ "bar"`, `x @ "baz"`, `x @
-    ///   _`). Here we have the invariant that everything in the
-    ///   otherwise list is of **lower priority** than the stuff in the
-    ///   other lists.
+    /// It might seem that we would end up with 2 disjoint candidate
+    /// sets, consisting of the first candidate or the other 3, but our
+    /// algorithm doesn't reason about "foo" being distinct from the other
+    /// constants; it considers the latter arms to potentially match after
+    /// both outcomes, which obviously leads to an exponential amount
+    /// of tests.
     ///
-    /// So we'll compile the test. For each outcome of the test, we
-    /// recursively call `match_candidates` with the corresponding set
-    /// of candidates. But note that this set is now inexhaustive: for
-    /// example, in the case where the test returns false, there are
-    /// NO candidates, even though there is stll a value to be
-    /// matched. So we'll collect the return values from
-    /// `match_candidates`, which are the blocks where control-flow
-    /// goes if none of the candidates matched. At this point, we can
-    /// continue with the "otherwise" list.
+    /// To avoid these kinds of problems, our algorithm tries to ensure
+    /// the amount of generated tests is linear. When we do a k-way test,
+    /// we return an additional "unmatched" set alongside the obvious `k`
+    /// sets. When we encounter a candidate that would be present in more
+    /// than one of the sets, we put it and all candidates below it into the
+    /// "unmatched" set. This ensures these `k+1` sets are disjoint.
+    ///
+    /// After we perform our test, we branch into the appropriate candidate
+    /// set and recurse with `match_candidates`. These sub-matches are
+    /// obviously inexhaustive - as we discarded our otherwise set - so
+    /// we set their continuation to do `match_candidates` on the
+    /// "unmatched" set (which is again inexhaustive).
     ///
     /// If you apply this to the above test, you basically wind up
     /// with an if-else-if chain, testing each candidate in turn,
     /// which is precisely what we want.
+    ///
+    /// In addition to avoiding exponential-time blowups, this algorithm
+    /// also has nice property that each guard and arm is only generated
+    /// once.
     fn test_candidates<'pat>(&mut self,
                              span: Span,
                              arm_blocks: &mut ArmBlocks,
@@ -585,24 +625,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         let arm_block = arm_blocks.blocks[candidate.arm_index];
 
-        let scope_id = self.innermost_scope_id();
         if let Some(guard) = candidate.guard {
             // the block to branch to if the guard fails; if there is no
             // guard, this block is simply unreachable
             let guard = self.hir.mirror(guard);
-            let guard_span = guard.span;
+            let source_info = self.source_info(guard.span);
             let cond = unpack!(block = self.as_operand(block, guard));
             let otherwise = self.cfg.start_new_block();
-            self.cfg.terminate(block,
-                               scope_id,
-                               guard_span,
+            self.cfg.terminate(block, source_info,
                                TerminatorKind::If { cond: cond,
                                                     targets: (arm_block, otherwise)});
             Some(otherwise)
         } else {
-            self.cfg.terminate(block,
-                               scope_id,
-                               candidate.span,
+            let source_info = self.source_info(candidate.span);
+            self.cfg.terminate(block, source_info,
                                TerminatorKind::Goto { target: arm_block });
             None
         }
@@ -628,39 +664,35 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Rvalue::Ref(region, borrow_kind, binding.source),
             };
 
-            let scope_id = self.innermost_scope_id();
-            self.cfg.push_assign(block, scope_id, binding.span,
+            let source_info = self.source_info(binding.span);
+            self.cfg.push_assign(block, source_info,
                                  &Lvalue::Var(var_index), rvalue);
         }
     }
 
     fn declare_binding(&mut self,
-                       var_scope_id: ScopeId,
+                       source_info: SourceInfo,
                        mutability: Mutability,
                        name: Name,
                        var_id: NodeId,
-                       var_ty: Ty<'tcx>,
-                       span: Span)
-                       -> u32
+                       var_ty: Ty<'tcx>)
+                       -> Var
     {
-        debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_scope_id={:?}, span={:?})",
-               var_id, name, var_ty, var_scope_id, span);
+        debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})",
+               var_id, name, var_ty, source_info);
 
-        let index = self.var_decls.len();
-        self.var_decls.push(VarDecl::<'tcx> {
-            scope: var_scope_id,
+        let var = self.var_decls.push(VarDecl::<'tcx> {
+            source_info: source_info,
             mutability: mutability,
             name: name,
             ty: var_ty.clone(),
-            span: span,
         });
-        let index = index as u32;
-        let extent = self.scope_auxiliary[var_scope_id].extent;
-        self.schedule_drop(span, extent, &Lvalue::Var(index), var_ty);
-        self.var_indices.insert(var_id, index);
+        let extent = self.extent_of_innermost_scope();
+        self.schedule_drop(source_info.span, extent, &Lvalue::Var(var), var_ty);
+        self.var_indices.insert(var_id, var);
 
-        debug!("declare_binding: index={:?}", index);
+        debug!("declare_binding: var={:?}", var);
 
-        index
+        var
     }
 }
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index c707bb8a27b..8392248e3f2 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -31,7 +31,7 @@ use std::mem;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn simplify_candidate<'pat>(&mut self,
-                                    mut block: BasicBlock,
+                                    block: BasicBlock,
                                     candidate: &mut Candidate<'pat, 'tcx>)
                                     -> BlockAnd<()> {
         // repeatedly simplify match pairs until fixed point is reached
@@ -39,10 +39,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
             let mut progress = match_pairs.len(); // count how many were simplified
             for match_pair in match_pairs {
-                match self.simplify_match_pair(block, match_pair, candidate) {
-                    Ok(b) => {
-                        block = b;
-                    }
+                match self.simplify_match_pair(match_pair, candidate) {
+                    Ok(()) => {}
                     Err(match_pair) => {
                         candidate.match_pairs.push(match_pair);
                         progress -= 1; // this one was not simplified
@@ -61,14 +59,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// possible, Err is returned and no changes are made to
     /// candidate.
     fn simplify_match_pair<'pat>(&mut self,
-                                 mut block: BasicBlock,
                                  match_pair: MatchPair<'pat, 'tcx>,
                                  candidate: &mut Candidate<'pat, 'tcx>)
-                                 -> Result<BasicBlock, MatchPair<'pat, 'tcx>> {
+                                 -> Result<(), MatchPair<'pat, 'tcx>> {
         match *match_pair.pattern.kind {
             PatternKind::Wild => {
                 // nothing left to do
-                Ok(block)
+                Ok(())
             }
 
             PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
@@ -87,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
                 }
 
-                Ok(block)
+                Ok(())
             }
 
             PatternKind::Constant { .. } => {
@@ -96,37 +93,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
 
             PatternKind::Range { .. } |
-            PatternKind::Variant { .. } => {
-                // cannot simplify, test is required
-                Err(match_pair)
-            }
-
-            PatternKind::Slice { .. } if !match_pair.slice_len_checked => {
+            PatternKind::Variant { .. } |
+            PatternKind::Slice { .. } => {
                 Err(match_pair)
             }
 
-            PatternKind::Array { ref prefix, ref slice, ref suffix } |
-            PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
-                unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs,
-                                                         block,
-                                                         match_pair.lvalue.clone(),
-                                                         prefix,
-                                                         slice.as_ref(),
-                                                         suffix));
-                Ok(block)
+            PatternKind::Array { ref prefix, ref slice, ref suffix } => {
+                self.prefix_slice_suffix(&mut candidate.match_pairs,
+                                         &match_pair.lvalue,
+                                         prefix,
+                                         slice.as_ref(),
+                                         suffix);
+                Ok(())
             }
 
             PatternKind::Leaf { ref subpatterns } => {
                 // tuple struct, match subpats (if any)
                 candidate.match_pairs
                          .extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
-                Ok(block)
+                Ok(())
             }
 
             PatternKind::Deref { ref subpattern } => {
                 let lvalue = match_pair.lvalue.deref();
                 candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
-                Ok(block)
+                Ok(())
             }
         }
     }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 09c146537e7..668bdcf7358 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
 use rustc::mir::repr::*;
 use syntax::codemap::Span;
+use std::cmp::Ordering;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Identifies what test is needed to decide if `match_pair` is applicable.
@@ -176,7 +177,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         lvalue: &Lvalue<'tcx>,
                         test: &Test<'tcx>)
                         -> Vec<BasicBlock> {
-        let scope_id = self.innermost_scope_id();
+        let source_info = self.source_info(test.span);
         match test.kind {
             TestKind::Switch { adt_def, ref variants } => {
                 let num_enum_variants = self.hir.num_variants(adt_def);
@@ -193,7 +194,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }).collect();
                 debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}",
                        num_enum_variants, variants.iter().count(), variants);
-                self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch {
+                self.cfg.terminate(block, source_info, TerminatorKind::Switch {
                     discr: lvalue.clone(),
                     adt_def: adt_def,
                     targets: target_blocks.clone()
@@ -245,10 +246,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                self.cfg.terminate(block,
-                                   scope_id,
-                                   test.span,
-                                   term);
+                self.cfg.terminate(block, source_info, term);
                 targets
             }
 
@@ -265,7 +263,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         if let ty::TyArray(_, _) = mt.ty.sty {
                             ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
                             let val_slice = self.temp(ty);
-                            self.cfg.push_assign(block, scope_id, test.span, &val_slice,
+                            self.cfg.push_assign(block, source_info, &val_slice,
                                                  Rvalue::Cast(CastKind::Unsize, val, ty));
                             val = Operand::Consume(val_slice);
                         }
@@ -280,7 +278,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     });
 
                     let slice = self.temp(ty);
-                    self.cfg.push_assign(block, scope_id, test.span, &slice,
+                    self.cfg.push_assign(block, source_info, &slice,
                                          Rvalue::Cast(CastKind::Unsize, array, ty));
                     Operand::Consume(slice)
                 } else {
@@ -301,7 +299,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let eq_result = self.temp(bool_ty);
                     let eq_block = self.cfg.start_new_block();
                     let cleanup = self.diverge_cleanup();
-                    self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Call {
+                    self.cfg.terminate(block, source_info, TerminatorKind::Call {
                         func: Operand::Constant(Constant {
                             span: test.span,
                             ty: mty,
@@ -314,7 +312,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                     // check the result
                     let block = self.cfg.start_new_block();
-                    self.cfg.terminate(eq_block, scope_id, test.span, TerminatorKind::If {
+                    self.cfg.terminate(eq_block, source_info, TerminatorKind::If {
                         cond: Operand::Consume(eq_result),
                         targets: (block, fail),
                     });
@@ -344,17 +342,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
 
                 // actual = len(lvalue)
-                self.cfg.push_assign(block, scope_id, test.span,
+                self.cfg.push_assign(block, source_info,
                                      &actual, Rvalue::Len(lvalue.clone()));
 
                 // expected = <N>
-                let expected = self.push_usize(block, scope_id, test.span, len);
+                let expected = self.push_usize(block, source_info, len);
 
                 // result = actual == expected OR result = actual < expected
-                self.cfg.push_assign(block,
-                                     scope_id,
-                                     test.span,
-                                     &result,
+                self.cfg.push_assign(block, source_info, &result,
                                      Rvalue::BinaryOp(op,
                                                       Operand::Consume(actual),
                                                       Operand::Consume(expected)));
@@ -362,7 +357,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // branch based on result
                 let target_blocks: Vec<_> = vec![self.cfg.start_new_block(),
                                                  self.cfg.start_new_block()];
-                self.cfg.terminate(block, scope_id, test.span, TerminatorKind::If {
+                self.cfg.terminate(block, source_info, TerminatorKind::If {
                     cond: Operand::Consume(result),
                     targets: (target_blocks[0], target_blocks[1])
                 });
@@ -383,13 +378,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let result = self.temp(bool_ty);
 
         // result = op(left, right)
-        let scope_id = self.innermost_scope_id();
-        self.cfg.push_assign(block, scope_id, span, &result,
+        let source_info = self.source_info(span);
+        self.cfg.push_assign(block, source_info, &result,
                              Rvalue::BinaryOp(op, left, right));
 
         // branch based on result
         let target_block = self.cfg.start_new_block();
-        self.cfg.terminate(block, scope_id, span, TerminatorKind::If {
+        self.cfg.terminate(block, source_info, TerminatorKind::If {
             cond: Operand::Consume(result),
             targets: (target_block, fail_block)
         });
@@ -452,69 +447,118 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         };
 
-        match test.kind {
+        match (&test.kind, &*match_pair.pattern.kind) {
             // If we are performing a variant switch, then this
             // informs variant patterns, but nothing else.
-            TestKind::Switch { adt_def: tested_adt_def , .. } => {
-                match *match_pair.pattern.kind {
-                    PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
-                        assert_eq!(adt_def, tested_adt_def);
-                        let new_candidate =
-                            self.candidate_after_variant_switch(match_pair_index,
-                                                                adt_def,
-                                                                variant_index,
-                                                                subpatterns,
-                                                                candidate);
-                        resulting_candidates[variant_index].push(new_candidate);
-                        true
-                    }
-                    _ => {
-                        false
-                    }
-                }
+            (&TestKind::Switch { adt_def: tested_adt_def, .. },
+             &PatternKind::Variant { adt_def, variant_index, ref subpatterns }) => {
+                assert_eq!(adt_def, tested_adt_def);
+                let new_candidate =
+                    self.candidate_after_variant_switch(match_pair_index,
+                                                        adt_def,
+                                                        variant_index,
+                                                        subpatterns,
+                                                        candidate);
+                resulting_candidates[variant_index].push(new_candidate);
+                true
             }
+            (&TestKind::Switch { .. }, _) => false,
 
             // If we are performing a switch over integers, then this informs integer
             // equality, but nothing else.
             //
-            // FIXME(#29623) we could use TestKind::Range to rule
+            // FIXME(#29623) we could use PatternKind::Range to rule
             // things out here, in some cases.
-            TestKind::SwitchInt { switch_ty: _, options: _, ref indices } => {
-                match *match_pair.pattern.kind {
-                    PatternKind::Constant { ref value }
-                    if is_switch_ty(match_pair.pattern.ty) => {
-                        let index = indices[value];
-                        let new_candidate = self.candidate_without_match_pair(match_pair_index,
-                                                                              candidate);
-                        resulting_candidates[index].push(new_candidate);
+            (&TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
+             &PatternKind::Constant { ref value })
+            if is_switch_ty(match_pair.pattern.ty) => {
+                let index = indices[value];
+                let new_candidate = self.candidate_without_match_pair(match_pair_index,
+                                                                      candidate);
+                resulting_candidates[index].push(new_candidate);
+                true
+            }
+            (&TestKind::SwitchInt { .. }, _) => false,
+
+
+            (&TestKind::Len { len: test_len, op: BinOp::Eq },
+             &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
+                let pat_len = (prefix.len() + suffix.len()) as u64;
+                match (test_len.cmp(&pat_len), slice) {
+                    (Ordering::Equal, &None) => {
+                        // on true, min_len = len = $actual_length,
+                        // on false, len != $actual_length
+                        resulting_candidates[0].push(
+                            self.candidate_after_slice_test(match_pair_index,
+                                                            candidate,
+                                                            prefix,
+                                                            slice.as_ref(),
+                                                            suffix)
+                        );
                         true
                     }
-                    _ => {
+                    (Ordering::Less, _) => {
+                        // test_len < pat_len. If $actual_len = test_len,
+                        // then $actual_len < pat_len and we don't have
+                        // enough elements.
+                        resulting_candidates[1].push(candidate.clone());
+                        true
+                    }
+                    (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
+                        // This can match both if $actual_len = test_len >= pat_len,
+                        // and if $actual_len > test_len. We can't advance.
                         false
                     }
+                    (Ordering::Greater, &None) => {
+                        // test_len != pat_len, so if $actual_len = test_len, then
+                        // $actual_len != pat_len.
+                        resulting_candidates[1].push(candidate.clone());
+                        true
+                    }
                 }
             }
 
-            // If we are performing a length check, then this
-            // informs slice patterns, but nothing else.
-            TestKind::Len { .. } => {
-                let pattern_test = self.test(&match_pair);
-                match *match_pair.pattern.kind {
-                    PatternKind::Slice { .. } if pattern_test.kind == test.kind => {
-                        let mut new_candidate = candidate.clone();
-
-                        // Set up the MatchKind to simplify this like an array.
-                        new_candidate.match_pairs[match_pair_index]
-                                     .slice_len_checked = true;
-                        resulting_candidates[0].push(new_candidate);
+            (&TestKind::Len { len: test_len, op: BinOp::Ge },
+             &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
+                // the test is `$actual_len >= test_len`
+                let pat_len = (prefix.len() + suffix.len()) as u64;
+                match (test_len.cmp(&pat_len), slice) {
+                    (Ordering::Equal, &Some(_))  => {
+                        // $actual_len >= test_len = pat_len,
+                        // so we can match.
+                        resulting_candidates[0].push(
+                            self.candidate_after_slice_test(match_pair_index,
+                                                            candidate,
+                                                            prefix,
+                                                            slice.as_ref(),
+                                                            suffix)
+                        );
                         true
                     }
-                    _ => false
+                    (Ordering::Less, _) | (Ordering::Equal, &None) => {
+                        // test_len <= pat_len. If $actual_len < test_len,
+                        // then it is also < pat_len, so the test passing is
+                        // necessary (but insufficient).
+                        resulting_candidates[0].push(candidate.clone());
+                        true
+                    }
+                    (Ordering::Greater, &None) => {
+                        // test_len > pat_len. If $actual_len >= test_len > pat_len,
+                        // then we know we won't have a match.
+                        resulting_candidates[1].push(candidate.clone());
+                        true
+                    }
+                    (Ordering::Greater, &Some(_)) => {
+                        // test_len < pat_len, and is therefore less
+                        // strict. This can still go both ways.
+                        false
+                    }
                 }
             }
 
-            TestKind::Eq { .. } |
-            TestKind::Range { .. } => {
+            (&TestKind::Eq { .. }, _) |
+            (&TestKind::Range { .. }, _) |
+            (&TestKind::Len { .. }, _) => {
                 // These are all binary tests.
                 //
                 // FIXME(#29623) we can be more clever here
@@ -550,6 +594,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
+    fn candidate_after_slice_test<'pat>(&mut self,
+                                        match_pair_index: usize,
+                                        candidate: &Candidate<'pat, 'tcx>,
+                                        prefix: &'pat [Pattern<'tcx>],
+                                        opt_slice: Option<&'pat Pattern<'tcx>>,
+                                        suffix: &'pat [Pattern<'tcx>])
+                                        -> Candidate<'pat, 'tcx> {
+        let mut new_candidate =
+            self.candidate_without_match_pair(match_pair_index, candidate);
+        self.prefix_slice_suffix(
+            &mut new_candidate.match_pairs,
+            &candidate.match_pairs[match_pair_index].lvalue,
+            prefix,
+            opt_slice,
+            suffix);
+
+        new_candidate
+    }
+
     fn candidate_after_variant_switch<'pat>(&mut self,
                                             match_pair_index: usize,
                                             adt_def: ty::AdtDef<'tcx>,
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
index 5eb58f7612d..53ebf6fceb5 100644
--- a/src/librustc_mir/build/matches/util.rs
+++ b/src/librustc_mir/build/matches/util.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build::{BlockAnd, BlockAndExtension, Builder};
+use build::Builder;
 use build::matches::MatchPair;
 use hair::*;
 use rustc::mir::repr::*;
@@ -28,64 +28,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                    .collect()
     }
 
-    /// When processing an array/slice pattern like `lv @ [x, y, ..s, z]`,
-    /// this function converts the prefix (`x`, `y`) and suffix (`z`) into
-    /// distinct match pairs:
-    ///
-    /// ```rust,ignore
-    ///     lv[0 of 3] @ x  // see ProjectionElem::ConstantIndex (and its Debug impl)
-    ///     lv[1 of 3] @ y  // to explain the `[x of y]` notation
-    ///     lv[-1 of 3] @ z
-    /// ```
-    ///
-    /// If a slice like `s` is present, then the function also creates
-    /// a temporary like:
-    ///
-    /// ```rust,ignore
-    ///     tmp0 = lv[2..-1] // using the special Rvalue::Slice
-    /// ```
-    ///
-    /// and creates a match pair `tmp0 @ s`
-    pub fn prefix_suffix_slice<'pat>(&mut self,
+    pub fn prefix_slice_suffix<'pat>(&mut self,
                                      match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
-                                     block: BasicBlock,
-                                     lvalue: Lvalue<'tcx>,
+                                     lvalue: &Lvalue<'tcx>,
                                      prefix: &'pat [Pattern<'tcx>],
                                      opt_slice: Option<&'pat Pattern<'tcx>>,
-                                     suffix: &'pat [Pattern<'tcx>])
-                                     -> BlockAnd<()> {
-        // If there is a `..P` pattern, create a temporary `t0` for
-        // the slice and then a match pair `t0 @ P`:
-        if let Some(slice) = opt_slice {
-            let prefix_len = prefix.len();
-            let suffix_len = suffix.len();
-            let rvalue = Rvalue::Slice {
-                input: lvalue.clone(),
-                from_start: prefix_len,
-                from_end: suffix_len,
-            };
-            let temp = self.temp(slice.ty.clone()); // no need to schedule drop, temp is always copy
-            let scope_id = self.innermost_scope_id();
-            self.cfg.push_assign(block, scope_id, slice.span, &temp, rvalue);
-            match_pairs.push(MatchPair::new(temp, slice));
-        }
-
-        self.prefix_suffix(match_pairs, lvalue, prefix, suffix);
-
-        block.unit()
-    }
-
-    /// Helper for `prefix_suffix_slice` which just processes the prefix and suffix.
-    fn prefix_suffix<'pat>(&mut self,
-                           match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
-                           lvalue: Lvalue<'tcx>,
-                           prefix: &'pat [Pattern<'tcx>],
-                           suffix: &'pat [Pattern<'tcx>]) {
+                                     suffix: &'pat [Pattern<'tcx>]) {
         let min_length = prefix.len() + suffix.len();
         assert!(min_length < u32::MAX as usize);
         let min_length = min_length as u32;
 
-        let prefix_pairs: Vec<_> =
+        match_pairs.extend(
             prefix.iter()
                   .enumerate()
                   .map(|(idx, subpattern)| {
@@ -97,9 +50,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                       let lvalue = lvalue.clone().elem(elem);
                       MatchPair::new(lvalue, subpattern)
                   })
-                  .collect();
+        );
+
+        if let Some(subslice_pat) = opt_slice {
+            let subslice = lvalue.clone().elem(ProjectionElem::Subslice {
+                from: prefix.len() as u32,
+                to: suffix.len() as u32
+            });
+            match_pairs.push(MatchPair::new(subslice, subslice_pat));
+        }
 
-        let suffix_pairs: Vec<_> =
+        match_pairs.extend(
             suffix.iter()
                   .rev()
                   .enumerate()
@@ -112,9 +73,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                       let lvalue = lvalue.clone().elem(elem);
                       MatchPair::new(lvalue, subpattern)
                   })
-                  .collect();
-
-        match_pairs.extend(prefix_pairs.into_iter().chain(suffix_pairs));
+        );
     }
 }
 
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index c3501140fc0..0d7a5028348 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -18,7 +18,6 @@ use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
 
 use rustc::mir::repr::*;
-use std::u32;
 use syntax::ast;
 use syntax::codemap::Span;
 
@@ -29,12 +28,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// NB: **No cleanup is scheduled for this temporary.** You should
     /// call `schedule_drop` once the temporary is initialized.
     pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
-        let index = self.temp_decls.len();
-        self.temp_decls.push(TempDecl { ty: ty });
-        assert!(index < (u32::MAX) as usize);
-        let lvalue = Lvalue::Temp(index as u32);
+        let temp = self.temp_decls.push(TempDecl { ty: ty });
+        let lvalue = Lvalue::Temp(temp);
         debug!("temp: created temp {:?} with type {:?}",
-               lvalue, self.temp_decls.last().unwrap().ty);
+               lvalue, self.temp_decls[temp].ty);
         lvalue
     }
 
@@ -103,16 +100,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     pub fn push_usize(&mut self,
                       block: BasicBlock,
-                      scope_id: ScopeId,
-                      span: Span,
+                      source_info: SourceInfo,
                       value: u64)
                       -> Lvalue<'tcx> {
         let usize_ty = self.hir.usize_ty();
         let temp = self.temp(usize_ty);
         self.cfg.push_assign_constant(
-            block, scope_id, span, &temp,
+            block, source_info, &temp,
             Constant {
-                span: span,
+                span: source_info.span,
                 ty: self.hir.usize_ty(),
                 literal: self.hir.usize_literal(value),
             });
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 9d7818a9ba4..2626a02281f 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -12,14 +12,17 @@ use hair::cx::Cx;
 use rustc::middle::region::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT};
 use rustc::ty::{self, Ty};
 use rustc::mir::repr::*;
-use rustc_data_structures::fnv::FnvHashMap;
+use rustc::util::nodemap::NodeMap;
 use rustc::hir;
-use std::ops::{Index, IndexMut};
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::parse::token::keywords;
 
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+
+use std::u32;
+
 pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     hir: Cx<'a, 'gcx, 'tcx>,
     cfg: CFG<'tcx>,
@@ -35,7 +38,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     ///  but these are liable to get out of date once optimization
     ///  begins. They are also hopefully temporary, and will be
     ///  no longer needed when we adopt graph-based regions.
-    scope_auxiliary: ScopeAuxiliaryVec,
+    scope_auxiliary: IndexVec<ScopeId, ScopeAuxiliary>,
 
     /// the current set of loops; see the `scope` module for more
     /// details
@@ -43,11 +46,12 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     /// the vector of all scopes that we have created thus far;
     /// we track this for debuginfo later
-    scope_datas: Vec<ScopeData>,
+    visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
+    visibility_scope: VisibilityScope,
 
-    var_decls: Vec<VarDecl<'tcx>>,
-    var_indices: FnvHashMap<ast::NodeId, u32>,
-    temp_decls: Vec<TempDecl<'tcx>>,
+    var_decls: IndexVec<Var, VarDecl<'tcx>>,
+    var_indices: NodeMap<Var>,
+    temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
     unit_temp: Option<Lvalue<'tcx>>,
 
     /// cached block with the RESUME terminator; this is created
@@ -58,7 +62,21 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 }
 
 struct CFG<'tcx> {
-    basic_blocks: Vec<BasicBlockData<'tcx>>,
+    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct ScopeId(u32);
+
+impl Idx for ScopeId {
+    fn new(index: usize) -> ScopeId {
+        assert!(index < (u32::MAX as usize));
+        ScopeId(index as u32)
+    }
+
+    fn index(self) -> usize {
+        self.0 as usize
+    }
 }
 
 /// For each scope, we track the extent (from the HIR) and a
@@ -93,25 +111,7 @@ pub struct Location {
     pub statement_index: usize,
 }
 
-pub struct ScopeAuxiliaryVec {
-    pub vec: Vec<ScopeAuxiliary>
-}
-
-impl Index<ScopeId> for ScopeAuxiliaryVec {
-    type Output = ScopeAuxiliary;
-
-    #[inline]
-    fn index(&self, index: ScopeId) -> &ScopeAuxiliary {
-        &self.vec[index.index()]
-    }
-}
-
-impl IndexMut<ScopeId> for ScopeAuxiliaryVec {
-    #[inline]
-    fn index_mut(&mut self, index: ScopeId) -> &mut ScopeAuxiliary {
-        &mut self.vec[index.index()]
-    }
-}
+pub type ScopeAuxiliaryVec = IndexVec<ScopeId, ScopeAuxiliary>;
 
 ///////////////////////////////////////////////////////////////////////////
 /// The `BlockAnd` "monad" packages up the new basic block along with a
@@ -179,17 +179,16 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
         tcx.region_maps.lookup_code_extent(
             CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
     let mut block = START_BLOCK;
-    let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block,
-                                                         |builder, call_site_scope_id| {
-        let arg_decls = unpack!(block = builder.in_scope(arg_extent, block,
-                                                         |builder, arg_scope_id| {
-            builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block)
+    let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
+        let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| {
+            builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block)
         }));
 
+        let source_info = builder.source_info(span);
         let return_block = builder.return_block();
-        builder.cfg.terminate(block, call_site_scope_id, span,
+        builder.cfg.terminate(block, source_info,
                               TerminatorKind::Goto { target: return_block });
-        builder.cfg.terminate(return_block, call_site_scope_id, span,
+        builder.cfg.terminate(return_block, source_info,
                               TerminatorKind::Return);
         return_block.and(arg_decls)
     }));
@@ -198,8 +197,8 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     match tcx.node_id_to_type(fn_id).sty {
         ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
             // RustCall pseudo-ABI untuples the last argument.
-            if let Some(arg_decl) = arg_decls.last_mut() {
-                arg_decl.spread = true;
+            if let Some(last_arg) = arg_decls.last() {
+                arg_decls[last_arg].spread = true;
             }
         }
         _ => {}
@@ -241,49 +240,53 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
 
     let extent = ROOT_CODE_EXTENT;
     let mut block = START_BLOCK;
-    let _ = builder.in_scope(extent, block, |builder, call_site_scope_id| {
+    let _ = builder.in_scope(extent, block, |builder| {
         let expr = builder.hir.mirror(ast_expr);
         unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr));
 
+        let source_info = builder.source_info(span);
         let return_block = builder.return_block();
-        builder.cfg.terminate(block, call_site_scope_id, span,
+        builder.cfg.terminate(block, source_info,
                               TerminatorKind::Goto { target: return_block });
-        builder.cfg.terminate(return_block, call_site_scope_id, span,
+        builder.cfg.terminate(return_block, source_info,
                               TerminatorKind::Return);
 
         return_block.unit()
     });
 
     let ty = tcx.expr_ty_adjusted(ast_expr);
-    builder.finish(vec![], vec![], ty::FnConverging(ty))
+    builder.finish(vec![], IndexVec::new(), ty::FnConverging(ty))
 }
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
         let mut builder = Builder {
             hir: hir,
-            cfg: CFG { basic_blocks: vec![] },
+            cfg: CFG { basic_blocks: IndexVec::new() },
             fn_span: span,
             scopes: vec![],
-            scope_datas: vec![],
-            scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
+            visibility_scopes: IndexVec::new(),
+            visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
+            scope_auxiliary: IndexVec::new(),
             loop_scopes: vec![],
-            temp_decls: vec![],
-            var_decls: vec![],
-            var_indices: FnvHashMap(),
+            temp_decls: IndexVec::new(),
+            var_decls: IndexVec::new(),
+            var_indices: NodeMap(),
             unit_temp: None,
             cached_resume_block: None,
             cached_return_block: None
         };
 
         assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
+        assert_eq!(builder.new_visibility_scope(span), ARGUMENT_VISIBILITY_SCOPE);
+        builder.visibility_scopes[ARGUMENT_VISIBILITY_SCOPE].parent_scope = None;
 
         builder
     }
 
     fn finish(self,
               upvar_decls: Vec<UpvarDecl>,
-              arg_decls: Vec<ArgDecl<'tcx>>,
+              arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
               return_ty: ty::FnOutput<'tcx>)
               -> (Mir<'tcx>, ScopeAuxiliaryVec) {
         for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
@@ -292,41 +295,38 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         }
 
-        (Mir {
-            basic_blocks: self.cfg.basic_blocks,
-            scopes: self.scope_datas,
-            promoted: vec![],
-            var_decls: self.var_decls,
-            arg_decls: arg_decls,
-            temp_decls: self.temp_decls,
-            upvar_decls: upvar_decls,
-            return_ty: return_ty,
-            span: self.fn_span
-        }, self.scope_auxiliary)
+        (Mir::new(self.cfg.basic_blocks,
+                  self.visibility_scopes,
+                  IndexVec::new(),
+                  return_ty,
+                  self.var_decls,
+                  arg_decls,
+                  self.temp_decls,
+                  upvar_decls,
+                  self.fn_span
+        ), self.scope_auxiliary)
     }
 
     fn args_and_body<A>(&mut self,
                         mut block: BasicBlock,
                         return_ty: ty::FnOutput<'tcx>,
                         arguments: A,
-                        argument_scope_id: ScopeId,
+                        argument_extent: CodeExtent,
                         ast_block: &'gcx hir::Block)
-                        -> BlockAnd<Vec<ArgDecl<'tcx>>>
+                        -> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>>
         where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
     {
         // to start, translate the argument patterns and collect the argument types.
+        let mut scope = None;
         let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
-            let lvalue = Lvalue::Arg(index as u32);
+            let lvalue = Lvalue::Arg(Arg::new(index));
             if let Some(pattern) = pattern {
                 let pattern = self.hir.irrefutable_pat(pattern);
-                unpack!(block = self.lvalue_into_pattern(block,
-                                                         argument_scope_id,
-                                                         pattern,
-                                                         &lvalue));
+                scope = self.declare_bindings(scope, ast_block.span, &pattern);
+                unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
             }
 
             // Make sure we drop (parts of) the argument even when not matched on.
-            let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
             self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
                                argument_extent, &lvalue, ty);
 
@@ -344,6 +344,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         }).collect();
 
+        // Enter the argument pattern bindings visibility scope, if it exists.
+        if let Some(visibility_scope) = scope {
+            self.visibility_scope = visibility_scope;
+        }
+
         // FIXME(#32959): temporary hack for the issue at hand
         let return_is_unit = if let ty::FnConverging(t) = return_ty {
             t.is_nil()
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 209649dd2fd..65457a9cc80 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -86,21 +86,23 @@ should go to.
 
 */
 
-use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary};
+use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId};
 use rustc::middle::region::{CodeExtent, CodeExtentData};
 use rustc::middle::lang_items;
 use rustc::ty::subst::{Substs, Subst, VecPerParamSpace};
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{Ty, TyCtxt};
 use rustc::mir::repr::*;
-use syntax::codemap::{Span, DUMMY_SP};
-use syntax::parse::token::intern_and_get_ident;
-use rustc::middle::const_val::ConstVal;
-use rustc_const_math::ConstInt;
+use syntax::codemap::Span;
+use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::fnv::FnvHashMap;
 
 pub struct Scope<'tcx> {
-    /// the scope-id within the scope_datas
+    /// the scope-id within the scope_auxiliary
     id: ScopeId,
 
+    /// The visibility scope this scope was created in.
+    visibility_scope: VisibilityScope,
+
     /// the extent of this scope within source code; also stored in
     /// `ScopeAuxiliary`, but kept here for convenience
     extent: CodeExtent,
@@ -126,12 +128,8 @@ pub struct Scope<'tcx> {
     /// stage.
     free: Option<FreeData<'tcx>>,
 
-    /// The cached block for the cleanups-on-diverge path. This block
-    /// contains a block that will just do a RESUME to an appropriate
-    /// place. This block does not execute any of the drops or free:
-    /// each of those has their own cached-blocks, which will branch
-    /// to this point.
-    cached_block: Option<BasicBlock>
+    /// The cache for drop chain on “normal” exit into a particular BasicBlock.
+    cached_exits: FnvHashMap<(BasicBlock, CodeExtent), BasicBlock>,
 }
 
 struct DropData<'tcx> {
@@ -171,7 +169,7 @@ pub struct LoopScope {
     pub continue_block: BasicBlock,
     /// Block to branch into when the loop terminates (either by being `break`-en out from, or by
     /// having its condition to become false)
-    pub break_block: BasicBlock, // where to go on a `break
+    pub break_block: BasicBlock,
     /// Indicates the reachability of the break_block for this loop
     pub might_break: bool
 }
@@ -182,7 +180,7 @@ impl<'tcx> Scope<'tcx> {
     /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
     /// larger extent of code.
     fn invalidate_cache(&mut self) {
-        self.cached_block = None;
+        self.cached_exits = FnvHashMap();
         for dropdata in &mut self.drops {
             dropdata.cached_block = None;
         }
@@ -191,7 +189,7 @@ impl<'tcx> Scope<'tcx> {
         }
     }
 
-    /// Returns the cached block for this scope.
+    /// Returns the cached entrypoint for diverging exit from this scope.
     ///
     /// Precondition: the caches must be fully filled (i.e. diverge_cleanup is called) in order for
     /// this method to work correctly.
@@ -204,6 +202,14 @@ impl<'tcx> Scope<'tcx> {
             None
         }
     }
+
+    /// Given a span and this scope's visibility scope, make a SourceInfo.
+    fn source_info(&self, span: Span) -> SourceInfo {
+        SourceInfo {
+            span: span,
+            scope: self.visibility_scope
+        }
+    }
 }
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -237,11 +243,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Convenience wrapper that pushes a scope and then executes `f`
     /// to build its contents, popping the scope afterwards.
     pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F) -> BlockAnd<R>
-        where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>, ScopeId) -> BlockAnd<R>
+        where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
     {
         debug!("in_scope(extent={:?}, block={:?})", extent, block);
-        let id = self.push_scope(extent, block);
-        let rv = unpack!(block = f(self, id));
+        self.push_scope(extent, block);
+        let rv = unpack!(block = f(self));
         unpack!(block = self.pop_scope(extent, block));
         debug!("in_scope: exiting extent={:?} block={:?}", extent, block);
         block.and(rv)
@@ -251,28 +257,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// scope and call `pop_scope` afterwards. Note that these two
     /// calls must be paired; using `in_scope` as a convenience
     /// wrapper maybe preferable.
-    pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) -> ScopeId {
+    pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) {
         debug!("push_scope({:?})", extent);
-        let parent_id = self.scopes.last().map(|s| s.id);
-        let id = ScopeId::new(self.scope_datas.len());
-        let tcx = self.hir.tcx();
-        self.scope_datas.push(ScopeData {
-            span: extent.span(&tcx.region_maps, &tcx.map).unwrap_or(DUMMY_SP),
-            parent_scope: parent_id,
-        });
+        let id = ScopeId::new(self.scope_auxiliary.len());
+        let vis_scope = self.visibility_scope;
         self.scopes.push(Scope {
             id: id,
+            visibility_scope: vis_scope,
             extent: extent,
             drops: vec![],
             free: None,
-            cached_block: None,
+            cached_exits: FnvHashMap()
         });
-        self.scope_auxiliary.vec.push(ScopeAuxiliary {
+        self.scope_auxiliary.push(ScopeAuxiliary {
             extent: extent,
             dom: self.cfg.current_location(entry),
             postdoms: vec![]
         });
-        id
     }
 
     /// Pops a scope, which should have extent `extent`, adding any
@@ -310,35 +311,52 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                                       .unwrap_or_else(||{
             span_bug!(span, "extent {:?} does not enclose", extent)
         });
-
+        let len = self.scopes.len();
+        assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
         let tmp = self.get_unit_temp();
-        for (idx, ref scope) in self.scopes.iter().enumerate().rev().take(scope_count) {
-            unpack!(block = build_scope_drops(&mut self.cfg,
-                                              scope,
-                                              &self.scopes[..idx],
-                                              block));
+        {
+        let mut rest = &mut self.scopes[(len - scope_count)..];
+        while let Some((scope, rest_)) = {rest}.split_last_mut() {
+            rest = rest_;
+            block = if let Some(&e) = scope.cached_exits.get(&(target, extent)) {
+                self.cfg.terminate(block, scope.source_info(span),
+                                   TerminatorKind::Goto { target: e });
+                return;
+            } else {
+                let b = self.cfg.start_new_block();
+                self.cfg.terminate(block, scope.source_info(span),
+                                   TerminatorKind::Goto { target: b });
+                scope.cached_exits.insert((target, extent), b);
+                b
+            };
+            unpack!(block = build_scope_drops(&mut self.cfg, scope, rest, block));
             if let Some(ref free_data) = scope.free {
                 let next = self.cfg.start_new_block();
                 let free = build_free(self.hir.tcx(), &tmp, free_data, next);
-                self.cfg.terminate(block, scope.id, span, free);
+                self.cfg.terminate(block, scope.source_info(span), free);
                 block = next;
             }
             self.scope_auxiliary[scope.id]
                 .postdoms
                 .push(self.cfg.current_location(block));
         }
-
-        assert!(scope_count < self.scopes.len(),
-                "should never use `exit_scope` to pop *ALL* scopes");
-        let scope = self.scopes.iter().rev().skip(scope_count)
-                                            .next()
-                                            .unwrap();
-        self.cfg.terminate(block,
-                           scope.id,
-                           span,
+        }
+        let scope = &self.scopes[len - scope_count];
+        self.cfg.terminate(block, scope.source_info(span),
                            TerminatorKind::Goto { target: target });
     }
 
+    /// Creates a new visibility scope, nested in the current one.
+    pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
+        let parent = self.visibility_scope;
+        let scope = VisibilityScope::new(self.visibility_scopes.len());
+        self.visibility_scopes.push(VisibilityScopeData {
+            span: span,
+            parent_scope: Some(parent),
+        });
+        scope
+    }
+
     // Finding scopes
     // ==============
     /// Finds the loop scope for a given label. This is used for
@@ -363,8 +381,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
     }
 
-    pub fn innermost_scope_id(&self) -> ScopeId {
-        self.scopes.last().map(|scope| scope.id).unwrap()
+    /// Given a span and the current visibility scope, make a SourceInfo.
+    pub fn source_info(&self, span: Span) -> SourceInfo {
+        SourceInfo {
+            span: span,
+            scope: self.visibility_scope
+        }
     }
 
     pub fn extent_of_innermost_scope(&self) -> CodeExtent {
@@ -481,15 +503,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             target
         } else {
             let resumeblk = cfg.start_new_cleanup_block();
-            cfg.terminate(resumeblk, scopes[0].id, self.fn_span, TerminatorKind::Resume);
+            cfg.terminate(resumeblk,
+                          scopes[0].source_info(self.fn_span),
+                          TerminatorKind::Resume);
             *cached_resume_block = Some(resumeblk);
             resumeblk
         };
 
-        for scope in scopes {
+        for scope in scopes.iter_mut().filter(|s| !s.drops.is_empty() || s.free.is_some()) {
             target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, scope, target);
         }
-
         Some(target)
     }
 
@@ -502,12 +525,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         if !self.hir.needs_drop(ty) {
             return block.unit();
         }
-        let scope_id = self.innermost_scope_id();
+        let source_info = self.source_info(span);
         let next_target = self.cfg.start_new_block();
         let diverge_target = self.diverge_cleanup();
-        self.cfg.terminate(block,
-                           scope_id,
-                           span,
+        self.cfg.terminate(block, source_info,
                            TerminatorKind::Drop {
                                location: location,
                                target: next_target,
@@ -516,18 +537,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         next_target.unit()
     }
 
-
+    /// Utility function for *non*-scope code to build their own drops
     pub fn build_drop_and_replace(&mut self,
                                   block: BasicBlock,
                                   span: Span,
                                   location: Lvalue<'tcx>,
                                   value: Operand<'tcx>) -> BlockAnd<()> {
-        let scope_id = self.innermost_scope_id();
+        let source_info = self.source_info(span);
         let next_target = self.cfg.start_new_block();
         let diverge_target = self.diverge_cleanup();
-        self.cfg.terminate(block,
-                           scope_id,
-                           span,
+        self.cfg.terminate(block, source_info,
                            TerminatorKind::DropAndReplace {
                                location: location,
                                value: value,
@@ -537,50 +556,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         next_target.unit()
     }
 
-    /// Create diverge cleanup and branch to it from `block`.
-    // FIXME: Remove this (used only for unreachable cases in match).
-    pub fn panic(&mut self, block: BasicBlock, msg: &'static str, span: Span) {
-        // fn(&(msg: &'static str filename: &'static str, line: u32)) -> !
-        let region = ty::ReStatic; // FIXME(mir-borrowck): use a better region?
-        let func = self.lang_function(lang_items::PanicFnLangItem);
-        let args = self.hir.tcx().replace_late_bound_regions(&func.ty.fn_args(), |_| region).0;
-
-        let ref_ty = args[0];
-        let tup_ty = if let ty::TyRef(_, tyandmut) = ref_ty.sty {
-            tyandmut.ty
-        } else {
-            span_bug!(span, "unexpected panic type: {:?}", func.ty);
-        };
-
-        let (tuple, tuple_ref) = (self.temp(tup_ty), self.temp(ref_ty));
-        let (file, line) = self.span_to_fileline_args(span);
-        let message = Constant {
-            span: span,
-            ty: self.hir.tcx().mk_static_str(),
-            literal: self.hir.str_literal(intern_and_get_ident(msg))
-        };
-        let elems = vec![Operand::Constant(message),
-                         Operand::Constant(file),
-                         Operand::Constant(line)];
-        let scope_id = self.innermost_scope_id();
-        // FIXME: We should have this as a constant, rather than a stack variable (to not pollute
-        // icache with cold branch code), however to achieve that we either have to rely on rvalue
-        // promotion or have some way, in MIR, to create constants.
-        self.cfg.push_assign(block, scope_id, span, &tuple, // [1]
-                             Rvalue::Aggregate(AggregateKind::Tuple, elems));
-        // [1] tuple = (message_arg, file_arg, line_arg);
-        // FIXME: is this region really correct here?
-        self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple;
-                             Rvalue::Ref(region, BorrowKind::Shared, tuple));
-        let cleanup = self.diverge_cleanup();
-        self.cfg.terminate(block, scope_id, span, TerminatorKind::Call {
-            func: Operand::Constant(func),
-            args: vec![Operand::Consume(tuple_ref)],
-            cleanup: cleanup,
-            destination: None,
-        });
-    }
-
     /// Create an Assert terminator and return the success block.
     /// If the boolean condition operand is not the expected value,
     /// a runtime panic will be caused with the given message.
@@ -590,12 +565,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                   msg: AssertMessage<'tcx>,
                   span: Span)
                   -> BasicBlock {
-        let scope_id = self.innermost_scope_id();
+        let source_info = self.source_info(span);
 
         let success_block = self.cfg.start_new_block();
         let cleanup = self.diverge_cleanup();
 
-        self.cfg.terminate(block, scope_id, span,
+        self.cfg.terminate(block, source_info,
                            TerminatorKind::Assert {
                                cond: cond,
                                expected: expected,
@@ -606,39 +581,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         success_block
     }
-
-    fn lang_function(&mut self, lang_item: lang_items::LangItem) -> Constant<'tcx> {
-        let funcdid = match self.hir.tcx().lang_items.require(lang_item) {
-            Ok(d) => d,
-            Err(m) => {
-                self.hir.tcx().sess.fatal(&m)
-            }
-        };
-        Constant {
-            span: DUMMY_SP,
-            ty: self.hir.tcx().lookup_item_type(funcdid).ty,
-            literal: Literal::Item {
-                def_id: funcdid,
-                substs: self.hir.tcx().mk_substs(Substs::empty())
-            }
-        }
-    }
-
-    fn span_to_fileline_args(&mut self, span: Span) -> (Constant<'tcx>, Constant<'tcx>) {
-        let span_lines = self.hir.tcx().sess.codemap().lookup_char_pos(span.lo);
-        (Constant {
-            span: span,
-            ty: self.hir.tcx().mk_static_str(),
-            literal: self.hir.str_literal(intern_and_get_ident(&span_lines.file.name))
-        }, Constant {
-            span: span,
-            ty: self.hir.tcx().types.u32,
-            literal: Literal::Value {
-                value: ConstVal::Integral(ConstInt::U32(span_lines.line as u32)),
-            },
-        })
-    }
-
 }
 
 /// Builds drops for pop_scope and exit_scope.
@@ -658,7 +600,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
             earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
         });
         let next = cfg.start_new_block();
-        cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop {
+        cfg.terminate(block, scope.source_info(drop_data.span), TerminatorKind::Drop {
             location: drop_data.location.clone(),
             target: next,
             unwind: on_diverge
@@ -688,15 +630,19 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     // remainder. If everything is cached, we'll just walk right to
     // left reading the cached results but never created anything.
 
+    let visibility_scope = scope.visibility_scope;
+    let source_info = |span| SourceInfo {
+        span: span,
+        scope: visibility_scope
+    };
+
     // Next, build up any free.
     if let Some(ref mut free_data) = scope.free {
         target = if let Some(cached_block) = free_data.cached_block {
             cached_block
         } else {
             let into = cfg.start_new_cleanup_block();
-            cfg.terminate(into,
-                          scope.id,
-                          free_data.span,
+            cfg.terminate(into, source_info(free_data.span),
                           build_free(tcx, unit_temp, free_data, target));
             free_data.cached_block = Some(into);
             into
@@ -711,9 +657,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             cached_block
         } else {
             let block = cfg.start_new_cleanup_block();
-            cfg.terminate(block,
-                          scope.id,
-                          drop_data.span,
+            cfg.terminate(block, source_info(drop_data.span),
                           TerminatorKind::Drop {
                               location: drop_data.location.clone(),
                               target: target,
diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs
index 6a34d9ff0b4..fdfa872b0b6 100644
--- a/src/librustc_mir/graphviz.rs
+++ b/src/librustc_mir/graphviz.rs
@@ -15,6 +15,8 @@ use std::fmt::Debug;
 use std::io::{self, Write};
 use syntax::ast::NodeId;
 
+use rustc_data_structures::indexed_vec::Idx;
+
 /// Write a graphviz DOT graph of a list of MIRs.
 pub fn write_mir_graphviz<'a, 'b, 'tcx, W, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                               iter: I, w: &mut W)
@@ -32,12 +34,12 @@ where W: Write, I: Iterator<Item=(&'a NodeId, &'a Mir<'a>)> {
         write_graph_label(tcx, nodeid, mir, w)?;
 
         // Nodes
-        for block in mir.all_basic_blocks() {
+        for (block, _) in mir.basic_blocks().iter_enumerated() {
             write_node(block, mir, w)?;
         }
 
         // Edges
-        for source in mir.all_basic_blocks() {
+        for (source, _) in mir.basic_blocks().iter_enumerated() {
             write_edges(source, mir, w)?;
         }
         writeln!(w, "}}")?
@@ -61,7 +63,7 @@ pub fn write_node_label<W: Write, INIT, FINI>(block: BasicBlock,
     where INIT: Fn(&mut W) -> io::Result<()>,
           FINI: Fn(&mut W) -> io::Result<()>
 {
-    let data = mir.basic_block_data(block);
+    let data = &mir[block];
 
     write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#)?;
 
@@ -105,7 +107,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
 
 /// Write graphviz DOT edges with labels between the given basic block and all of its successors.
 fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
-    let terminator = &mir.basic_block_data(source).terminator();
+    let terminator = mir[source].terminator();
     let labels = terminator.kind.fmt_successor_labels();
 
     for (&target, label) in terminator.successors().iter().zip(labels) {
@@ -130,7 +132,7 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         if i > 0 {
             write!(w, ", ")?;
         }
-        write!(w, "{:?}: {}", Lvalue::Arg(i as u32), escape(&arg.ty))?;
+        write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?;
     }
 
     write!(w, ") -&gt; ")?;
@@ -150,13 +152,13 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             write!(w, "mut ")?;
         }
         write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
-               Lvalue::Var(i as u32), escape(&var.ty), var.name)?;
+               Lvalue::Var(Var::new(i)), escape(&var.ty), var.name)?;
     }
 
     // Compiler-introduced temporary types.
     for (i, temp) in mir.temp_decls.iter().enumerate() {
         write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
-               Lvalue::Temp(i as u32), escape(&temp.ty))?;
+               Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?;
     }
 
     writeln!(w, ">;")
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 1f560672b62..b5e2ce9de48 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use hair::*;
-use rustc_data_structures::fnv::FnvHashMap;
+use rustc_data_structures::indexed_vec::Idx;
 use rustc_const_math::ConstInt;
 use hair::cx::Cx;
 use hair::cx::block;
@@ -19,7 +19,6 @@ use rustc::hir::def::Def;
 use rustc::middle::const_val::ConstVal;
 use rustc_const_eval as const_eval;
 use rustc::middle::region::CodeExtent;
-use rustc::hir::pat_util;
 use rustc::ty::{self, VariantDef, Ty};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::mir::repr::*;
@@ -263,7 +262,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 let adt_data = if let hir::ExprPath(..) = fun.node {
                     // Tuple-like ADTs are represented as ExprCall. We convert them here.
                     expr_ty.ty_adt_def().and_then(|adt_def|{
-                        match cx.tcx.def_map.borrow()[&fun.id].full_def() {
+                        match cx.tcx.expect_def(fun.id) {
                             Def::Variant(_, variant_id) => {
                                 Some((adt_def, adt_def.variant_index_with_id(variant_id)))
                             },
@@ -471,7 +470,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     }
                 }
                 ty::TyEnum(adt, substs) => {
-                    match cx.tcx.def_map.borrow()[&expr.id].full_def() {
+                    match cx.tcx.expect_def(expr.id) {
                         Def::Variant(enum_id, variant_id) => {
                             debug_assert!(adt.did == enum_id);
                             assert!(base.is_none());
@@ -651,19 +650,8 @@ 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> {
-    let mut map;
-    let opt_map = if arm.pats.len() == 1 {
-        None
-    } else {
-        map = FnvHashMap();
-        pat_util::pat_bindings(&arm.pats[0], |_, p_id, _, path| {
-            map.insert(path.node, p_id);
-        });
-        Some(&map)
-    };
-
     Arm {
-        patterns: arm.pats.iter().map(|p| cx.refutable_pat(opt_map, p)).collect(),
+        patterns: arm.pats.iter().map(|p| cx.refutable_pat(p)).collect(),
         guard: arm.guard.to_ref(),
         body: arm.body.to_ref(),
     }
@@ -674,7 +662,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      -> ExprKind<'tcx> {
     let substs = cx.tcx.node_id_item_substs(expr.id).substs;
     // Otherwise there may be def_map borrow conflicts
-    let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
+    let def = cx.tcx.expect_def(expr.id);
     let def_id = match def {
         // A regular function.
         Def::Fn(def_id) | Def::Method(def_id) => def_id,
@@ -730,14 +718,9 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             id: node_id,
         },
 
-        def @ Def::Local(..) |
-        def @ Def::Upvar(..) => return convert_var(cx, expr, def),
+        Def::Local(..) | Def::Upvar(..) => return convert_var(cx, expr, def),
 
-        def =>
-            span_bug!(
-                expr.span,
-                "def `{:?}` not yet implemented",
-                def),
+        _ => span_bug!(expr.span, "def `{:?}` not yet implemented", def),
     };
     ExprKind::Literal {
         literal: Literal::Item { def_id: def_id, substs: substs }
@@ -1038,11 +1021,9 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
 fn loop_label<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                               expr: &'tcx hir::Expr) -> CodeExtent {
-    match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
-        Some(Def::Label(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
-        d => {
-            span_bug!(expr.span, "loop scope resolved to {:?}", d);
-        }
+    match cx.tcx.expect_def(expr.id) {
+        Def::Label(loop_id) => cx.tcx.region_maps.node_extent(loop_id),
+        d => span_bug!(expr.span, "loop scope resolved to {:?}", d),
     }
 }
 
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 25860ae7ef1..81b098281d6 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -21,6 +21,7 @@ use rustc::mir::transform::MirSource;
 
 use rustc::middle::const_val::ConstVal;
 use rustc_const_eval as const_eval;
+use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index acde81979f9..1bc3954a5fe 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -10,14 +10,13 @@
 
 use hair::*;
 use hair::cx::Cx;
-use rustc_data_structures::fnv::FnvHashMap;
+use rustc_data_structures::indexed_vec::Idx;
 use rustc_const_eval as const_eval;
 use rustc::hir::def::Def;
 use rustc::hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
 use rustc::ty::{self, Ty};
 use rustc::mir::repr::*;
 use rustc::hir::{self, PatKind};
-use syntax::ast;
 use syntax::codemap::Span;
 use syntax::ptr::P;
 
@@ -36,29 +35,25 @@ use syntax::ptr::P;
 /// ```
 struct PatCx<'patcx, 'cx: 'patcx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>,
-    binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>,
 }
 
 impl<'cx, 'gcx, 'tcx> Cx<'cx, 'gcx, 'tcx> {
     pub fn irrefutable_pat(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
-        PatCx::new(self, None).to_pattern(pat)
+        PatCx::new(self).to_pattern(pat)
     }
 
     pub fn refutable_pat(&mut self,
-                         binding_map: Option<&FnvHashMap<ast::Name, ast::NodeId>>,
                          pat: &hir::Pat)
                          -> Pattern<'tcx> {
-        PatCx::new(self, binding_map).to_pattern(pat)
+        PatCx::new(self).to_pattern(pat)
     }
 }
 
 impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
-    fn new(cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>,
-               binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>)
+    fn new(cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>)
                -> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
         PatCx {
             cx: cx,
-            binding_map: binding_map,
         }
     }
 
@@ -84,8 +79,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
             PatKind::Path(..) | PatKind::QPath(..)
                 if pat_is_resolved_const(&self.cx.tcx.def_map.borrow(), pat) =>
             {
-                let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
-                match def {
+                match self.cx.tcx.expect_def(pat.id) {
                     Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                         let tcx = self.cx.tcx.global_tcx();
                         let substs = Some(self.cx.tcx.node_id_item_substs(pat.id).substs);
@@ -110,7 +104,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                             }
                         }
                     }
-                    _ =>
+                    def =>
                         span_bug!(
                             pat.span,
                             "def not a constant: {:?}",
@@ -168,10 +162,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
             }
 
             PatKind::Binding(bm, ref ident, ref sub) => {
-                let id = match self.binding_map {
-                    None => pat.id,
-                    Some(ref map) => map[&ident.node],
-                };
+                let id = self.cx.tcx.expect_def(pat.id).var_id();
                 let var_ty = self.cx.tcx.node_id_to_type(pat.id);
                 let region = match var_ty.sty {
                     ty::TyRef(&r, _) => Some(r),
@@ -218,8 +209,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                     ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def,
                     _ => span_bug!(pat.span, "tuple struct pattern not applied to struct or enum"),
                 };
-                let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
-                let variant_def = adt_def.variant_of_def(def);
+                let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id));
 
                 let subpatterns =
                         subpatterns.iter()
@@ -242,9 +232,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                             "struct pattern not applied to struct or enum");
                     }
                 };
-
-                let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
-                let variant_def = adt_def.variant_of_def(def);
+                let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id));
 
                 let subpatterns =
                     fields.iter()
@@ -323,8 +311,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                        pat: &hir::Pat,
                        subpatterns: Vec<FieldPattern<'tcx>>)
                        -> PatternKind<'tcx> {
-        let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
-        match def {
+        match self.cx.tcx.expect_def(pat.id) {
             Def::Variant(enum_id, variant_id) => {
                 let adt_def = self.cx.tcx.lookup_adt_def(enum_id);
                 if adt_def.variants.len() > 1 {
@@ -342,7 +329,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                 PatternKind::Leaf { subpatterns: subpatterns }
             }
 
-            _ => {
+            def => {
                 span_bug!(pat.span, "inappropriate def for pattern: {:?}", def);
             }
         }
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 79d11e78bde..3d1ef31bd5c 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -49,4 +49,3 @@ mod hair;
 pub mod mir_map;
 pub mod pretty;
 pub mod transform;
-pub mod traversal;
diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs
index a6bbd55ffa7..515620d4253 100644
--- a/src/librustc_mir/pretty.rs
+++ b/src/librustc_mir/pretty.rs
@@ -8,17 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build::{Location, ScopeAuxiliaryVec};
+use build::{Location, ScopeAuxiliaryVec, ScopeId};
 use rustc::hir;
 use rustc::mir::repr::*;
 use rustc::mir::transform::MirSource;
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::fnv::FnvHashMap;
+use rustc_data_structures::indexed_vec::{Idx};
 use std::fmt::Display;
 use std::fs;
 use std::io::{self, Write};
 use syntax::ast::NodeId;
-use syntax::codemap::Span;
 
 const INDENT: &'static str = "    ";
 /// Alignment for lining up comments following MIR statements
@@ -61,8 +61,13 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return;
     }
 
-    let file_name = format!("rustc.node{}.{}.{}.mir",
-                            node_id, pass_name, disambiguator);
+    let promotion_id = match src {
+        MirSource::Promoted(_, id) => format!("-{:?}", id),
+        _ => String::new()
+    };
+
+    let file_name = format!("rustc.node{}{}.{}.{}.mir",
+                            node_id, promotion_id, pass_name, disambiguator);
     let _ = fs::File::create(&file_name).and_then(|mut file| {
         try!(writeln!(file, "// MIR for `{}`", node_path));
         try!(writeln!(file, "// node_id = {}", node_id));
@@ -93,7 +98,7 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
         let src = MirSource::from_node(tcx, id);
         write_mir_fn(tcx, src, mir, w, None)?;
 
-        for (i, mir) in mir.promoted.iter().enumerate() {
+        for (i, mir) in mir.promoted.iter_enumerated() {
             writeln!(w, "")?;
             write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
         }
@@ -112,9 +117,7 @@ fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>)
     // compute scope/entry exit annotations
     let mut annotations = FnvHashMap();
     if let Some(auxiliary) = auxiliary {
-        for (index, auxiliary) in auxiliary.vec.iter().enumerate() {
-            let scope_id = ScopeId::new(index);
-
+        for (scope_id, auxiliary) in auxiliary.iter_enumerated() {
             annotations.entry(auxiliary.dom)
                        .or_insert(vec![])
                        .push(Annotation::EnterScope(scope_id));
@@ -137,22 +140,13 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               -> io::Result<()> {
     let annotations = scope_entry_exit_annotations(auxiliary);
     write_mir_intro(tcx, src, mir, w)?;
-    for block in mir.all_basic_blocks() {
+    for block in mir.basic_blocks().indices() {
         write_basic_block(tcx, block, mir, w, &annotations)?;
+        if block.index() + 1 != mir.basic_blocks().len() {
+            writeln!(w, "")?;
+        }
     }
 
-    // construct a scope tree and write it out
-    let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
-    for (index, scope_data) in mir.scopes.iter().enumerate() {
-        scope_tree.entry(scope_data.parent_scope)
-                  .or_insert(vec![])
-                  .push(ScopeId::new(index));
-    }
-
-    writeln!(w, "{}scope tree:", INDENT)?;
-    write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1, false)?;
-    writeln!(w, "")?;
-
     writeln!(w, "}}")?;
     Ok(())
 }
@@ -164,7 +158,7 @@ fn write_basic_block(tcx: TyCtxt,
                      w: &mut Write,
                      annotations: &FnvHashMap<Location, Vec<Annotation>>)
                      -> io::Result<()> {
-    let data = mir.basic_block_data(block);
+    let data = &mir[block];
 
     // Basic block label at the top.
     writeln!(w, "{}{:?}: {{", INDENT, block)?;
@@ -189,7 +183,7 @@ fn write_basic_block(tcx: TyCtxt,
         writeln!(w, "{0:1$} // {2}",
                  indented_mir,
                  ALIGN,
-                 comment(tcx, statement.scope, statement.span))?;
+                 comment(tcx, statement.source_info))?;
 
         current_location.statement_index += 1;
     }
@@ -199,71 +193,64 @@ fn write_basic_block(tcx: TyCtxt,
     writeln!(w, "{0:1$} // {2}",
              indented_terminator,
              ALIGN,
-             comment(tcx, data.terminator().scope, data.terminator().span))?;
+             comment(tcx, data.terminator().source_info))?;
 
     writeln!(w, "{}}}\n", INDENT)
 }
 
-fn comment(tcx: TyCtxt, scope: ScopeId, span: Span) -> String {
+fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
     format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
 }
 
 fn write_scope_tree(tcx: TyCtxt,
                     mir: &Mir,
-                    auxiliary: Option<&ScopeAuxiliaryVec>,
-                    scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>,
+                    scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
                     w: &mut Write,
-                    parent: Option<ScopeId>,
-                    depth: usize,
-                    same_line: bool)
+                    parent: VisibilityScope,
+                    depth: usize)
                     -> io::Result<()> {
-    let indent = if same_line {
-        0
-    } else {
-        depth * INDENT.len()
-    };
+    let indent = depth * INDENT.len();
 
     let children = match scope_tree.get(&parent) {
         Some(childs) => childs,
         None => return Ok(()),
     };
 
-    for (index, &child) in children.iter().enumerate() {
-        if index == 0 && same_line {
-            // We know we're going to output a scope, so prefix it with a space to separate it from
-            // the previous scopes on this line
-            write!(w, " ")?;
-        }
-
-        let data = &mir.scopes[child];
-        assert_eq!(data.parent_scope, parent);
-        write!(w, "{0:1$}{2}", "", indent, child.index())?;
+    for &child in children {
+        let data = &mir.visibility_scopes[child];
+        assert_eq!(data.parent_scope, Some(parent));
+        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
 
-        let indent = indent + INDENT.len();
+        // User variable types (including the user's name in a comment).
+        for (id, var) in mir.var_decls.iter_enumerated() {
+            // Skip if not declared in this scope.
+            if var.source_info.scope != child {
+                continue;
+            }
 
-        if let Some(auxiliary) = auxiliary {
-            let extent = auxiliary[child].extent;
-            let data = tcx.region_maps.code_extent_data(extent);
-            writeln!(w, "{0:1$}Extent: {2:?}", "", indent, data)?;
+            let mut_str = if var.mutability == Mutability::Mut {
+                "mut "
+            } else {
+                ""
+            };
+
+            let indent = indent + INDENT.len();
+            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
+                                       INDENT,
+                                       indent,
+                                       mut_str,
+                                       id,
+                                       var.ty);
+            writeln!(w, "{0:1$} // \"{2}\" in {3}",
+                     indented_var,
+                     ALIGN,
+                     var.name,
+                     comment(tcx, var.source_info))?;
         }
 
-        let child_count = scope_tree.get(&Some(child)).map(Vec::len).unwrap_or(0);
-        if child_count < 2 {
-            // Skip the braces when there's no or only a single subscope
-            write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
-                             Some(child), depth, true)?;
-        } else {
-            // 2 or more child scopes? Put them in braces and on new lines.
-            writeln!(w, " {{")?;
-            write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
-                             Some(child), depth + 1, false)?;
+        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
 
-            write!(w, "\n{0:1$}}}", "", depth * INDENT.len())?;
-        }
-
-        if !same_line && index + 1 < children.len() {
-            writeln!(w, "")?;
-        }
+        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
     }
 
     Ok(())
@@ -278,7 +265,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              -> io::Result<()> {
     write_mir_sig(tcx, src, mir, w)?;
     writeln!(w, " {{")?;
-    write_mir_decls(tcx, mir, w)
+
+    // construct a scope tree and write it out
+    let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
+    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
+        if let Some(parent) = scope_data.parent_scope {
+            scope_tree.entry(parent)
+                      .or_insert(vec![])
+                      .push(VisibilityScope::new(index));
+        } else {
+            // Only the argument scope has no parent, because it's the root.
+            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
+        }
+    }
+
+    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
+
+    write_mir_decls(mir, w)
 }
 
 fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
@@ -289,7 +292,7 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
         MirSource::Const(_) => write!(w, "const")?,
         MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
         MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
-        MirSource::Promoted(_, i) => write!(w, "promoted{} in", i)?
+        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
     }
 
     write!(w, " {}", tcx.node_path_str(src.item_id()))?;
@@ -298,11 +301,11 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
         write!(w, "(")?;
 
         // fn argument types.
-        for (i, arg) in mir.arg_decls.iter().enumerate() {
-            if i > 0 {
+        for (i, arg) in mir.arg_decls.iter_enumerated() {
+            if i.index() != 0 {
                 write!(w, ", ")?;
             }
-            write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
+            write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
         }
 
         write!(w, ") -> ")?;
@@ -318,32 +321,10 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
     }
 }
 
-fn write_mir_decls(tcx: TyCtxt, mir: &Mir, w: &mut Write)
-                   -> io::Result<()>
-{
-    // User variable types (including the user's name in a comment).
-    for (i, var) in mir.var_decls.iter().enumerate() {
-        let mut_str = if var.mutability == Mutability::Mut {
-            "mut "
-        } else {
-            ""
-        };
-
-        let indented_var = format!("{}let {}{:?}: {};",
-                                   INDENT,
-                                   mut_str,
-                                   Lvalue::Var(i as u32),
-                                   var.ty);
-        writeln!(w, "{0:1$} // \"{2}\" in {3}",
-                 indented_var,
-                 ALIGN,
-                 var.name,
-                 comment(tcx, var.scope, var.span))?;
-    }
-
+fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
     // Compiler-introduced temporary types.
-    for (i, temp) in mir.temp_decls.iter().enumerate() {
-        writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;
+    for (id, temp) in mir.temp_decls.iter_enumerated() {
+        writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
     }
 
     // Wrote any declaration? Add an empty line before the first block is printed.
diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs
index bcdd62c1899..c028504d6f9 100644
--- a/src/librustc_mir/transform/add_call_guards.rs
+++ b/src/librustc_mir/transform/add_call_guards.rs
@@ -11,10 +11,7 @@
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
 use rustc::mir::transform::{MirPass, MirSource, Pass};
-
-use pretty;
-
-use traversal;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 
 pub struct AddCallGuards;
 
@@ -39,42 +36,30 @@ pub struct AddCallGuards;
  */
 
 impl<'tcx> MirPass<'tcx> for AddCallGuards {
-    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
-        let mut pred_count = vec![0u32; mir.basic_blocks.len()];
-
-        // Build the precedecessor map for the MIR
-        for (_, data) in traversal::preorder(mir) {
-            if let Some(ref term) = data.terminator {
-                for &tgt in term.successors().iter() {
-                    pred_count[tgt.index()] += 1;
-                }
-            }
-        }
+    fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
+        let pred_count: IndexVec<_, _> =
+            mir.predecessors().iter().map(|ps| ps.len()).collect();
 
         // We need a place to store the new blocks generated
         let mut new_blocks = Vec::new();
 
-        let bbs = mir.all_basic_blocks();
-        let cur_len = mir.basic_blocks.len();
-
-        for &bb in &bbs {
-            let data = mir.basic_block_data_mut(bb);
+        let cur_len = mir.basic_blocks().len();
 
-            match data.terminator {
+        for block in mir.basic_blocks_mut() {
+            match block.terminator {
                 Some(Terminator {
                     kind: TerminatorKind::Call {
                         destination: Some((_, ref mut destination)),
                         cleanup: Some(_),
                         ..
-                    }, span, scope
-                }) if pred_count[destination.index()] > 1 => {
+                    }, source_info
+                }) if pred_count[*destination] > 1 => {
                     // It's a critical edge, break it
                     let call_guard = BasicBlockData {
                         statements: vec![],
-                        is_cleanup: data.is_cleanup,
+                        is_cleanup: block.is_cleanup,
                         terminator: Some(Terminator {
-                            span: span,
-                            scope: scope,
+                            source_info: source_info,
                             kind: TerminatorKind::Goto { target: *destination }
                         })
                     };
@@ -88,10 +73,9 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards {
             }
         }
 
-        pretty::dump_mir(tcx, "break_cleanup_edges", &0, src, mir, None);
         debug!("Broke {} N edges", new_blocks.len());
 
-        mir.basic_blocks.extend_from_slice(&new_blocks);
+        mir.basic_blocks_mut().extend(new_blocks);
     }
 }
 
diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs
index fb49f951ecd..642adeee5cd 100644
--- a/src/librustc_mir/transform/dump_mir.rs
+++ b/src/librustc_mir/transform/dump_mir.rs
@@ -10,18 +10,64 @@
 
 //! This pass just dumps MIR at a specified point.
 
+use std::fmt;
+
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
-use rustc::mir::transform::{Pass, MirPass, MirSource};
+use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource};
 use pretty;
 
-pub struct DumpMir<'a>(pub &'a str);
+pub struct Marker<'a>(pub &'a str);
+
+impl<'b, 'tcx> MirPass<'tcx> for Marker<'b> {
+    fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    _src: MirSource, _mir: &mut Mir<'tcx>)
+    {}
+}
+
+impl<'b> Pass for Marker<'b> {
+    fn name(&self) -> &str { self.0 }
+}
+
+pub struct Disambiguator<'a> {
+    pass: &'a Pass,
+    is_after: bool
+}
+
+impl<'a> fmt::Display for Disambiguator<'a> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let title = if self.is_after { "after" } else { "before" };
+        if let Some(fmt) = self.pass.disambiguator() {
+            write!(formatter, "{}-{}", fmt, title)
+        } else {
+            write!(formatter, "{}", title)
+        }
+    }
+}
+
+pub struct DumpMir;
 
-impl<'b, 'tcx> MirPass<'tcx> for DumpMir<'b> {
-    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                    src: MirSource, mir: &mut Mir<'tcx>) {
-        pretty::dump_mir(tcx, self.0, &0, src, mir, None);
+impl<'tcx> MirPassHook<'tcx> for DumpMir {
+    fn on_mir_pass<'a>(
+        &mut self,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        src: MirSource,
+        mir: &Mir<'tcx>,
+        pass: &Pass,
+        is_after: bool)
+    {
+        pretty::dump_mir(
+            tcx,
+            pass.name(),
+            &Disambiguator {
+                pass: pass,
+                is_after: is_after
+            },
+            src,
+            mir,
+            None
+        );
     }
 }
 
-impl<'b> Pass for DumpMir<'b> {}
+impl<'b> Pass for DumpMir {}
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 339dcdec060..7b707b4adb6 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub mod remove_dead_blocks;
+pub mod simplify_branches;
 pub mod simplify_cfg;
 pub mod erase_regions;
 pub mod no_landing_pads;
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index 590106e0a22..818f060ed44 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -24,6 +24,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
             TerminatorKind::Goto { .. } |
             TerminatorKind::Resume |
             TerminatorKind::Return |
+            TerminatorKind::Unreachable |
             TerminatorKind::If { .. } |
             TerminatorKind::Switch { .. } |
             TerminatorKind::SwitchInt { .. } => {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index d81c4e2dfb6..3ebfef10d43 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -24,11 +24,13 @@
 
 use rustc::mir::repr::*;
 use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
+use rustc::mir::traversal::ReversePostorder;
 use rustc::ty::{self, TyCtxt};
 use syntax::codemap::Span;
 
 use build::Location;
-use traversal::ReversePostorder;
+
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 use std::mem;
 
@@ -74,7 +76,7 @@ pub enum Candidate {
 }
 
 struct TempCollector {
-    temps: Vec<TempState>,
+    temps: IndexVec<Temp, TempState>,
     location: Location,
     span: Span
 }
@@ -89,7 +91,7 @@ impl<'tcx> Visitor<'tcx> for TempCollector {
                 return;
             }
 
-            let temp = &mut self.temps[index as usize];
+            let temp = &mut self.temps[index];
             if *temp == TempState::Undefined {
                 match context {
                     LvalueContext::Store |
@@ -117,18 +119,16 @@ impl<'tcx> Visitor<'tcx> for TempCollector {
         }
     }
 
+    fn visit_source_info(&mut self, source_info: &SourceInfo) {
+        self.span = source_info.span;
+    }
+
     fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
         assert_eq!(self.location.block, bb);
-        self.span = statement.span;
         self.super_statement(bb, statement);
         self.location.statement_index += 1;
     }
 
-    fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) {
-        self.span = terminator.span;
-        self.super_terminator(bb, terminator);
-    }
-
     fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
         self.location.statement_index = 0;
         self.location.block = bb;
@@ -136,9 +136,9 @@ impl<'tcx> Visitor<'tcx> for TempCollector {
     }
 }
 
-pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> Vec<TempState> {
+pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
     let mut collector = TempCollector {
-        temps: vec![TempState::Undefined; mir.temp_decls.len()],
+        temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls),
         location: Location {
             block: START_BLOCK,
             statement_index: 0
@@ -154,7 +154,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> Vec<TempState> {
 struct Promoter<'a, 'tcx: 'a> {
     source: &'a mut Mir<'tcx>,
     promoted: Mir<'tcx>,
-    temps: &'a mut Vec<TempState>,
+    temps: &'a mut IndexVec<Temp, TempState>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -163,34 +163,37 @@ struct Promoter<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> Promoter<'a, 'tcx> {
     fn new_block(&mut self) -> BasicBlock {
-        let index = self.promoted.basic_blocks.len();
-        self.promoted.basic_blocks.push(BasicBlockData {
+        let span = self.promoted.span;
+        self.promoted.basic_blocks_mut().push(BasicBlockData {
             statements: vec![],
             terminator: Some(Terminator {
-                span: self.promoted.span,
-                scope: ScopeId::new(0),
+                source_info: SourceInfo {
+                    span: span,
+                    scope: ARGUMENT_VISIBILITY_SCOPE
+                },
                 kind: TerminatorKind::Return
             }),
             is_cleanup: false
-        });
-        BasicBlock::new(index)
+        })
     }
 
     fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) {
-        let data = self.promoted.basic_blocks.last_mut().unwrap();
+        let last = self.promoted.basic_blocks().last().unwrap();
+        let data = &mut self.promoted[last];
         data.statements.push(Statement {
-            span: span,
-            scope: ScopeId::new(0),
+            source_info: SourceInfo {
+                span: span,
+                scope: ARGUMENT_VISIBILITY_SCOPE
+            },
             kind: StatementKind::Assign(dest, rvalue)
         });
     }
 
     /// Copy the initialization of this temp to the
     /// promoted MIR, recursing through temps.
-    fn promote_temp(&mut self, index: u32) -> u32 {
-        let index = index as usize;
+    fn promote_temp(&mut self, temp: Temp) -> Temp {
         let old_keep_original = self.keep_original;
-        let (bb, stmt_idx) = match self.temps[index] {
+        let (bb, stmt_idx) = match self.temps[temp] {
             TempState::Defined {
                 location: Location { block, statement_index },
                 uses
@@ -200,13 +203,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 }
                 (block, statement_index)
             }
-            temp =>  {
-                span_bug!(self.promoted.span, "tmp{} not promotable: {:?}",
-                          index, temp);
+            state =>  {
+                span_bug!(self.promoted.span, "{:?} not promotable: {:?}",
+                          temp, state);
             }
         };
         if !self.keep_original {
-            self.temps[index] = TempState::PromotedOut;
+            self.temps[temp] = TempState::PromotedOut;
         }
 
         let no_stmts = self.source[bb].statements.len();
@@ -214,7 +217,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         // First, take the Rvalue or Call out of the source MIR,
         // or duplicate it, depending on keep_original.
         let (mut rvalue, mut call) = (None, None);
-        let span = if stmt_idx < no_stmts {
+        let source_info = if stmt_idx < no_stmts {
             let statement = &mut self.source[bb].statements[stmt_idx];
             let StatementKind::Assign(_, ref mut rhs) = statement.kind;
             if self.keep_original {
@@ -223,11 +226,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]);
                 rvalue = Some(mem::replace(rhs, unit));
             }
-            statement.span
+            statement.source_info
         } else if self.keep_original {
             let terminator = self.source[bb].terminator().clone();
             call = Some(terminator.kind);
-            terminator.span
+            terminator.source_info
         } else {
             let terminator = self.source[bb].terminator_mut();
             let target = match terminator.kind {
@@ -242,13 +245,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                     dest.take().unwrap().1
                 }
                 ref kind => {
-                    span_bug!(terminator.span, "{:?} not promotable", kind);
+                    span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
                 }
             };
             call = Some(mem::replace(&mut terminator.kind, TerminatorKind::Goto {
                 target: target
             }));
-            terminator.span
+            terminator.source_info
         };
 
         // Then, recurse for components in the Rvalue or Call.
@@ -258,34 +261,32 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
             self.visit_terminator_kind(bb, call.as_mut().unwrap());
         }
 
-        let new_index = self.promoted.temp_decls.len() as u32;
-        let new_temp = Lvalue::Temp(new_index);
-        self.promoted.temp_decls.push(TempDecl {
-            ty: self.source.temp_decls[index].ty
+        let new_temp = self.promoted.temp_decls.push(TempDecl {
+            ty: self.source.temp_decls[temp].ty
         });
 
         // Inject the Rvalue or Call into the promoted MIR.
         if stmt_idx < no_stmts {
-            self.assign(new_temp, rvalue.unwrap(), span);
+            self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span);
         } else {
-            let last = self.promoted.basic_blocks.len() - 1;
+            let last = self.promoted.basic_blocks().last().unwrap();
             let new_target = self.new_block();
             let mut call = call.unwrap();
             match call {
                 TerminatorKind::Call { ref mut destination, ..}  => {
-                    *destination = Some((new_temp, new_target));
+                    *destination = Some((Lvalue::Temp(new_temp), new_target));
                 }
                 _ => bug!()
             }
-            let terminator = &mut self.promoted.basic_blocks[last].terminator_mut();
-            terminator.span = span;
+            let terminator = self.promoted[last].terminator_mut();
+            terminator.source_info.span = source_info.span;
             terminator.kind = call;
         }
 
         // Restore the old duplication state.
         self.keep_original = old_keep_original;
 
-        new_index
+        new_temp
     }
 
     fn promote_candidate(mut self, candidate: Candidate) {
@@ -294,7 +295,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
             span: span,
             ty: self.promoted.return_ty.unwrap(),
             literal: Literal::Promoted {
-                index: self.source.promoted.len()
+                index: Promoted::new(self.source.promoted.len())
             }
         });
         let mut rvalue = match candidate {
@@ -323,8 +324,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 /// Replaces all temporaries with their promoted counterparts.
 impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
     fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, context: LvalueContext) {
-        if let Lvalue::Temp(ref mut index) = *lvalue {
-            *index = self.promote_temp(*index);
+        if let Lvalue::Temp(ref mut temp) = *lvalue {
+            *temp = self.promote_temp(*temp);
         }
         self.super_lvalue(lvalue, context);
     }
@@ -332,7 +333,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
 
 pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    mut temps: Vec<TempState>,
+                                    mut temps: IndexVec<Temp, TempState>,
                                     candidates: Vec<Candidate>) {
     // Visit candidates in reverse, in case they're nested.
     for candidate in candidates.into_iter().rev() {
@@ -341,12 +342,12 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                 let statement = &mir[bb].statements[stmt_idx];
                 let StatementKind::Assign(ref dest, _) = statement.kind;
                 if let Lvalue::Temp(index) = *dest {
-                    if temps[index as usize] == TempState::PromotedOut {
+                    if temps[index] == TempState::PromotedOut {
                         // Already promoted.
                         continue;
                     }
                 }
-                (statement.span, mir.lvalue_ty(tcx, dest).to_ty(tcx))
+                (statement.source_info.span, mir.lvalue_ty(tcx, dest).to_ty(tcx))
             }
             Candidate::ShuffleIndices(bb) => {
                 let terminator = mir[bb].terminator();
@@ -355,30 +356,30 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                         mir.operand_ty(tcx, &args[2])
                     }
                     _ => {
-                        span_bug!(terminator.span,
+                        span_bug!(terminator.source_info.span,
                                   "expected simd_shuffleN call to promote");
                     }
                 };
-                (terminator.span, ty)
+                (terminator.source_info.span, ty)
             }
         };
 
         let mut promoter = Promoter {
             source: mir,
-            promoted: Mir {
-                basic_blocks: vec![],
-                scopes: vec![ScopeData {
+            promoted: Mir::new(
+                IndexVec::new(),
+                Some(VisibilityScopeData {
                     span: span,
                     parent_scope: None
-                }],
-                promoted: vec![],
-                return_ty: ty::FnConverging(ty),
-                var_decls: vec![],
-                arg_decls: vec![],
-                temp_decls: vec![],
-                upvar_decls: vec![],
-                span: span
-            },
+                }).into_iter().collect(),
+                IndexVec::new(),
+                ty::FnConverging(ty),
+                IndexVec::new(),
+                IndexVec::new(),
+                IndexVec::new(),
+                vec![],
+                span
+            ),
             temps: &mut temps,
             keep_original: false
         };
@@ -387,8 +388,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
     }
 
     // Eliminate assignments to, and drops of promoted temps.
-    let promoted = |index: u32| temps[index as usize] == TempState::PromotedOut;
-    for block in &mut mir.basic_blocks {
+    let promoted = |index: Temp| temps[index] == TempState::PromotedOut;
+    for block in mir.basic_blocks_mut() {
         block.statements.retain(|statement| {
             match statement.kind {
                 StatementKind::Assign(Lvalue::Temp(index), _) => {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index b9eec6ecd9c..784ddc1ede4 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -15,6 +15,7 @@
 //! diagnostics as to why a constant rvalue wasn't promoted.
 
 use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::FnKind;
@@ -24,7 +25,8 @@ use rustc::ty::{self, TyCtxt, Ty};
 use rustc::ty::cast::CastTy;
 use rustc::mir::repr::*;
 use rustc::mir::mir_map::MirMap;
-use rustc::mir::transform::{Pass, MirMapPass, MirSource};
+use rustc::mir::traversal::{self, ReversePostorder};
+use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource};
 use rustc::mir::visit::{LvalueContext, Visitor};
 use rustc::util::nodemap::DefIdMap;
 use syntax::abi::Abi;
@@ -35,7 +37,6 @@ use std::collections::hash_map::Entry;
 use std::fmt;
 
 use build::Location;
-use traversal::{self, ReversePostorder};
 
 use super::promote_consts::{self, Candidate, TempState};
 
@@ -141,12 +142,12 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     param_env: ty::ParameterEnvironment<'tcx>,
     qualif_map: &'a mut DefIdMap<Qualif>,
     mir_map: Option<&'a MirMap<'tcx>>,
-    temp_qualif: Vec<Option<Qualif>>,
+    temp_qualif: IndexVec<Temp, Option<Qualif>>,
     return_qualif: Option<Qualif>,
     qualif: Qualif,
     const_fn_arg_vars: BitVector,
     location: Location,
-    temp_promotion_state: Vec<TempState>,
+    temp_promotion_state: IndexVec<Temp, TempState>,
     promotion_candidates: Vec<Candidate>
 }
 
@@ -172,7 +173,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             param_env: param_env,
             qualif_map: qualif_map,
             mir_map: mir_map,
-            temp_qualif: vec![None; mir.temp_decls.len()],
+            temp_qualif: IndexVec::from_elem(None, &mir.temp_decls),
             return_qualif: None,
             qualif: Qualif::empty(),
             const_fn_arg_vars: BitVector::new(mir.var_decls.len()),
@@ -301,22 +302,22 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
         // Only handle promotable temps in non-const functions.
         if self.mode == Mode::Fn {
             if let Lvalue::Temp(index) = *dest {
-                if self.temp_promotion_state[index as usize].is_promotable() {
-                    store(&mut self.temp_qualif[index as usize]);
+                if self.temp_promotion_state[index].is_promotable() {
+                    store(&mut self.temp_qualif[index]);
                 }
             }
             return;
         }
 
         match *dest {
-            Lvalue::Temp(index) => store(&mut self.temp_qualif[index as usize]),
+            Lvalue::Temp(index) => store(&mut self.temp_qualif[index]),
             Lvalue::ReturnPointer => store(&mut self.return_qualif),
 
             Lvalue::Projection(box Projection {
                 base: Lvalue::Temp(index),
                 elem: ProjectionElem::Deref
-            }) if self.mir.temp_decls[index as usize].ty.is_unique()
-               && self.temp_qualif[index as usize].map_or(false, |qualif| {
+            }) if self.mir.temp_decls[index].ty.is_unique()
+               && self.temp_qualif[index].map_or(false, |qualif| {
                     qualif.intersects(Qualif::NOT_CONST)
                }) => {
                 // Part of `box expr`, we should've errored
@@ -336,7 +337,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
     fn qualify_const(&mut self) -> Qualif {
         let mir = self.mir;
 
-        let mut seen_blocks = BitVector::new(mir.basic_blocks.len());
+        let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
         let mut bb = START_BLOCK;
         loop {
             seen_blocks.insert(bb.index());
@@ -361,27 +362,29 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                 TerminatorKind::Switch {..} |
                 TerminatorKind::SwitchInt {..} |
                 TerminatorKind::DropAndReplace { .. } |
-                TerminatorKind::Resume => None,
+                TerminatorKind::Resume |
+                TerminatorKind::Unreachable => None,
 
                 TerminatorKind::Return => {
                     // Check for unused values. This usually means
                     // there are extra statements in the AST.
-                    for i in 0..mir.temp_decls.len() {
-                        if self.temp_qualif[i].is_none() {
+                    for temp in mir.temp_decls.indices() {
+                        if self.temp_qualif[temp].is_none() {
                             continue;
                         }
 
-                        let state = self.temp_promotion_state[i];
+                        let state = self.temp_promotion_state[temp];
                         if let TempState::Defined { location, uses: 0 } = state {
                             let data = &mir[location.block];
                             let stmt_idx = location.statement_index;
 
                             // Get the span for the initialization.
-                            if stmt_idx < data.statements.len() {
-                                self.span = data.statements[stmt_idx].span;
+                            let source_info = if stmt_idx < data.statements.len() {
+                                data.statements[stmt_idx].source_info
                             } else {
-                                self.span = data.terminator().span;
-                            }
+                                data.terminator().source_info
+                            };
+                            self.span = source_info.span;
 
                             // Treat this as a statement in the AST.
                             self.statement_like();
@@ -392,7 +395,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                     self.qualif = Qualif::NOT_CONST;
                     for index in 0..mir.var_decls.len() {
                         if !self.const_fn_arg_vars.contains(index) {
-                            self.assign(&Lvalue::Var(index as u32));
+                            self.assign(&Lvalue::Var(Var::new(index)));
                         }
                     }
 
@@ -447,11 +450,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 self.add(Qualif::NOT_CONST);
             }
             Lvalue::Temp(index) => {
-                if !self.temp_promotion_state[index as usize].is_promotable() {
+                if !self.temp_promotion_state[index].is_promotable() {
                     self.add(Qualif::NOT_PROMOTABLE);
                 }
 
-                if let Some(qualif) = self.temp_qualif[index as usize] {
+                if let Some(qualif) = self.temp_qualif[index] {
                     self.add(qualif);
                 } else {
                     self.not_const();
@@ -508,6 +511,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                         }
 
                         ProjectionElem::ConstantIndex {..} |
+                        ProjectionElem::Subslice {..} |
                         ProjectionElem::Downcast(..) => {
                             this.not_const()
                         }
@@ -707,7 +711,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 }
             }
 
-            Rvalue::Slice {..} |
             Rvalue::InlineAsm {..} => {
                 self.not_const();
             }
@@ -821,7 +824,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
 
         // Check the allowed const fn argument forms.
         if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) {
-            if self.const_fn_arg_vars.insert(index as usize) {
+            if self.const_fn_arg_vars.insert(index.index()) {
                 // Direct use of an argument is permitted.
                 if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue {
                     return;
@@ -829,8 +832,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
 
                 // Avoid a generic error for other uses of arguments.
                 if self.qualif.intersects(Qualif::FN_ARGUMENT) {
-                    let decl = &self.mir.var_decls[index as usize];
-                    span_err!(self.tcx.sess, decl.span, E0022,
+                    let decl = &self.mir.var_decls[index];
+                    span_err!(self.tcx.sess, decl.source_info.span, E0022,
                               "arguments of constant functions can only \
                                be immutable by-value bindings");
                     return;
@@ -841,16 +844,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
         self.assign(dest);
     }
 
+    fn visit_source_info(&mut self, source_info: &SourceInfo) {
+        self.span = source_info.span;
+    }
+
     fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
         assert_eq!(self.location.block, bb);
-        self.span = statement.span;
         self.nest(|this| this.super_statement(bb, statement));
         self.location.statement_index += 1;
     }
 
     fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) {
         assert_eq!(self.location.block, bb);
-        self.span = terminator.span;
         self.nest(|this| this.super_terminator(bb, terminator));
     }
 
@@ -904,7 +909,10 @@ pub struct QualifyAndPromoteConstants;
 impl Pass for QualifyAndPromoteConstants {}
 
 impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
-    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) {
+    fn run_pass<'a>(&mut self,
+                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    map: &mut MirMap<'tcx>,
+                    hooks: &mut [Box<for<'s> MirPassHook<'s>>]) {
         let mut qualif_map = DefIdMap();
 
         // First, visit `const` items, potentially recursing, to get
@@ -940,6 +948,10 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
             };
             let param_env = ty::ParameterEnvironment::for_item(tcx, id);
 
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, false);
+            }
+
             if mode == Mode::Fn || mode == Mode::ConstFn {
                 // This is ugly because Qualifier holds onto mir,
                 // which can't be mutated until its scope ends.
@@ -967,6 +979,10 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
                 qualifier.qualify_const();
             }
 
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, true);
+            }
+
             // Statics must be Sync.
             if mode == Mode::Static {
                 let ty = mir.return_ty.unwrap();
diff --git a/src/librustc_mir/transform/remove_dead_blocks.rs b/src/librustc_mir/transform/remove_dead_blocks.rs
deleted file mode 100644
index 44f3ce7361c..00000000000
--- a/src/librustc_mir/transform/remove_dead_blocks.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A pass that erases the contents of dead blocks. This pass must
-//! run before any analysis passes because some of the dead blocks
-//! can be ill-typed.
-//!
-//! The main problem is that typeck lets most blocks whose end is not
-//! reachable have an arbitrary return type, rather than having the
-//! usual () return type (as a note, typeck's notion of reachability
-//! is in fact slightly weaker than MIR CFG reachability - see #31617).
-//!
-//! A standard example of the situation is:
-//! ```rust
-//!   fn example() {
-//!       let _a: char = { return; };
-//!   }
-//! ```
-//!
-//! Here the block (`{ return; }`) has the return type `char`,
-//! rather than `()`, but the MIR we naively generate still contains
-//! the `_a = ()` write in the unreachable block "after" the return.
-//!
-//! As we have to run this pass even when we want to debug the MIR,
-//! this pass just replaces the blocks with empty "return" blocks
-//! and does not renumber anything.
-
-use rustc_data_structures::bitvec::BitVector;
-use rustc::ty::TyCtxt;
-use rustc::mir::repr::*;
-use rustc::mir::transform::{Pass, MirPass, MirSource};
-
-pub struct RemoveDeadBlocks;
-
-impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks {
-    fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>,
-                    _: MirSource, mir: &mut Mir<'tcx>) {
-        let mut seen = BitVector::new(mir.basic_blocks.len());
-        // This block is always required.
-        seen.insert(START_BLOCK.index());
-
-        let mut worklist = Vec::with_capacity(4);
-        worklist.push(START_BLOCK);
-        while let Some(bb) = worklist.pop() {
-            for succ in mir.basic_block_data(bb).terminator().successors().iter() {
-                if seen.insert(succ.index()) {
-                    worklist.push(*succ);
-                }
-            }
-        }
-        retain_basic_blocks(mir, &seen);
-    }
-}
-
-impl Pass for RemoveDeadBlocks {}
-
-/// Mass removal of basic blocks to keep the ID-remapping cheap.
-fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) {
-    let num_blocks = mir.basic_blocks.len();
-
-    let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
-    let mut used_blocks = 0;
-    for alive_index in keep.iter() {
-        replacements[alive_index] = BasicBlock::new(used_blocks);
-        if alive_index != used_blocks {
-            // Swap the next alive block data with the current available slot. Since alive_index is
-            // non-decreasing this is a valid operation.
-            mir.basic_blocks.swap(alive_index, used_blocks);
-        }
-        used_blocks += 1;
-    }
-    mir.basic_blocks.truncate(used_blocks);
-
-    for bb in mir.all_basic_blocks() {
-        for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
-            *target = replacements[target.index()];
-        }
-    }
-}
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
new file mode 100644
index 00000000000..b4960c677a1
--- /dev/null
+++ b/src/librustc_mir/transform/simplify_branches.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.
+
+//! A pass that simplifies branches when their condition is known.
+
+use rustc::ty::TyCtxt;
+use rustc::middle::const_val::ConstVal;
+use rustc::mir::transform::{MirPass, MirSource, Pass};
+use rustc::mir::repr::*;
+
+use std::fmt;
+
+pub struct SimplifyBranches<'a> { label: &'a str }
+
+impl<'a> SimplifyBranches<'a> {
+    pub fn new(label: &'a str) -> Self {
+        SimplifyBranches { label: label }
+    }
+}
+
+impl<'l, 'tcx> MirPass<'tcx> for SimplifyBranches<'l> {
+    fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
+        for block in mir.basic_blocks_mut() {
+            let terminator = block.terminator_mut();
+            terminator.kind = match terminator.kind {
+                TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
+                    literal: Literal::Value {
+                        value: ConstVal::Bool(cond)
+                    }, ..
+                }) } => {
+                    if cond {
+                        TerminatorKind::Goto { target: targets.0 }
+                    } else {
+                        TerminatorKind::Goto { target: targets.1 }
+                    }
+                }
+
+                TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
+                    literal: Literal::Value {
+                        value: ConstVal::Bool(cond)
+                    }, ..
+                }), expected, .. } if cond == expected => {
+                    TerminatorKind::Goto { target: target }
+                }
+
+                _ => continue
+            };
+        }
+    }
+}
+
+impl<'l> Pass for SimplifyBranches<'l> {
+    fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> {
+        Some(Box::new(self.label))
+    }
+
+    // avoid calling `type_name` - it contains `<'static>`
+    fn name(&self) -> &str { "SimplifyBranches" }
+}
diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs
index d008918026a..c0e7e54050a 100644
--- a/src/librustc_mir/transform/simplify_cfg.rs
+++ b/src/librustc_mir/transform/simplify_cfg.rs
@@ -8,198 +8,242 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! A pass that removes various redundancies in the CFG. It should be
+//! called after every significant CFG modification to tidy things
+//! up.
+//!
+//! This pass must also be run before any analysis passes because it removes
+//! dead blocks, and some of these can be ill-typed.
+//!
+//! The cause of that is that typeck lets most blocks whose end is not
+//! reachable have an arbitrary return type, rather than having the
+//! usual () return type (as a note, typeck's notion of reachability
+//! is in fact slightly weaker than MIR CFG reachability - see #31617).
+//!
+//! A standard example of the situation is:
+//! ```rust
+//!   fn example() {
+//!       let _a: char = { return; };
+//!   }
+//! ```
+//!
+//! Here the block (`{ return; }`) has the return type `char`,
+//! rather than `()`, but the MIR we naively generate still contains
+//! the `_a = ()` write in the unreachable block "after" the return.
+
+
 use rustc_data_structures::bitvec::BitVector;
-use rustc::middle::const_val::ConstVal;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
 use rustc::mir::transform::{MirPass, MirSource, Pass};
-use pretty;
-use std::mem;
-
-use super::remove_dead_blocks::RemoveDeadBlocks;
+use rustc::mir::traversal;
+use std::fmt;
 
-use traversal;
+pub struct SimplifyCfg<'a> { label: &'a str }
 
-pub struct SimplifyCfg;
-
-impl SimplifyCfg {
-    pub fn new() -> SimplifyCfg {
-        SimplifyCfg
+impl<'a> SimplifyCfg<'a> {
+    pub fn new(label: &'a str) -> Self {
+        SimplifyCfg { label: label }
     }
 }
 
-impl<'tcx> MirPass<'tcx> for SimplifyCfg {
-    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
-        simplify_branches(mir);
-        RemoveDeadBlocks.run_pass(tcx, src, mir);
-        merge_consecutive_blocks(mir);
-        RemoveDeadBlocks.run_pass(tcx, src, mir);
-        pretty::dump_mir(tcx, "simplify_cfg", &0, src, mir, None);
+impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> {
+    fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
+        CfgSimplifier::new(mir).simplify();
+        remove_dead_blocks(mir);
 
         // FIXME: Should probably be moved into some kind of pass manager
-        mir.basic_blocks.shrink_to_fit();
+        mir.basic_blocks_mut().raw.shrink_to_fit();
+    }
+}
+
+impl<'l> Pass for SimplifyCfg<'l> {
+    fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> {
+        Some(Box::new(self.label))
     }
+
+    // avoid calling `type_name` - it contains `<'static>`
+    fn name(&self) -> &str { "SimplifyCfg" }
+}
+
+pub struct CfgSimplifier<'a, 'tcx: 'a> {
+    basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+    pred_count: IndexVec<BasicBlock, u32>
 }
 
-impl Pass for SimplifyCfg {}
+impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
+    fn new(mir: &'a mut Mir<'tcx>) -> Self {
+        let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks());
 
-fn merge_consecutive_blocks(mir: &mut Mir) {
-    // Build the precedecessor map for the MIR
-    let mut pred_count = vec![0u32; mir.basic_blocks.len()];
-    for (_, data) in traversal::preorder(mir) {
-        if let Some(ref term) = data.terminator {
-            for &tgt in term.successors().iter() {
-                pred_count[tgt.index()] += 1;
+        // we can't use mir.predecessors() here because that counts
+        // dead blocks, which we don't want to.
+        for (_, data) in traversal::preorder(mir) {
+            if let Some(ref term) = data.terminator {
+                for &tgt in term.successors().iter() {
+                    pred_count[tgt] += 1;
+                }
             }
         }
+
+        let basic_blocks = mir.basic_blocks_mut();
+
+        CfgSimplifier {
+            basic_blocks: basic_blocks,
+            pred_count: pred_count
+        }
     }
 
-    loop {
-        let mut changed = false;
-        let mut seen = BitVector::new(mir.basic_blocks.len());
-        let mut worklist = vec![START_BLOCK];
-        while let Some(bb) = worklist.pop() {
-            // Temporarily take ownership of the terminator we're modifying to keep borrowck happy
-            let mut terminator = mir.basic_block_data_mut(bb).terminator.take()
-                .expect("invalid terminator state");
-
-            // See if we can merge the target block into this one
-            loop {
-                let mut inner_change = false;
-
-                if let TerminatorKind::Goto { target } = terminator.kind {
-                    // Don't bother trying to merge a block into itself
-                    if target == bb {
-                        break;
-                    }
-
-                    let num_insts = mir.basic_block_data(target).statements.len();
-                    match mir.basic_block_data(target).terminator().kind {
-                        TerminatorKind::Goto { target: new_target } if num_insts == 0 => {
-                            inner_change = true;
-                            terminator.kind = TerminatorKind::Goto { target: new_target };
-                            pred_count[target.index()] -= 1;
-                            pred_count[new_target.index()] += 1;
-                        }
-                        _ if pred_count[target.index()] == 1 => {
-                            inner_change = true;
-                            let mut stmts = Vec::new();
-                            {
-                                let target_data = mir.basic_block_data_mut(target);
-                                mem::swap(&mut stmts, &mut target_data.statements);
-                                mem::swap(&mut terminator, target_data.terminator_mut());
-                            }
-
-                            mir.basic_block_data_mut(bb).statements.append(&mut stmts);
-                        }
-                        _ => {}
-                    };
+    fn simplify(mut self) {
+        loop {
+            let mut changed = false;
+
+            for bb in (0..self.basic_blocks.len()).map(BasicBlock::new) {
+                if self.pred_count[bb] == 0 {
+                    continue
                 }
 
-                for target in terminator.successors_mut() {
-                    let new_target = match final_target(mir, *target) {
-                        Some(new_target) => new_target,
-                        None if mir.basic_block_data(bb).statements.is_empty() => bb,
-                        None => continue
-                    };
-                    if *target != new_target {
-                        inner_change = true;
-                        pred_count[target.index()] -= 1;
-                        pred_count[new_target.index()] += 1;
-                        *target = new_target;
-                    }
+                debug!("simplifying {:?}", bb);
+
+                let mut terminator = self.basic_blocks[bb].terminator.take()
+                    .expect("invalid terminator state");
+
+                for successor in terminator.successors_mut() {
+                    self.collapse_goto_chain(successor, &mut changed);
                 }
 
-                changed |= inner_change;
-                if !inner_change {
-                    break;
+                let mut new_stmts = vec![];
+                let mut inner_changed = true;
+                while inner_changed {
+                    inner_changed = false;
+                    inner_changed |= self.simplify_branch(&mut terminator);
+                    inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator);
+                    changed |= inner_changed;
                 }
-            }
 
-            mir.basic_block_data_mut(bb).terminator = Some(terminator);
+                self.basic_blocks[bb].statements.extend(new_stmts);
+                self.basic_blocks[bb].terminator = Some(terminator);
 
-            for succ in mir.basic_block_data(bb).terminator().successors().iter() {
-                if seen.insert(succ.index()) {
-                    worklist.push(*succ);
-                }
+                changed |= inner_changed;
             }
-        }
 
-        if !changed {
-            break;
+            if !changed { break }
         }
     }
-}
 
-// Find the target at the end of the jump chain, return None if there is a loop
-fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
-    // Keep track of already seen blocks to detect loops
-    let mut seen: Vec<BasicBlock> = Vec::with_capacity(8);
-
-    while mir.basic_block_data(target).statements.is_empty() {
-        // NB -- terminator may have been swapped with `None` in
-        // merge_consecutive_blocks, in which case we have a cycle and just want
-        // to stop
-        match mir.basic_block_data(target).terminator {
-            Some(Terminator { kind: TerminatorKind::Goto { target: next }, .. }) =>  {
-                if seen.contains(&next) {
-                    return None;
-                }
-                seen.push(next);
-                target = next;
+    // Collapse a goto chain starting from `start`
+    fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) {
+        let mut terminator = match self.basic_blocks[*start] {
+            BasicBlockData {
+                ref statements,
+                terminator: ref mut terminator @ Some(Terminator {
+                    kind: TerminatorKind::Goto { .. }, ..
+                }), ..
+            } if statements.is_empty() => terminator.take(),
+            // if `terminator` is None, this means we are in a loop. In that
+            // case, let all the loop collapse to its entry.
+            _ => return
+        };
+
+        let target = match terminator {
+            Some(Terminator { kind: TerminatorKind::Goto { ref mut target }, .. }) => {
+                self.collapse_goto_chain(target, changed);
+                *target
             }
-            _ => break
-        }
-    }
+            _ => unreachable!()
+        };
+        self.basic_blocks[*start].terminator = terminator;
 
-    Some(target)
-}
+        debug!("collapsing goto chain from {:?} to {:?}", *start, target);
 
-fn simplify_branches(mir: &mut Mir) {
-    loop {
-        let mut changed = false;
-
-        for bb in mir.all_basic_blocks() {
-            let basic_block = mir.basic_block_data_mut(bb);
-            let mut terminator = basic_block.terminator_mut();
-            terminator.kind = match terminator.kind {
-                TerminatorKind::If { ref targets, .. } if targets.0 == targets.1 => {
-                    changed = true;
-                    TerminatorKind::Goto { target: targets.0 }
-                }
+        *changed |= *start != target;
+        self.pred_count[target] += 1;
+        self.pred_count[*start] -= 1;
+        *start = target;
+    }
 
-                TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
-                    literal: Literal::Value {
-                        value: ConstVal::Bool(cond)
-                    }, ..
-                }) } => {
-                    changed = true;
-                    if cond {
-                        TerminatorKind::Goto { target: targets.0 }
-                    } else {
-                        TerminatorKind::Goto { target: targets.1 }
-                    }
-                }
+    // merge a block with 1 `goto` predecessor to its parent
+    fn merge_successor(&mut self,
+                       new_stmts: &mut Vec<Statement<'tcx>>,
+                       terminator: &mut Terminator<'tcx>)
+                       -> bool
+    {
+        let target = match terminator.kind {
+            TerminatorKind::Goto { target }
+                if self.pred_count[target] == 1
+                => target,
+            _ => return false
+        };
+
+        debug!("merging block {:?} into {:?}", target, terminator);
+        *terminator = match self.basic_blocks[target].terminator.take() {
+            Some(terminator) => terminator,
+            None => {
+                // unreachable loop - this should not be possible, as we
+                // don't strand blocks, but handle it correctly.
+                return false
+            }
+        };
+        new_stmts.extend(self.basic_blocks[target].statements.drain(..));
+        self.pred_count[target] = 0;
 
-                TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
-                    literal: Literal::Value {
-                        value: ConstVal::Bool(cond)
-                    }, ..
-                }), expected, .. } if cond == expected => {
-                    changed = true;
-                    TerminatorKind::Goto { target: target }
-                }
+        true
+    }
 
-                TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => {
-                    changed = true;
-                    TerminatorKind::Goto { target: targets[0] }
+    // turn a branch with all successors identical to a goto
+    fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
+        match terminator.kind {
+            TerminatorKind::If { .. } |
+            TerminatorKind::Switch { .. } |
+            TerminatorKind::SwitchInt { .. } => {},
+            _ => return false
+        };
+
+        let first_succ = {
+            let successors = terminator.successors();
+            if let Some(&first_succ) = terminator.successors().get(0) {
+                if successors.iter().all(|s| *s == first_succ) {
+                    self.pred_count[first_succ] -= (successors.len()-1) as u32;
+                    first_succ
+                } else {
+                    return false
                 }
-                _ => continue
+            } else {
+                return false
             }
+        };
+
+        debug!("simplifying branch {:?}", terminator);
+        terminator.kind = TerminatorKind::Goto { target: first_succ };
+        true
+    }
+}
+
+fn remove_dead_blocks(mir: &mut Mir) {
+    let mut seen = BitVector::new(mir.basic_blocks().len());
+    for (bb, _) in traversal::preorder(mir) {
+        seen.insert(bb.index());
+    }
+
+    let basic_blocks = mir.basic_blocks_mut();
+
+    let num_blocks = basic_blocks.len();
+    let mut replacements : Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
+    let mut used_blocks = 0;
+    for alive_index in seen.iter() {
+        replacements[alive_index] = BasicBlock::new(used_blocks);
+        if alive_index != used_blocks {
+            // Swap the next alive block data with the current available slot. Since alive_index is
+            // non-decreasing this is a valid operation.
+            basic_blocks.raw.swap(alive_index, used_blocks);
         }
+        used_blocks += 1;
+    }
+    basic_blocks.raw.truncate(used_blocks);
 
-        if !changed {
-            break;
+    for block in basic_blocks {
+        for target in block.terminator_mut().successors_mut() {
+            *target = replacements[target.index()];
         }
     }
 }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 019ed670d1f..e4398fcab31 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -24,6 +24,8 @@ use rustc::mir::visit::{self, Visitor};
 use std::fmt;
 use syntax::codemap::{Span, DUMMY_SP};
 
+use rustc_data_structures::indexed_vec::Idx;
+
 macro_rules! span_mirbug {
     ($context:expr, $elem:expr, $($message:tt)*) => ({
         $context.tcx().sess.span_warn(
@@ -129,11 +131,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
     fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> {
         debug!("sanitize_lvalue: {:?}", lvalue);
         match *lvalue {
-            Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index as usize].ty },
-            Lvalue::Temp(index) =>
-                LvalueTy::Ty { ty: self.mir.temp_decls[index as usize].ty },
-            Lvalue::Arg(index) =>
-                LvalueTy::Ty { ty: self.mir.arg_decls[index as usize].ty },
+            Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty },
+            Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty },
+            Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty },
             Lvalue::Static(def_id) =>
                 LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
             Lvalue::ReturnPointer => {
@@ -203,6 +203,26 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                     })
                 }
             }
+            ProjectionElem::Subslice { from, to } => {
+                LvalueTy::Ty {
+                    ty: match base_ty.sty {
+                        ty::TyArray(inner, size) => {
+                            let min_size = (from as usize) + (to as usize);
+                            if let Some(rest_size) = size.checked_sub(min_size) {
+                                tcx.mk_array(inner, rest_size)
+                            } else {
+                                span_mirbug_and_err!(
+                                    self, lvalue, "taking too-small slice of {:?}", base_ty)
+                            }
+                        }
+                        ty::TySlice(..) => base_ty,
+                        _ => {
+                            span_mirbug_and_err!(
+                                self, lvalue, "slice of non-array {:?}", base_ty)
+                        }
+                    }
+                }
+            }
             ProjectionElem::Downcast(adt_def1, index) =>
                 match base_ty.sty {
                     ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => {
@@ -359,6 +379,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             TerminatorKind::Goto { .. } |
             TerminatorKind::Resume |
             TerminatorKind::Return |
+            TerminatorKind::Unreachable |
             TerminatorKind::Drop { .. } => {
                 // no checks needed for these
             }
@@ -551,7 +572,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>)
     {
         let is_cleanup = block.is_cleanup;
-        self.last_span = block.terminator().span;
+        self.last_span = block.terminator().source_info.span;
         match block.terminator().kind {
             TerminatorKind::Goto { target } =>
                 self.assert_iscleanup(mir, block, target, is_cleanup),
@@ -575,6 +596,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     span_mirbug!(self, block, "return on cleanup block")
                 }
             }
+            TerminatorKind::Unreachable => {}
             TerminatorKind::Drop { target, unwind, .. } |
             TerminatorKind::DropAndReplace { target, unwind, .. } |
             TerminatorKind::Assert { target, cleanup: unwind, .. } => {
@@ -606,7 +628,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         bb: BasicBlock,
                         iscleanuppad: bool)
     {
-        if mir.basic_block_data(bb).is_cleanup != iscleanuppad {
+        if mir[bb].is_cleanup != iscleanuppad {
             span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}",
                          bb, iscleanuppad);
         }
@@ -615,10 +637,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
         self.last_span = mir.span;
         debug!("run_on_mir: {:?}", mir.span);
-        for block in &mir.basic_blocks {
+        for block in mir.basic_blocks() {
             for stmt in &block.statements {
-                if stmt.span != DUMMY_SP {
-                    self.last_span = stmt.span;
+                if stmt.source_info.span != DUMMY_SP {
+                    self.last_span = stmt.source_info.span;
                 }
                 self.check_stmt(mir, stmt);
             }
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index b1bb48aacee..75bfe7c0f2f 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -499,38 +499,36 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
             }
         }
         hir::ExprPath(..) => {
-            let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
-            match def {
-                Some(Def::Variant(..)) => {
+            match v.tcx.expect_def(e.id) {
+                Def::Variant(..) => {
                     // Count the discriminator or function pointer.
                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
                 }
-                Some(Def::Struct(..)) => {
+                Def::Struct(..) => {
                     if let ty::TyFnDef(..) = node_ty.sty {
                         // Count the function pointer.
                         v.add_qualif(ConstQualif::NON_ZERO_SIZED);
                     }
                 }
-                Some(Def::Fn(..)) | Some(Def::Method(..)) => {
+                Def::Fn(..) | Def::Method(..) => {
                     // Count the function pointer.
                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
                 }
-                Some(Def::Static(..)) => {
+                Def::Static(..) => {
                     match v.mode {
                         Mode::Static | Mode::StaticMut => {}
                         Mode::Const | Mode::ConstFn => {}
                         Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
                     }
                 }
-                Some(Def::Const(did)) |
-                Some(Def::AssociatedConst(did)) => {
+                Def::Const(did) | Def::AssociatedConst(did) => {
                     let substs = Some(v.tcx.node_id_item_substs(e.id).substs);
                     if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
                         let inner = v.global_expr(Mode::Const, expr);
                         v.add_qualif(inner);
                     }
                 }
-                Some(Def::Local(..)) if v.mode == Mode::ConstFn => {
+                Def::Local(..) if v.mode == Mode::ConstFn => {
                     // Sadly, we can't determine whether the types are zero-sized.
                     v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
                 }
@@ -550,8 +548,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                     _ => break
                 };
             }
-            let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
-            let is_const = match def {
+            // The callee is an arbitrary expression, it doesn't necessarily have a definition.
+            let is_const = match v.tcx.expect_def_or_none(callee.id) {
                 Some(Def::Struct(..)) => true,
                 Some(Def::Variant(..)) => {
                     // Count the discriminator.
@@ -586,8 +584,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
             }
         }
         hir::ExprStruct(..) => {
-            let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
-            if did == v.tcx.lang_items.unsafe_cell_type() {
+            // unsafe_cell_type doesn't necessarily exist with no_core
+            if Some(v.tcx.expect_def(e.id).def_id()) == v.tcx.lang_items.unsafe_cell_type() {
                 v.add_qualif(ConstQualif::MUTABLE_MEM);
             }
         }
diff --git a/src/librustc_plugin/Cargo.toml b/src/librustc_plugin/Cargo.toml
index e9a32e53a9f..6acd1e76ff2 100644
--- a/src/librustc_plugin/Cargo.toml
+++ b/src/librustc_plugin/Cargo.toml
@@ -14,5 +14,4 @@ rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
 rustc_metadata = { path = "../librustc_metadata" }
-rustc_mir = { path = "../librustc_mir" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs
index 5fa29771c57..7ef628e8f9b 100644
--- a/src/librustc_plugin/lib.rs
+++ b/src/librustc_plugin/lib.rs
@@ -70,7 +70,6 @@
 extern crate rustc;
 extern crate rustc_back;
 extern crate rustc_metadata;
-extern crate rustc_mir;
 
 pub use self::registry::Registry;
 
diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/diagnostics.rs
index 36ece929413..66afe5835bf 100644
--- a/src/librustc_privacy/diagnostics.rs
+++ b/src/librustc_privacy/diagnostics.rs
@@ -16,7 +16,7 @@ E0445: r##"
 A private trait was used on a public type parameter bound. Erroneous code
 examples:
 
-```compile_fail
+```compile_fail,E0445
 #![deny(private_in_public)]
 
 trait Foo {
@@ -46,7 +46,7 @@ pub fn foo<T: Foo> (t: T) {} // ok!
 E0446: r##"
 A private type was used in a public type signature. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0446
 #![deny(private_in_public)]
 
 mod Foo {
@@ -100,7 +100,7 @@ pub enum Foo {
 Since the enum is already public, adding `pub` on one its elements is
 unnecessary. Example:
 
-```compile_fail
+```compile_fail,
 enum Foo {
     pub Bar, // not ok!
 }
@@ -119,7 +119,7 @@ E0450: r##"
 A tuple constructor was invoked while some of its fields are private. Erroneous
 code example:
 
-```compile_fail
+```compile_fail,E0450
 mod Bar {
     pub struct Foo(isize);
 }
@@ -157,7 +157,7 @@ let f = bar::Foo::new(1);
 E0451: r##"
 A struct constructor with private fields was invoked. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0451
 mod Bar {
     pub struct Foo {
         pub a: isize,
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 7e76842a9f4..918c149ef85 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -65,7 +65,7 @@ struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
 impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
     fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
         if let hir::TyPath(..) = ty.node {
-            match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
+            match self.tcx.expect_def(ty.id) {
                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
                     Some(AccessLevel::Public)
                 }
@@ -83,7 +83,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
     }
 
     fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
-        let did = self.tcx.trait_ref_to_def_id(trait_ref);
+        let did = self.tcx.expect_def(trait_ref.ref_id).def_id();
         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
             self.get(node_id)
         } else {
@@ -317,7 +317,7 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
 impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     fn visit_ty(&mut self, ty: &hir::Ty) {
         if let hir::TyPath(_, ref path) = ty.node {
-            let def = self.ev.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
+            let def = self.ev.tcx.expect_def(ty.id);
             match def {
                 Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
                 Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
@@ -343,7 +343,7 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<
     }
 
     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
-        let def_id = self.ev.tcx.trait_ref_to_def_id(trait_ref);
+        let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id();
         if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
             let item = self.ev.tcx.map.expect_item(node_id);
             self.ev.update(item.id, Some(AccessLevel::Reachable));
@@ -426,7 +426,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
             }
             hir::ExprStruct(..) => {
                 let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
-                let variant = adt.variant_of_def(self.tcx.resolve_expr(expr));
+                let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
                 // (i.e. `all_fields - fields`), just check them all.
@@ -436,7 +436,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
             }
             hir::ExprPath(..) => {
 
-                if let Def::Struct(..) = self.tcx.resolve_expr(expr) {
+                if let Def::Struct(..) = self.tcx.expect_def(expr.id) {
                     let expr_ty = self.tcx.expr_ty(expr);
                     let def = match expr_ty.sty {
                         ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
@@ -470,8 +470,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
         match pattern.node {
             PatKind::Struct(_, ref fields, _) => {
                 let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap();
-                let def = self.tcx.def_map.borrow().get(&pattern.id).unwrap().full_def();
-                let variant = adt.variant_of_def(def);
+                let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id));
                 for field in fields {
                     self.check_field(pattern.span, adt, variant.field_named(field.node.name));
                 }
@@ -534,10 +533,9 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
 
 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
-        let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
-            // `int` etc. (None doesn't seem to occur.)
-            None | Some(Def::PrimTy(..)) | Some(Def::SelfTy(..)) => return false,
-            Some(def) => def.def_id(),
+        let did = match self.tcx.expect_def(path_id) {
+            Def::PrimTy(..) | Def::SelfTy(..) => return false,
+            def => def.def_id(),
         };
 
         // A path can only be private if:
@@ -653,7 +651,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
                 let not_private_trait =
                     trait_ref.as_ref().map_or(true, // no trait counts as public trait
                                               |tr| {
-                        let did = self.tcx.trait_ref_to_def_id(tr);
+                        let did = self.tcx.expect_def(tr.ref_id).def_id();
 
                         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
                             self.trait_is_public(node_id)
@@ -911,8 +909,7 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
 impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     fn visit_ty(&mut self, ty: &hir::Ty) {
         if let hir::TyPath(_, ref path) = ty.node {
-            let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
-            match def {
+            match self.tcx.expect_def(ty.id) {
                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
                     // Public
                 }
@@ -962,7 +959,7 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a,
 
     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
         // Non-local means public (private items can't leave their crate, modulo bugs)
-        let def_id = self.tcx.trait_ref_to_def_id(trait_ref);
+        let def_id = self.tcx.expect_def(trait_ref.ref_id).def_id();
         if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
             let item = self.tcx.map.expect_item(node_id);
             let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index c7b113689fd..775c24b6d4a 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -27,7 +27,7 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::ty::{self, VariantKind};
 
 use syntax::ast::Name;
-use syntax::attr::AttrMetaMethods;
+use syntax::attr;
 use syntax::parse::token;
 use syntax::codemap::{Span, DUMMY_SP};
 
@@ -57,6 +57,9 @@ impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) {
 impl<'b> Resolver<'b> {
     /// Constructs the reduced graph for the entire crate.
     pub fn build_reduced_graph(&mut self, krate: &Crate) {
+        let no_implicit_prelude = attr::contains_name(&krate.attrs, "no_implicit_prelude");
+        self.graph_root.no_implicit_prelude.set(no_implicit_prelude);
+
         let mut visitor = BuildReducedGraphVisitor {
             parent: self.graph_root,
             resolver: self,
@@ -128,7 +131,7 @@ impl<'b> Resolver<'b> {
                 };
 
                 // Build up the import directives.
-                let is_prelude = item.attrs.iter().any(|attr| attr.name() == "prelude_import");
+                let is_prelude = attr::contains_name(&item.attrs, "prelude_import");
 
                 match view_path.node {
                     ViewPathSimple(binding, ref full_path) => {
@@ -221,6 +224,10 @@ impl<'b> Resolver<'b> {
                 let parent_link = ModuleParentLink(parent, name);
                 let def = Def::Mod(self.definitions.local_def_id(item.id));
                 let module = self.new_module(parent_link, Some(def), false);
+                module.no_implicit_prelude.set({
+                    parent.no_implicit_prelude.get() ||
+                        attr::contains_name(&item.attrs, "no_implicit_prelude")
+                });
                 self.define(parent, name, TypeNS, (module, sp, vis));
                 self.module_map.insert(item.id, module);
                 *parent_ref = module;
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 97b57f231b9..208b5f11e20 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -677,100 +677,6 @@ fn foo<T>(x: T) {} // ok!
 ```
 "##,
 
-E0413: r##"
-A declaration shadows an enum variant or unit-like struct in scope. Example of
-erroneous code:
-
-```compile_fail
-struct Foo;
-
-let Foo = 12i32; // error: declaration of `Foo` shadows an enum variant or
-                 //        unit-like struct in scope
-```
-
-To fix this error, rename the variable such that it doesn't shadow any enum
-variable or structure in scope. Example:
-
-```
-struct Foo;
-
-let foo = 12i32; // ok!
-```
-
-Or:
-
-```
-struct FooStruct;
-
-let Foo = 12i32; // ok!
-```
-
-The goal here is to avoid a conflict of names.
-"##,
-
-E0414: r##"
-A variable binding in an irrefutable pattern is shadowing the name of a
-constant. Example of erroneous code:
-
-```compile_fail
-const FOO: u8 = 7;
-
-let FOO = 5; // error: variable bindings cannot shadow constants
-
-// or
-
-fn bar(FOO: u8) { // error: variable bindings cannot shadow constants
-
-}
-
-// or
-
-for FOO in bar {
-
-}
-```
-
-Introducing a new variable in Rust is done through a pattern. Thus you can have
-`let` bindings like `let (a, b) = ...`. However, patterns also allow constants
-in them, e.g. if you want to match over a constant:
-
-```ignore
-const FOO: u8 = 1;
-
-match (x,y) {
- (3, 4) => { .. }, // it is (3,4)
- (FOO, 1) => { .. }, // it is (1,1)
- (foo, 1) => { .. }, // it is (anything, 1)
-                     // call the value in the first slot "foo"
- _ => { .. } // it is anything
-}
-```
-
-Here, the second arm matches the value of `x` against the constant `FOO`,
-whereas the third arm will accept any value of `x` and call it `foo`.
-
-This works for `match`, however in cases where an irrefutable pattern is
-required, constants can't be used. An irrefutable pattern is one which always
-matches, whose purpose is only to bind variable names to values. These are
-required by let, for, and function argument patterns.
-
-Refutable patterns in such a situation do not make sense, for example:
-
-```ignore
-let Some(x) = foo; // what if foo is None, instead?
-
-let (1, x) = foo; // what if foo.0 is not 1?
-
-let (SOME_CONST, x) = foo; // what if foo.0 is not SOME_CONST?
-
-let SOME_CONST = foo; // what if foo is not SOME_CONST?
-```
-
-Thus, an irrefutable variable binding can't contain a constant.
-
-To fix this error, just give the marked variable a different name.
-"##,
-
 E0415: r##"
 More than one function parameter have the same name. Example of erroneous code:
 
@@ -814,60 +720,6 @@ match (A, B, C) {
 ```
 "##,
 
-E0417: r##"
-A static variable was referenced in a pattern. Example of erroneous code:
-
-```compile_fail
-static FOO : i32 = 0;
-
-match 0 {
-    FOO => {} // error: static variables cannot be referenced in a
-              //        pattern, use a `const` instead
-    _ => {}
-}
-```
-
-The compiler needs to know the value of the pattern at compile time;
-compile-time patterns can defined via const or enum items. Please verify
-that the identifier is spelled correctly, and if so, use a const instead
-of static to define it. Example:
-
-```
-const FOO : i32 = 0;
-
-match 0 {
-    FOO => {} // ok!
-    _ => {}
-}
-```
-"##,
-
-E0419: r##"
-An unknown enum variant, struct or const was used. Example of erroneous code:
-
-```compile_fail
-match 0 {
-    Something::Foo => {} // error: unresolved enum variant, struct
-                         //        or const `Foo`
-}
-```
-
-Please verify you didn't misspell it and the enum variant, struct or const has
-been declared and imported into scope. Example:
-
-```
-enum Something {
-    Foo,
-    NotFoo,
-}
-
-match Something::NotFoo {
-    Something::Foo => {} // ok!
-    _ => {}
-}
-```
-"##,
-
 E0422: r##"
 You are trying to use an identifier that is either undefined or not a struct.
 For instance:
@@ -1253,10 +1105,17 @@ register_diagnostics! {
 //  E0257,
 //  E0258,
     E0402, // cannot use an outer type parameter in this context
-    E0406, // undeclared associated type
+//  E0406, merged into 420
 //  E0410, merged into 408
-    E0418, // is not an enum variant, struct or const
-    E0420, // is not an associated const
-    E0421, // unresolved associated const
-    E0427, // cannot use `ref` binding mode with ...
+//  E0413, merged into 530
+//  E0414, merged into 530
+//  E0417, merged into 532
+//  E0418, merged into 532
+//  E0419, merged into 531
+//  E0420, merged into 532
+//  E0421, merged into 531
+    E0530, // X bindings cannot shadow Ys
+    E0531, // unresolved pattern path kind `name`
+    E0532, // expected pattern path kind, found another pattern path kind
+//  E0427, merged into 530
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 4941f867f06..e82b4e2fcd7 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -31,7 +31,6 @@ extern crate arena;
 #[macro_use]
 extern crate rustc;
 
-use self::PatternBindingMode::*;
 use self::Namespace::*;
 use self::ResolveResult::*;
 use self::FallbackSuggestion::*;
@@ -39,8 +38,6 @@ use self::TypeParameters::*;
 use self::RibKind::*;
 use self::UseLexicalScopeFlag::*;
 use self::ModulePrefixResult::*;
-use self::AssocItemResolveResult::*;
-use self::BareIdentifierPatternResolution::*;
 use self::ParentLink::*;
 
 use rustc::hir::map::Definitions;
@@ -66,8 +63,8 @@ use syntax::visit::{self, FnKind, Visitor};
 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, Pat, PatKind, Path};
-use syntax::ast::{PathSegment, PathParameters, TraitItemKind, TraitRef, Ty, TyKind};
+use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
+use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 
 use std::collections::{HashMap, HashSet};
 use std::cell::{Cell, RefCell};
@@ -107,8 +104,6 @@ enum ResolutionError<'a> {
     IsNotATrait(&'a str),
     /// error E0405: use of undeclared trait name
     UndeclaredTraitName(&'a str, SuggestedCandidates),
-    /// error E0406: undeclared associated type
-    UndeclaredAssociatedType,
     /// error E0407: method is not a member of trait
     MethodNotMemberOfTrait(Name, &'a str),
     /// error E0437: type is not a member of trait
@@ -123,24 +118,10 @@ enum ResolutionError<'a> {
     SelfUsedOutsideImplOrTrait,
     /// error E0412: use of undeclared
     UseOfUndeclared(&'a str, &'a str, SuggestedCandidates),
-    /// error E0413: cannot be named the same as an enum variant or unit-like struct in scope
-    DeclarationShadowsEnumVariantOrUnitLikeStruct(Name),
-    /// error E0414: only irrefutable patterns allowed here
-    ConstantForIrrefutableBinding(Name),
     /// 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 E0417: static variables cannot be referenced in a pattern
-    StaticVariableReference(&'a NameBinding<'a>),
-    /// error E0418: is not an enum variant, struct or const
-    NotAnEnumVariantStructOrConst(&'a str),
-    /// error E0419: unresolved enum variant, struct or const
-    UnresolvedEnumVariantStructOrConst(&'a str),
-    /// error E0420: is not an associated const
-    NotAnAssociatedConst(&'a str),
-    /// error E0421: unresolved associated const
-    UnresolvedAssociatedConst(&'a str),
     /// error E0422: does not name a struct
     DoesNotNameAStruct(&'a str),
     /// error E0423: is a struct variant name, but this expression uses it like a function name
@@ -158,8 +139,6 @@ enum ResolutionError<'a> {
     },
     /// error E0426: use of undeclared label
     UndeclaredLabel(&'a str),
-    /// error E0427: cannot use `ref` binding mode with ...
-    CannotUseRefBindingModeWith(&'a str),
     /// error E0429: `self` imports are only allowed within a { } list
     SelfImportsOnlyAllowedWithin,
     /// error E0430: `self` import can only appear once in the list
@@ -174,6 +153,12 @@ enum ResolutionError<'a> {
     CannotCaptureDynamicEnvironmentInFnItem,
     /// error E0435: attempt to use a non-constant value in a constant
     AttemptToUseNonConstantValueInConstant,
+    /// error E0530: X bindings cannot shadow Ys
+    BindingShadowsSomethingUnacceptable(&'a str, &'a str, Name),
+    /// 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.
@@ -242,9 +227,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err.span_label(span, &format!("`{}` is not in scope", name));
             err
         }
-        ResolutionError::UndeclaredAssociatedType => {
-            struct_span_err!(resolver.session, span, E0406, "undeclared associated type")
-        }
         ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
             struct_span_err!(resolver.session,
                              span,
@@ -306,32 +288,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err.span_label(span, &format!("undefined or not in scope"));
             err
         }
-        ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0413,
-                             "`{}` cannot be named the same as an enum variant \
-                              or unit-like struct in scope",
-                             name);
-            err.span_label(span,
-                &format!("has same name as enum variant or unit-like struct"));
-            err
-        }
-        ResolutionError::ConstantForIrrefutableBinding(name) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0414,
-                                       "let variables cannot be named the same as const variables");
-            err.span_label(span,
-                           &format!("cannot be named the same as a const variable"));
-            if let Some(binding) = resolver.current_module
-                                           .resolve_name_in_lexical_scope(name, ValueNS) {
-                let participle = if binding.is_import() { "imported" } else { "defined" };
-                err.span_label(binding.span, &format!("a constant `{}` is {} here",
-                               name, participle));
-            }
-            err
-        }
         ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
             let mut err = struct_span_err!(resolver.session,
                              span,
@@ -350,47 +306,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::StaticVariableReference(binding) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0417,
-                                           "static variables cannot be referenced in a \
-                                            pattern, use a `const` instead");
-            err.span_label(span, &format!("static variable used in pattern"));
-            if binding.span != codemap::DUMMY_SP {
-                let participle = if binding.is_import() { "imported" } else { "defined" };
-                err.span_label(binding.span, &format!("static variable {} here", participle));
-            }
-            err
-        }
-        ResolutionError::NotAnEnumVariantStructOrConst(name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0418,
-                             "`{}` is not an enum variant, struct or const",
-                             name)
-        }
-        ResolutionError::UnresolvedEnumVariantStructOrConst(name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0419,
-                             "unresolved enum variant, struct or const `{}`",
-                             name)
-        }
-        ResolutionError::NotAnAssociatedConst(name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0420,
-                             "`{}` is not an associated const",
-                             name)
-        }
-        ResolutionError::UnresolvedAssociatedConst(name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0421,
-                             "unresolved associated const `{}`",
-                             name)
-        }
         ResolutionError::DoesNotNameAStruct(name) => {
             struct_span_err!(resolver.session,
                              span,
@@ -459,13 +374,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
                              "use of undeclared label `{}`",
                              name)
         }
-        ResolutionError::CannotUseRefBindingModeWith(descr) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0427,
-                             "cannot use `ref` binding mode with {}",
-                             descr)
-        }
         ResolutionError::SelfImportsOnlyAllowedWithin => {
             struct_span_err!(resolver.session,
                              span,
@@ -510,6 +418,36 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
                              E0435,
                              "attempt to use a non-constant value in a constant")
         }
+        ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, shadows_what, name) => {
+            let mut err = struct_span_err!(resolver.session,
+                                           span,
+                                           E0530,
+                                           "{}s cannot shadow {}s", what_binding, shadows_what);
+            err.span_label(span, &format!("cannot be named the same as a {}", shadows_what));
+            if let Success(binding) = resolver.current_module.resolve_name(name, ValueNS, true) {
+                let participle = if binding.is_import() { "imported" } else { "defined" };
+                err.span_label(binding.span, &format!("a {} `{}` is {} here",
+                                                      shadows_what, name, participle));
+            }
+            err
+        }
+        ResolutionError::PatPathUnresolved(expected_what, path) => {
+            struct_span_err!(resolver.session,
+                             span,
+                             E0531,
+                             "unresolved {} `{}`",
+                             expected_what,
+                             path.segments.last().unwrap().identifier)
+        }
+        ResolutionError::PatPathUnexpected(expected_what, found_what, path) => {
+            struct_span_err!(resolver.session,
+                             span,
+                             E0532,
+                             "expected {}, found {} `{}`",
+                             expected_what,
+                             found_what,
+                             path.segments.last().unwrap().identifier)
+        }
     }
 }
 
@@ -522,11 +460,33 @@ struct BindingInfo {
 // Map from the name in a pattern to its binding mode.
 type BindingMap = HashMap<Name, BindingInfo>;
 
-#[derive(Copy, Clone, PartialEq)]
-enum PatternBindingMode {
-    RefutableMode,
-    LocalIrrefutableMode,
-    ArgumentIrrefutableMode,
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum PatternSource {
+    Match,
+    IfLet,
+    WhileLet,
+    Let,
+    For,
+    FnParam,
+}
+
+impl PatternSource {
+    fn is_refutable(self) -> bool {
+        match self {
+            PatternSource::Match | PatternSource::IfLet | PatternSource::WhileLet => true,
+            PatternSource::Let | PatternSource::For | PatternSource::FnParam  => false,
+        }
+    }
+    fn descr(self) -> &'static str {
+        match self {
+            PatternSource::Match => "match binding",
+            PatternSource::IfLet => "if let binding",
+            PatternSource::WhileLet => "while let binding",
+            PatternSource::Let => "let binding",
+            PatternSource::For => "for binding",
+            PatternSource::FnParam => "function parameter",
+        }
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -554,9 +514,6 @@ impl<'a, 'v> Visitor<'v> for Resolver<'a> {
     fn visit_ty(&mut self, ty: &Ty) {
         self.resolve_type(ty);
     }
-    fn visit_generics(&mut self, generics: &Generics) {
-        self.resolve_generics(generics);
-    }
     fn visit_poly_trait_ref(&mut self, tref: &ast::PolyTraitRef, m: &ast::TraitBoundModifier) {
         match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0) {
             Ok(def) => self.record_def(tref.trait_ref.ref_id, def),
@@ -704,22 +661,6 @@ enum ModulePrefixResult<'a> {
     PrefixFound(Module<'a>, usize),
 }
 
-#[derive(Copy, Clone)]
-enum AssocItemResolveResult {
-    /// Syntax such as `<T>::item`, which can't be resolved until type
-    /// checking.
-    TypecheckRequired,
-    /// We should have been able to resolve the associated item.
-    ResolveAttempt(Option<PathResolution>),
-}
-
-#[derive(Copy, Clone)]
-enum BareIdentifierPatternResolution {
-    FoundStructOrEnumVariant(Def),
-    FoundConst(Def, Name),
-    BareIdentifierPatternUnresolved,
-}
-
 /// One local scope.
 #[derive(Debug)]
 struct Rib<'a> {
@@ -792,7 +733,7 @@ pub struct ModuleS<'a> {
     resolutions: RefCell<HashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
     unresolved_imports: RefCell<Vec<&'a ImportDirective<'a>>>,
 
-    prelude: RefCell<Option<Module<'a>>>,
+    no_implicit_prelude: Cell<bool>,
 
     glob_importers: RefCell<Vec<(Module<'a>, &'a ImportDirective<'a>)>>,
     globs: RefCell<Vec<&'a ImportDirective<'a>>>,
@@ -821,7 +762,7 @@ impl<'a> ModuleS<'a> {
             extern_crate_id: None,
             resolutions: RefCell::new(HashMap::new()),
             unresolved_imports: RefCell::new(Vec::new()),
-            prelude: RefCell::new(None),
+            no_implicit_prelude: Cell::new(false),
             glob_importers: RefCell::new(Vec::new()),
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
@@ -985,6 +926,8 @@ pub struct Resolver<'a> {
 
     graph_root: Module<'a>,
 
+    prelude: Option<Module<'a>>,
+
     trait_item_map: FnvHashMap<(Name, DefId), bool /* is static method? */>,
 
     structs: FnvHashMap<DefId, Vec<Name>>,
@@ -1129,7 +1072,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
     }
 
     fn record_resolution(&mut self, id: NodeId, def: Def) {
-        self.def_map.insert(id, PathResolution { base_def: def, depth: 0 });
+        self.def_map.insert(id, PathResolution::new(def));
     }
 
     fn definitions(&mut self) -> Option<&mut Definitions> {
@@ -1174,6 +1117,7 @@ impl<'a> Resolver<'a> {
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
             graph_root: graph_root,
+            prelude: None,
 
             trait_item_map: FnvHashMap(),
             structs: FnvHashMap(),
@@ -1456,7 +1400,15 @@ impl<'a> Resolver<'a> {
                 }
 
                 // We can only see through anonymous modules
-                if module.def.is_some() { return None; }
+                if module.def.is_some() {
+                    return match self.prelude {
+                        Some(prelude) if !module.no_implicit_prelude.get() => {
+                            prelude.resolve_name(name, ns, false).success()
+                                   .map(LexicalScopeBinding::Item)
+                        }
+                        _ => None,
+                    };
+                }
             }
         }
 
@@ -1543,11 +1495,7 @@ impl<'a> Resolver<'a> {
         debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(module));
 
         self.populate_module_if_necessary(module);
-        match use_lexical_scope {
-            true => module.resolve_name_in_lexical_scope(name, namespace)
-                          .map(Success).unwrap_or(Failed(None)),
-            false => module.resolve_name(name, namespace, false),
-        }.and_then(|binding| {
+        module.resolve_name(name, namespace, use_lexical_scope).and_then(|binding| {
             if record_used {
                 if let NameBindingKind::Import { directive, .. } = binding.kind {
                     self.used_imports.insert((directive.id, namespace));
@@ -1717,7 +1665,7 @@ impl<'a> Resolver<'a> {
                                                                    TypeNS) {
                                 Ok(binding) => {
                                     let def = binding.def().unwrap();
-                                    self.record_def(item.id, PathResolution::new(def, 0));
+                                    self.record_def(item.id, PathResolution::new(def));
                                 }
                                 Err(true) => self.record_def(item.id, err_path_resolution()),
                                 Err(false) => {
@@ -1811,7 +1759,7 @@ impl<'a> Resolver<'a> {
         // Add each argument to the rib.
         let mut bindings_list = HashMap::new();
         for argument in &declaration.inputs {
-            self.resolve_pattern(&argument.pat, ArgumentIrrefutableMode, &mut bindings_list);
+            self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
 
             self.visit_ty(&argument.ty);
 
@@ -1894,30 +1842,6 @@ impl<'a> Resolver<'a> {
         })
     }
 
-    fn resolve_generics(&mut self, generics: &Generics) {
-        for predicate in &generics.where_clause.predicates {
-            match predicate {
-                &ast::WherePredicate::BoundPredicate(_) |
-                &ast::WherePredicate::RegionPredicate(_) => {}
-                &ast::WherePredicate::EqPredicate(ref eq_pred) => {
-                    self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS).and_then(|path_res| {
-                        if let PathResolution { base_def: Def::TyParam(..), .. } = path_res {
-                            Ok(self.record_def(eq_pred.id, path_res))
-                        } else {
-                            Err(false)
-                        }
-                    }).map_err(|error_reported| {
-                        self.record_def(eq_pred.id, err_path_resolution());
-                        if error_reported { return }
-                        let error_variant = ResolutionError::UndeclaredAssociatedType;
-                        resolve_error(self, eq_pred.span, error_variant);
-                    }).unwrap_or(());
-                }
-            }
-        }
-        visit::walk_generics(self, generics);
-    }
-
     fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
         where F: FnOnce(&mut Resolver) -> T
     {
@@ -2052,7 +1976,7 @@ impl<'a> Resolver<'a> {
         walk_list!(self, visit_expr, &local.init);
 
         // Resolve the pattern.
-        self.resolve_pattern(&local.pat, LocalIrrefutableMode, &mut HashMap::new());
+        self.resolve_pattern(&local.pat, PatternSource::Let, &mut HashMap::new());
     }
 
     // build a map from pattern identifiers to binding-info's.
@@ -2121,7 +2045,7 @@ impl<'a> Resolver<'a> {
 
         let mut bindings_list = HashMap::new();
         for pattern in &arm.pats {
-            self.resolve_pattern(&pattern, RefutableMode, &mut bindings_list);
+            self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
         }
 
         // This has to happen *after* we determine which
@@ -2164,26 +2088,22 @@ impl<'a> Resolver<'a> {
     fn resolve_type(&mut self, ty: &Ty) {
         match ty.node {
             TyKind::Path(ref maybe_qself, ref path) => {
-                let resolution = match self.resolve_possibly_assoc_item(ty.id,
-                                                                        maybe_qself.as_ref(),
-                                                                        path,
-                                                                        TypeNS) {
-                    // `<T>::a::b::c` is resolved by typeck alone.
-                    TypecheckRequired => {
-                        // Resolve embedded types.
-                        visit::walk_ty(self, ty);
-                        return;
-                    }
-                    ResolveAttempt(resolution) => resolution,
-                };
-
                 // This is a path in the type namespace. Walk through scopes
                 // looking for it.
-                if let Some(def) = 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);
+                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());
 
@@ -2243,321 +2163,229 @@ impl<'a> Resolver<'a> {
         visit::walk_ty(self, ty);
     }
 
-    fn resolve_pattern(&mut self,
-                       pattern: &Pat,
-                       mode: PatternBindingMode,
-                       // Maps idents to the node ID for the (outermost)
-                       // pattern that binds them
-                       bindings_list: &mut HashMap<Name, NodeId>) {
-        let pat_id = pattern.id;
-        pattern.walk(&mut |pattern| {
-            match pattern.node {
-                PatKind::Ident(binding_mode, ref path1, ref at_rhs) => {
-                    // The meaning of PatKind::Ident with no type parameters
-                    // depends on whether an enum variant or unit-like struct
-                    // with that name is in scope. The probing lookup has to
-                    // be careful not to emit spurious errors. Only matching
-                    // patterns (match) can match nullary variants or
-                    // unit-like structs. For binding patterns (let
-                    // and the LHS of @-patterns), matching such a value is
-                    // simply disallowed (since it's rarely what you want).
-                    let const_ok = mode == RefutableMode && at_rhs.is_none();
-
-                    let ident = path1.node;
-                    let renamed = mtwt::resolve(ident);
-
-                    match self.resolve_bare_identifier_pattern(ident, pattern.span) {
-                        FoundStructOrEnumVariant(def) if const_ok => {
-                            debug!("(resolving pattern) resolving `{}` to struct or enum variant",
-                                   renamed);
-
-                            self.enforce_default_binding_mode(pattern,
-                                                              binding_mode,
-                                                              "an enum variant");
-                            self.record_def(pattern.id,
-                                            PathResolution {
-                                                base_def: def,
-                                                depth: 0,
-                                            });
-                        }
-                        FoundStructOrEnumVariant(..) => {
-                            resolve_error(
-                                self,
-                                pattern.span,
-                                ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(
-                                    renamed)
-                            );
-                            self.record_def(pattern.id, err_path_resolution());
-                        }
-                        FoundConst(def, _) if const_ok => {
-                            debug!("(resolving pattern) resolving `{}` to constant", renamed);
-
-                            self.enforce_default_binding_mode(pattern, binding_mode, "a constant");
-                            self.record_def(pattern.id,
-                                            PathResolution {
-                                                base_def: def,
-                                                depth: 0,
-                                            });
-                        }
-                        FoundConst(_, name) => {
-                            resolve_error(
-                                self,
-                                pattern.span,
-                                ResolutionError::ConstantForIrrefutableBinding(name)
-                            );
-                            self.record_def(pattern.id, err_path_resolution());
-                        }
-                        BareIdentifierPatternUnresolved => {
-                            debug!("(resolving pattern) binding `{}`", renamed);
-
-                            let def_id = self.definitions.local_def_id(pattern.id);
-                            let def = Def::Local(def_id, pattern.id);
-
-                            // Record the definition so that later passes
-                            // will be able to distinguish variants from
-                            // locals in patterns.
-
-                            self.record_def(pattern.id,
-                                            PathResolution {
-                                                base_def: def,
-                                                depth: 0,
-                                            });
-
-                            // Add the binding to the local ribs, if it
-                            // doesn't already exist in the bindings list. (We
-                            // must not add it if it's in the bindings list
-                            // because that breaks the assumptions later
-                            // passes make about or-patterns.)
-                            if !bindings_list.contains_key(&renamed) {
-                                let this = &mut *self;
-                                let last_rib = this.value_ribs.last_mut().unwrap();
-                                last_rib.bindings.insert(renamed, def);
-                                bindings_list.insert(renamed, pat_id);
-                            } else if mode == ArgumentIrrefutableMode &&
-                               bindings_list.contains_key(&renamed) {
-                                // Forbid duplicate bindings in the same
-                                // parameter list.
-                                resolve_error(
-                                    self,
-                                    pattern.span,
-                                    ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
-                                        &ident.name.as_str())
-                                );
-                            } else if bindings_list.get(&renamed) == Some(&pat_id) {
-                                // Then this is a duplicate variable in the
-                                // same disjunction, which is an error.
-                                resolve_error(
-                                    self,
-                                    pattern.span,
-                                    ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
-                                        &ident.name.as_str())
-                                );
-                            }
-                            // Else, not bound in the same pattern: do
-                            // nothing.
-                        }
-                    }
+    fn fresh_binding(&mut self,
+                     ident: &ast::SpannedIdent,
+                     pat_id: NodeId,
+                     outer_pat_id: NodeId,
+                     pat_src: PatternSource,
+                     bindings: &mut HashMap<Name, NodeId>)
+                     -> PathResolution {
+        // Add the binding to the local ribs, if it
+        // doesn't already exist in the bindings map. (We
+        // must not add it if it's in the bindings map
+        // because that breaks the assumptions later
+        // passes make about or-patterns.)
+        let renamed = mtwt::resolve(ident.node);
+        let def = match bindings.get(&renamed).cloned() {
+            Some(id) if id == outer_pat_id => {
+                // `Variant(a, a)`, error
+                resolve_error(
+                    self,
+                    ident.span,
+                    ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
+                        &ident.node.name.as_str())
+                );
+                Def::Err
+            }
+            Some(..) if pat_src == PatternSource::FnParam => {
+                // `fn f(a: u8, a: u8)`, error
+                resolve_error(
+                    self,
+                    ident.span,
+                    ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
+                        &ident.node.name.as_str())
+                );
+                Def::Err
+            }
+            Some(..) if pat_src == PatternSource::Match => {
+                // `Variant1(a) | Variant2(a)`, ok
+                // Reuse definition from the first `a`.
+                self.value_ribs.last_mut().unwrap().bindings[&renamed]
+            }
+            Some(..) => {
+                span_bug!(ident.span, "two bindings with the same name from \
+                                       unexpected pattern source {:?}", pat_src);
+            }
+            None => {
+                // A completely fresh binding, add to the lists.
+                // FIXME: Later stages are not ready to deal with `Def::Err` here yet, so
+                // define `Invalid` bindings as `Def::Local`, just don't add them to the lists.
+                let def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
+                if ident.node.name != keywords::Invalid.name() {
+                    bindings.insert(renamed, outer_pat_id);
+                    self.value_ribs.last_mut().unwrap().bindings.insert(renamed, def);
                 }
+                def
+            }
+        };
 
-                PatKind::TupleStruct(ref path, _, _) | PatKind::Path(ref path) => {
-                    // This must be an enum variant, struct or const.
-                    let resolution = match self.resolve_possibly_assoc_item(pat_id,
-                                                                            None,
-                                                                            path,
-                                                                            ValueNS) {
-                        // The below shouldn't happen because all
-                        // qualified paths should be in PatKind::QPath.
-                        TypecheckRequired =>
-                            span_bug!(path.span,
-                                      "resolve_possibly_assoc_item claimed that a path \
-                                       in PatKind::Path or PatKind::TupleStruct \
-                                       requires typecheck to resolve, but qualified \
-                                       paths should be PatKind::QPath"),
-                        ResolveAttempt(resolution) => resolution,
-                    };
-                    if let Some(path_res) = resolution {
-                        match path_res.base_def {
-                            Def::Struct(..) if path_res.depth == 0 => {
-                                self.record_def(pattern.id, path_res);
-                            }
-                            Def::Variant(..) | Def::Const(..) => {
-                                self.record_def(pattern.id, path_res);
-                            }
-                            Def::Static(..) => {
-                                let segments = &path.segments;
-                                let binding = if path.global {
-                                    self.resolve_crate_relative_path(path.span, segments, ValueNS)
-                                } else {
-                                    self.resolve_module_relative_path(path.span, segments, ValueNS)
-                                }.unwrap();
+        PathResolution::new(def)
+    }
 
-                                let error = ResolutionError::StaticVariableReference(binding);
-                                resolve_error(self, path.span, error);
-                                self.record_def(pattern.id, err_path_resolution());
-                            }
-                            _ => {
-                                // If anything ends up here entirely resolved,
-                                // it's an error. If anything ends up here
-                                // partially resolved, that's OK, because it may
-                                // be a `T::CONST` that typeck will resolve.
-                                if path_res.depth == 0 {
-                                    resolve_error(
-                                        self,
-                                        path.span,
-                                        ResolutionError::NotAnEnumVariantStructOrConst(
-                                            &path.segments
-                                                 .last()
-                                                 .unwrap()
-                                                 .identifier
-                                                 .name
-                                                 .as_str())
-                                    );
-                                    self.record_def(pattern.id, err_path_resolution());
-                                } else {
-                                    let const_name = path.segments
-                                                         .last()
-                                                         .unwrap()
-                                                         .identifier
-                                                         .name;
-                                    let traits = self.get_traits_containing_item(const_name);
-                                    self.trait_map.insert(pattern.id, traits);
-                                    self.record_def(pattern.id, path_res);
-                                }
-                            }
-                        }
-                    } else {
-                        if let Err(false) = self.resolve_path(pat_id, &path, 0, ValueNS) {
-                            // No error has been reported, so we need to do this ourselves.
-                            resolve_error(
-                                self,
-                                path.span,
-                                ResolutionError::UnresolvedEnumVariantStructOrConst(
-                                    &path.segments.last().unwrap().identifier.name.as_str())
-                            );
-                        }
-                        self.record_def(pattern.id, err_path_resolution());
-                    }
-                    visit::walk_path(self, path);
+    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
+                } 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 {
+            if let Err(false) = self.resolve_path(pat_id, path, 0, namespace) {
+                resolve_error(
+                    self,
+                    path.span,
+                    ResolutionError::PatPathUnresolved(expected_what, path)
+                );
+            }
+            err_path_resolution()
+        };
 
-                PatKind::QPath(ref qself, ref path) => {
-                    // Associated constants only.
-                    let resolution = match self.resolve_possibly_assoc_item(pat_id,
-                                                                            Some(qself),
-                                                                            path,
-                                                                            ValueNS) {
-                        TypecheckRequired => {
-                            // All `<T>::CONST` should end up here, and will
-                            // require use of the trait map to resolve
-                            // during typechecking.
-                            let const_name = path.segments
-                                                 .last()
-                                                 .unwrap()
-                                                 .identifier
-                                                 .name;
-                            let traits = self.get_traits_containing_item(const_name);
-                            self.trait_map.insert(pattern.id, traits);
-                            visit::walk_pat(self, pattern);
-                            return true;
-                        }
-                        ResolveAttempt(resolution) => resolution,
-                    };
-                    if let Some(path_res) = resolution {
-                        match path_res.base_def {
-                            // All `<T as Trait>::CONST` should end up here, and
-                            // have the trait already selected.
-                            Def::AssociatedConst(..) => {
-                                self.record_def(pattern.id, path_res);
+        self.record_def(pat_id, resolution);
+    }
+
+    fn resolve_pattern(&mut self,
+                       pat: &Pat,
+                       pat_src: PatternSource,
+                       // Maps idents to the node ID for the
+                       // outermost pattern that binds them.
+                       bindings: &mut HashMap<Name, NodeId>) {
+        // Visit all direct subpatterns of this pattern.
+        let outer_pat_id = pat.id;
+        pat.walk(&mut |pat| {
+            match pat.node {
+                PatKind::Ident(bmode, ref ident, ref opt_pat) => {
+                    // First try to resolve the identifier as some existing
+                    // entity, then fall back to a fresh binding.
+                    let resolution = if let Ok(resolution) = self.resolve_path(pat.id,
+                                &Path::from_ident(ident.span, ident.node), 0, ValueNS) {
+                        let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
+                                             bmode != BindingMode::ByValue(Mutability::Immutable);
+                        match resolution.base_def {
+                            Def::Struct(..) | Def::Variant(..) |
+                            Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
+                                // A constant, unit variant, etc pattern.
+                                resolution
                             }
-                            _ => {
+                            Def::Struct(..) | Def::Variant(..) |
+                            Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => {
+                                // A fresh binding that shadows something unacceptable.
                                 resolve_error(
                                     self,
-                                    path.span,
-                                    ResolutionError::NotAnAssociatedConst(
-                                        &path.segments.last().unwrap().identifier.name.as_str()
-                                    )
+                                    ident.span,
+                                    ResolutionError::BindingShadowsSomethingUnacceptable(
+                                        pat_src.descr(), resolution.kind_name(), ident.node.name)
                                 );
-                                self.record_def(pattern.id, err_path_resolution());
+                                err_path_resolution()
+                            }
+                            Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
+                                // These entities are explicitly allowed
+                                // to be shadowed by fresh bindings.
+                                self.fresh_binding(ident, pat.id, outer_pat_id,
+                                                   pat_src, bindings)
+                            }
+                            def => {
+                                span_bug!(ident.span, "unexpected definition for an \
+                                                       identifier in pattern {:?}", def);
                             }
                         }
                     } else {
-                        resolve_error(self,
-                                      path.span,
-                                      ResolutionError::UnresolvedAssociatedConst(&path.segments
-                                                                                      .last()
-                                                                                      .unwrap()
-                                                                                      .identifier
-                                                                                      .name
-                                                                                      .as_str()));
-                        self.record_def(pattern.id, err_path_resolution());
-                    }
-                    visit::walk_pat(self, pattern);
+                        // Fall back to a fresh binding.
+                        self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
+                    };
+
+                    self.record_def(pat.id, resolution);
                 }
 
-                PatKind::Struct(ref path, _, _) => {
-                    match self.resolve_path(pat_id, path, 0, TypeNS) {
-                        Ok(definition) => {
-                            self.record_def(pattern.id, definition);
+                PatKind::TupleStruct(ref path, _, _) => {
+                    self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
+                        match def {
+                            Def::Struct(..) | Def::Variant(..) | Def::Err => true,
+                            _ => false,
                         }
-                        Err(true) => self.record_def(pattern.id, err_path_resolution()),
-                        Err(false) => {
-                            resolve_error(
-                                self,
-                                path.span,
-                                ResolutionError::DoesNotNameAStruct(
-                                    &path_names_to_string(path, 0))
-                            );
-                            self.record_def(pattern.id, err_path_resolution());
+                    }, "variant or struct");
+                }
+
+                PatKind::Path(ref path) => {
+                    self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
+                        match def {
+                            Def::Struct(..) | Def::Variant(..) |
+                            Def::Const(..) | Def::AssociatedConst(..) | Def::Err => true,
+                            _ => false,
                         }
-                    }
-                    visit::walk_path(self, path);
+                    }, "variant, struct or constant");
                 }
 
-                PatKind::Lit(_) | PatKind::Range(..) => {
-                    visit::walk_pat(self, pattern);
+                PatKind::QPath(ref qself, ref path) => {
+                    self.resolve_pattern_path(pat.id, Some(qself), path, ValueNS, |def| {
+                        match def {
+                            Def::AssociatedConst(..) | Def::Err => true,
+                            _ => false,
+                        }
+                    }, "associated constant");
                 }
 
-                _ => {
-                    // Nothing to do.
+                PatKind::Struct(ref path, _, _) => {
+                    self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
+                        match def {
+                            Def::Struct(..) | Def::Variant(..) |
+                            Def::TyAlias(..) | Def::AssociatedTy(..) | Def::Err => true,
+                            _ => false,
+                        }
+                    }, "variant, struct or type alias");
                 }
+
+                _ => {}
             }
             true
         });
-    }
-
-    fn resolve_bare_identifier_pattern(&mut self, ident: ast::Ident, span: Span)
-                                       -> BareIdentifierPatternResolution {
-        let binding = match self.resolve_ident_in_lexical_scope(ident, ValueNS, true) {
-            Some(LexicalScopeBinding::Item(binding)) => binding,
-            _ => return BareIdentifierPatternUnresolved,
-        };
-        let def = binding.def().unwrap();
 
-        match def {
-            Def::Variant(..) | Def::Struct(..) => FoundStructOrEnumVariant(def),
-            Def::Const(..) | Def::AssociatedConst(..) => FoundConst(def, ident.name),
-            Def::Static(..) => {
-                let error = ResolutionError::StaticVariableReference(binding);
-                resolve_error(self, span, error);
-                BareIdentifierPatternUnresolved
-            }
-            _ => BareIdentifierPatternUnresolved,
-        }
+        visit::walk_pat(self, pat);
     }
 
     /// Handles paths that may refer to associated items
     fn resolve_possibly_assoc_item(&mut self,
                                    id: NodeId,
-                                   maybe_qself: Option<&ast::QSelf>,
+                                   maybe_qself: Option<&QSelf>,
                                    path: &Path,
                                    namespace: Namespace)
-                                   -> AssocItemResolveResult {
+                                   -> Option<PathResolution> {
         let max_assoc_types;
 
         match maybe_qself {
             Some(qself) => {
                 if qself.position == 0 {
-                    return TypecheckRequired;
+                    // 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)),
+                        depth: path.segments.len(),
+                    });
                 }
                 max_assoc_types = path.segments.len() - qself.position;
                 // Make sure the trait is valid.
@@ -2576,14 +2404,15 @@ impl<'a> Resolver<'a> {
                 break;
             }
             self.with_no_errors(|this| {
-                resolution = this.resolve_path(id, path, depth, TypeNS).ok();
+                let partial_resolution = this.resolve_path(id, path, depth, TypeNS).ok();
+                if let Some(Def::Mod(..)) = partial_resolution.map(|r| r.base_def) {
+                    // Modules cannot have associated items
+                } else {
+                    resolution = partial_resolution;
+                }
             });
         }
-        if let Some(Def::Mod(_)) = resolution.map(|r| r.base_def) {
-            // A module is not a valid type or value.
-            resolution = None;
-        }
-        ResolveAttempt(resolution)
+        resolution
     }
 
     /// Skips `path_depth` trailing segments, which is also reflected in the
@@ -2595,7 +2424,7 @@ impl<'a> Resolver<'a> {
         let span = path.span;
         let segments = &path.segments[..path.segments.len() - path_depth];
 
-        let mk_res = |def| PathResolution::new(def, path_depth);
+        let mk_res = |def| PathResolution { base_def: def, depth: path_depth };
 
         if path.global {
             let binding = self.resolve_crate_relative_path(span, segments, namespace);
@@ -2863,19 +2692,18 @@ 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.
-            match self.def_map.get(&node_id).map(|d| d.full_def()) {
-                Some(Def::Enum(did)) |
-                Some(Def::TyAlias(did)) |
-                Some(Def::Struct(did)) |
-                Some(Def::Variant(_, did)) => match self.structs.get(&did) {
-                    None => {}
-                    Some(fields) => {
-                        if fields.iter().any(|&field_name| name == field_name) {
-                            return Field;
+            if let Some(resolution) = self.def_map.get(&node_id) {
+                match resolution.base_def {
+                    Def::Enum(did) | Def::TyAlias(did) |
+                    Def::Struct(did) | Def::Variant(_, did) if resolution.depth == 0 => {
+                        if let Some(fields) = self.structs.get(&did) {
+                            if fields.iter().any(|&field_name| name == field_name) {
+                                return Field;
+                            }
                         }
                     }
-                },
-                _ => {} // Self type didn't resolve properly
+                    _ => {}
+                }
             }
         }
 
@@ -2932,24 +2760,10 @@ impl<'a> Resolver<'a> {
         // Next, resolve the node.
         match expr.node {
             ExprKind::Path(ref maybe_qself, ref path) => {
-                let resolution = match self.resolve_possibly_assoc_item(expr.id,
-                                                                        maybe_qself.as_ref(),
-                                                                        path,
-                                                                        ValueNS) {
-                    // `<T>::a::b::c` is resolved by typeck alone.
-                    TypecheckRequired => {
-                        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);
-                        visit::walk_expr(self, expr);
-                        return;
-                    }
-                    ResolveAttempt(resolution) => resolution,
-                };
-
                 // This is a local path in the value namespace. Walk through
                 // scopes looking for it.
-                if let Some(path_res) = resolution {
+                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 = if let Def::Variant(_, variant_id) = path_res.base_def {
                         self.structs.contains_key(&variant_id)
@@ -3152,11 +2966,7 @@ impl<'a> Resolver<'a> {
                     }
                     Some(def @ Def::Label(_)) => {
                         // Since this def is a label, it is never read.
-                        self.record_def(expr.id,
-                                        PathResolution {
-                                            base_def: def,
-                                            depth: 0,
-                                        })
+                        self.record_def(expr.id, PathResolution::new(def))
                     }
                     Some(_) => {
                         span_bug!(expr.span, "label wasn't mapped to a label def!")
@@ -3168,7 +2978,7 @@ impl<'a> Resolver<'a> {
                 self.visit_expr(subexpression);
 
                 self.value_ribs.push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, RefutableMode, &mut HashMap::new());
+                self.resolve_pattern(pattern, PatternSource::IfLet, &mut HashMap::new());
                 self.visit_block(if_block);
                 self.value_ribs.pop();
 
@@ -3178,7 +2988,7 @@ impl<'a> Resolver<'a> {
             ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
                 self.visit_expr(subexpression);
                 self.value_ribs.push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, RefutableMode, &mut HashMap::new());
+                self.resolve_pattern(pattern, PatternSource::WhileLet, &mut HashMap::new());
 
                 self.resolve_labeled_block(label.map(|l| l.node), expr.id, block);
 
@@ -3188,7 +2998,7 @@ impl<'a> Resolver<'a> {
             ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
                 self.visit_expr(subexpression);
                 self.value_ribs.push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, LocalIrrefutableMode, &mut HashMap::new());
+                self.resolve_pattern(pattern, PatternSource::For, &mut HashMap::new());
 
                 self.resolve_labeled_block(label.map(|l| l.node), expr.id, block);
 
@@ -3264,7 +3074,7 @@ impl<'a> Resolver<'a> {
         let mut search_module = self.current_module;
         loop {
             // Look for trait children.
-            let mut search_in_module = |module: Module<'a>| {
+            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();
@@ -3279,23 +3089,25 @@ impl<'a> Resolver<'a> {
 
                 for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
                     let trait_def_id = binding.def().unwrap().def_id();
-                    if self.trait_item_map.contains_key(&(name, trait_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;
-                            self.maybe_unused_trait_imports.insert(id);
+                            this.maybe_unused_trait_imports.insert(id);
                             import_id = Some(id);
                         }
                         add_trait_info(&mut found_traits, trait_def_id, import_id, name);
-                        self.record_use(trait_name, binding);
+                        this.record_use(trait_name, binding);
                     }
                 }
             };
-            search_in_module(search_module);
+            search_in_module(self, search_module);
 
             match search_module.parent_link {
                 NoParentLink | ModuleParentLink(..) => {
-                    search_module.prelude.borrow().map(search_in_module);
+                    if !search_module.no_implicit_prelude.get() {
+                        self.prelude.map(|prelude| search_in_module(self, prelude));
+                    }
                     break;
                 }
                 BlockParentLink(parent_module, _) => {
@@ -3406,20 +3218,6 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn enforce_default_binding_mode(&mut self,
-                                    pat: &Pat,
-                                    pat_binding_mode: BindingMode,
-                                    descr: &str) {
-        match pat_binding_mode {
-            BindingMode::ByValue(_) => {}
-            BindingMode::ByRef(..) => {
-                resolve_error(self,
-                              pat.span,
-                              ResolutionError::CannotUseRefBindingModeWith(descr));
-            }
-        }
-    }
-
     fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
         let (path, id) = match *vis {
             ast::Visibility::Public => return ty::Visibility::Public,
@@ -3435,11 +3233,11 @@ impl<'a> Resolver<'a> {
         };
 
         let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect();
+        let mut path_resolution = err_path_resolution();
         let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, path.span) {
             Success(module) => {
                 let def = module.def.unwrap();
-                let path_resolution = PathResolution { base_def: def, depth: 0 };
-                self.def_map.insert(id, path_resolution);
+                path_resolution = PathResolution::new(def);
                 ty::Visibility::Restricted(self.definitions.as_local_node_id(def.def_id()).unwrap())
             }
             Failed(Some((span, msg))) => {
@@ -3451,6 +3249,7 @@ impl<'a> Resolver<'a> {
                 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(path.span, &msg);
@@ -3651,13 +3450,9 @@ fn module_to_string(module: Module) -> String {
 }
 
 fn err_path_resolution() -> PathResolution {
-    PathResolution {
-        base_def: Def::Err,
-        depth: 0,
-    }
+    PathResolution::new(Def::Err)
 }
 
-
 #[derive(PartialEq,Copy, Clone)]
 pub enum MakeGlobMap {
     Yes,
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 9bd16117f9a..3082a8b4307 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -257,15 +257,6 @@ impl<'a> ::ModuleS<'a> {
         Failed(None)
     }
 
-    // Invariant: this may not be called until import resolution is complete.
-    pub fn resolve_name_in_lexical_scope(&self, name: Name, ns: Namespace)
-                                         -> Option<&'a NameBinding<'a>> {
-        self.resolution(name, ns).borrow().binding
-            .or_else(|| self.prelude.borrow().and_then(|prelude| {
-                prelude.resolve_name(name, ns, false).success()
-            }))
-    }
-
     // Define the name or return the existing binding if there is a collision.
     pub fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>)
                             -> Result<(), &'a NameBinding<'a>> {
@@ -607,7 +598,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             Some(def) => def,
             None => value_result.success().and_then(NameBinding::def).unwrap(),
         };
-        let path_resolution = PathResolution { base_def: def, depth: 0 };
+        let path_resolution = PathResolution::new(def);
         self.resolver.def_map.insert(directive.id, path_resolution);
 
         debug!("(resolving single import) successfully resolved import");
@@ -633,7 +624,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         self.resolver.populate_module_if_necessary(target_module);
 
         if let GlobImport { is_prelude: true } = directive.subclass {
-            *module_.prelude.borrow_mut() = Some(target_module);
+            self.resolver.prelude = Some(target_module);
             return Success(());
         }
 
@@ -653,7 +644,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
 
         // Record the destination of this import
         if let Some(did) = target_module.def_id() {
-            let resolution = PathResolution { base_def: Def::Mod(did), depth: 0 };
+            let resolution = PathResolution::new(Def::Mod(did));
             self.resolver.def_map.insert(directive.id, resolution);
         }
 
diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs
index 2275a1c5c65..15aaa77cc35 100644
--- a/src/librustc_save_analysis/data.rs
+++ b/src/librustc_save_analysis/data.rs
@@ -102,6 +102,8 @@ pub struct EnumData {
     pub qualname: String,
     pub span: Span,
     pub scope: NodeId,
+    pub variants: Vec<NodeId>,
+
 }
 
 /// Data for extern crates.
@@ -212,6 +214,7 @@ pub struct MethodData {
     pub span: Span,
     pub scope: NodeId,
     pub value: String,
+    pub decl_id: Option<DefId>,
 }
 
 /// Data for modules.
@@ -223,6 +226,7 @@ pub struct ModData {
     pub span: Span,
     pub scope: NodeId,
     pub filename: String,
+    pub items: Vec<NodeId>,
 }
 
 /// Data for a reference to a module.
@@ -242,7 +246,8 @@ pub struct StructData {
     pub ctor_id: NodeId,
     pub qualname: String,
     pub scope: NodeId,
-    pub value: String
+    pub value: String,
+    pub fields: Vec<NodeId>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -263,7 +268,8 @@ pub struct TraitData {
     pub name: String,
     pub qualname: String,
     pub scope: NodeId,
-    pub value: String
+    pub value: String,
+    pub items: Vec<NodeId>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -317,6 +323,7 @@ pub struct UseGlobData {
 #[derive(Debug, RustcEncodable)]
 pub struct VariableData {
     pub id: NodeId,
+    pub kind: VariableKind,
     pub name: String,
     pub qualname: String,
     pub span: Span,
@@ -325,6 +332,14 @@ pub struct VariableData {
     pub type_value: String,
 }
 
+#[derive(Debug, RustcEncodable)]
+pub enum VariableKind {
+    Static,
+    Const,
+    Local,
+    Field,
+}
+
 /// Data for the use of some item (e.g., the use of a local variable, which
 /// will refer to that variables declaration (by ref_id)).
 #[derive(Debug, RustcEncodable)]
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 4d79ddfe8cb..56c7436a8fe 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -30,7 +30,7 @@
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::session::Session;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer};
 
 use std::collections::HashSet;
 use std::hash::*;
@@ -269,14 +269,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
     // looks up anything, not just a type
     fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
-        if !self.tcx.def_map.borrow().contains_key(&ref_id) {
-            bug!("def_map has no key for {} in lookup_type_ref", ref_id);
-        }
-        let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
-        match def {
+        match self.tcx.expect_def(ref_id) {
             Def::PrimTy(..) => None,
             Def::SelfTy(..) => None,
-            _ => Some(def.def_id()),
+            def => Some(def.def_id()),
         }
     }
 
@@ -290,13 +286,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             return;
         }
 
-        let def_map = self.tcx.def_map.borrow();
-        if !def_map.contains_key(&ref_id) {
-            span_bug!(span,
-                      "def_map has no key for {} in lookup_def_kind",
-                      ref_id);
-        }
-        let def = def_map.get(&ref_id).unwrap().full_def();
+        let def = self.tcx.expect_def(ref_id);
         match def {
             Def::Mod(_) |
             Def::ForeignMod(_) => {
@@ -366,6 +356,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 if !self.span.filter_generated(sub_span, p.span) {
                     self.dumper.variable(VariableData {
                         id: id,
+                        kind: VariableKind::Local,
                         span: sub_span.expect("No span found for variable"),
                         name: path_to_string(p),
                         qualname: format!("{}::{}", qualname, path_to_string(p)),
@@ -390,24 +381,42 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
             let sig_str = ::make_signature(&sig.decl, &sig.generics);
             if body.is_some() {
-                if !self.span.filter_generated(Some(method_data.span), span) {
-                    let mut data = method_data.clone();
-                    data.value = sig_str;
-                    self.dumper.function(data.lower(self.tcx));
-                }
                 self.process_formals(&sig.decl.inputs, &method_data.qualname);
-            } else {
-                if !self.span.filter_generated(Some(method_data.span), span) {
-                    self.dumper.method(MethodData {
-                        id: method_data.id,
-                        name: method_data.name,
-                        span: method_data.span,
-                        scope: method_data.scope,
-                        qualname: method_data.qualname.clone(),
-                        value: sig_str,
-                    }.lower(self.tcx));
-                }
             }
+
+            // If the method is defined in an impl, then try and find the corresponding
+            // method decl in a trait, and if there is one, make a decl_id for it. This
+            // requires looking up the impl, then the trait, then searching for a method
+            // with the right name.
+            if !self.span.filter_generated(Some(method_data.span), span) {
+                let container =
+                    self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container();
+                let decl_id = if let ImplOrTraitItemContainer::ImplContainer(id) = container {
+                    self.tcx.trait_id_of_impl(id).and_then(|id| {
+                        for item in &**self.tcx.trait_items(id) {
+                            if let &ImplOrTraitItem::MethodTraitItem(ref m) = item {
+                                if m.name == name {
+                                    return Some(m.def_id);
+                                }
+                            }
+                        }
+                        None
+                    })
+                } else {
+                    None
+                };
+
+                self.dumper.method(MethodData {
+                    id: method_data.id,
+                    name: method_data.name,
+                    span: method_data.span,
+                    scope: method_data.scope,
+                    qualname: method_data.qualname.clone(),
+                    value: sig_str,
+                    decl_id: decl_id,
+                }.lower(self.tcx));
+            }
+
             self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
         }
 
@@ -529,6 +538,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         if !self.span.filter_generated(sub_span, span) {
             self.dumper.variable(VariableData {
                 span: sub_span.expect("No span found for variable"),
+                kind: VariableKind::Const,
                 id: id,
                 name: name.to_string(),
                 qualname: qualname,
@@ -552,17 +562,18 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
 
         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
-        let val = if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) =
-                    item.node {
+        let (val, fields) =
+            if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) = item.node
+        {
             let fields_str = fields.iter()
                                    .enumerate()
                                    .map(|(i, f)| f.ident.map(|i| i.to_string())
                                                   .unwrap_or(i.to_string()))
                                    .collect::<Vec<_>>()
                                    .join(", ");
-            format!("{} {{ {} }}", name, fields_str)
+            (format!("{} {{ {} }}", name, fields_str), fields.iter().map(|f| f.id).collect())
         } else {
-            String::new()
+            (String::new(), vec![])
         };
 
         if !self.span.filter_generated(sub_span, item.span) {
@@ -573,7 +584,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 ctor_id: def.id(),
                 qualname: qualname.clone(),
                 scope: self.cur_scope,
-                value: val
+                value: val,
+                fields: fields,
             }.lower(self.tcx));
         }
 
@@ -728,7 +740,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 name: name,
                 qualname: qualname.clone(),
                 scope: self.cur_scope,
-                value: val
+                value: val,
+                items: methods.iter().map(|i| i.id).collect(),
             }.lower(self.tcx));
         }
 
@@ -853,9 +866,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         }
 
         // Modules or types in the path prefix.
-        let def_map = self.tcx.def_map.borrow();
-        let def = def_map.get(&id).unwrap().full_def();
-        match def {
+        match self.tcx.expect_def(id) {
             Def::Method(did) => {
                 let ti = self.tcx.impl_or_trait_item(did);
                 if let ty::MethodTraitItem(m) = ti {
@@ -924,8 +935,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             PatKind::Struct(ref path, ref fields, _) => {
                 visit::walk_path(self, path);
                 let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap();
-                let def = self.tcx.def_map.borrow()[&p.id].full_def();
-                let variant = adt.variant_of_def(def);
+                let variant = adt.variant_of_def(self.tcx.expect_def(p.id));
 
                 for &Spanned { node: ref field, span } in fields {
                     let sub_span = self.span.span_for_first_ident(span);
@@ -971,6 +981,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             if !self.span.filter_generated(sub_span, p.span) {
                 self.dumper.variable(VariableData {
                     span: sub_span.expect("No span found for variable"),
+                    kind: VariableKind::Local,
                     id: id,
                     name: path_to_string(p),
                     qualname: format!("{}${}", path_to_string(p), id),
@@ -1269,7 +1280,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
                 let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id);
                 let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap();
-                let def = self.tcx.resolve_expr(&hir_expr);
+                let def = self.tcx.expect_def(hir_expr.id);
                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
             }
             ast::ExprKind::MethodCall(_, _, ref args) => self.process_method_call(ex, args),
@@ -1366,12 +1377,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
 
         // process collected paths
         for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
-            let def_map = self.tcx.def_map.borrow();
-            if !def_map.contains_key(&id) {
-                span_bug!(p.span, "def_map has no key for {} in visit_arm", id);
-            }
-            let def = def_map.get(&id).unwrap().full_def();
-            match def {
+            match self.tcx.expect_def(id) {
                 Def::Local(_, id) => {
                     let value = if immut == ast::Mutability::Immutable {
                         self.span.snippet(p.span).to_string()
@@ -1384,6 +1390,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
                     if !self.span.filter_generated(Some(p.span), p.span) {
                         self.dumper.variable(VariableData {
                             span: p.span,
+                            kind: VariableKind::Local,
                             id: id,
                             name: path_to_string(p),
                             qualname: format!("{}${}", path_to_string(p), id),
@@ -1401,8 +1408,8 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
                 Def::Static(_, _) |
                 Def::Const(..) |
                 Def::AssociatedConst(..) => {}
-                _ => error!("unexpected definition kind when processing collected paths: {:?}",
-                            def),
+                def => error!("unexpected definition kind when processing collected paths: {:?}",
+                              def),
             }
         }
 
diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs
index dc51c41f296..7efd2624561 100644
--- a/src/librustc_save_analysis/external_data.rs
+++ b/src/librustc_save_analysis/external_data.rs
@@ -14,7 +14,7 @@ use rustc::ty::TyCtxt;
 use syntax::ast::{CrateNum, NodeId};
 use syntax::codemap::{Span, CodeMap};
 
-use super::data;
+use data;
 
 // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet
 pub trait Lower {
@@ -90,6 +90,7 @@ pub struct EnumData {
     pub qualname: String,
     pub span: SpanData,
     pub scope: DefId,
+    pub variants: Vec<DefId>
 }
 
 impl Lower for data::EnumData {
@@ -103,6 +104,7 @@ impl Lower for data::EnumData {
             qualname: self.qualname,
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
             scope: make_def_id(self.scope, &tcx.map),
+            variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
         }
     }
 }
@@ -319,6 +321,7 @@ pub struct MethodData {
     pub span: SpanData,
     pub scope: DefId,
     pub value: String,
+    pub decl_id: Option<DefId>,
 }
 
 impl Lower for data::MethodData {
@@ -332,6 +335,7 @@ impl Lower for data::MethodData {
             id: make_def_id(self.id, &tcx.map),
             qualname: self.qualname,
             value: self.value,
+            decl_id: self.decl_id,
         }
     }
 }
@@ -345,6 +349,7 @@ pub struct ModData {
     pub span: SpanData,
     pub scope: DefId,
     pub filename: String,
+    pub items: Vec<DefId>,
 }
 
 impl Lower for data::ModData {
@@ -358,6 +363,7 @@ impl Lower for data::ModData {
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
             scope: make_def_id(self.scope, &tcx.map),
             filename: self.filename,
+            items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
         }
     }
 }
@@ -392,7 +398,8 @@ pub struct StructData {
     pub ctor_id: DefId,
     pub qualname: String,
     pub scope: DefId,
-    pub value: String
+    pub value: String,
+    pub fields: Vec<DefId>,
 }
 
 impl Lower for data::StructData {
@@ -406,7 +413,8 @@ impl Lower for data::StructData {
             ctor_id: make_def_id(self.ctor_id, &tcx.map),
             qualname: self.qualname,
             scope: make_def_id(self.scope, &tcx.map),
-            value: self.value
+            value: self.value,
+            fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
         }
     }
 }
@@ -445,7 +453,8 @@ pub struct TraitData {
     pub id: DefId,
     pub qualname: String,
     pub scope: DefId,
-    pub value: String
+    pub value: String,
+    pub items: Vec<DefId>,
 }
 
 impl Lower for data::TraitData {
@@ -459,6 +468,7 @@ impl Lower for data::TraitData {
             qualname: self.qualname,
             scope: make_def_id(self.scope, &tcx.map),
             value: self.value,
+            items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
         }
     }
 }
@@ -585,6 +595,7 @@ impl Lower for data::UseGlobData {
 pub struct VariableData {
     pub id: DefId,
     pub name: String,
+    pub kind: data::VariableKind,
     pub qualname: String,
     pub span: SpanData,
     pub scope: DefId,
@@ -598,6 +609,7 @@ impl Lower for data::VariableData {
     fn lower(self, tcx: TyCtxt) -> VariableData {
         VariableData {
             id: make_def_id(self.id, &tcx.map),
+            kind: self.kind,
             name: self.name,
             qualname: self.qualname,
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs
index 610a9ac2ad6..b1955cbd7b8 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/json_dumper.rs
@@ -13,8 +13,9 @@ use std::io::Write;
 use rustc::hir::def_id::DefId;
 use rustc_serialize::json::as_json;
 
-use super::external_data::*;
-use super::dump::Dump;
+use external_data::*;
+use data::VariableKind;
+use dump::Dump;
 
 pub struct JsonDumper<'b, W: Write + 'b> {
     output: &'b mut W,
@@ -180,6 +181,8 @@ struct Def {
     name: String,
     qualname: String,
     value: String,
+    children: Vec<Id>,
+    decl_id: Option<Id>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -194,14 +197,19 @@ enum DefKind {
     Trait,
     // value = type + generics
     Function,
+    // value = type + generics
+    Method,
     // No id, no value.
     Macro,
     // value = file_name
     Mod,
     // value = aliased type
     Type,
-    // value = type and init expression
-    Variable,
+    // value = type and init expression (for all variable kinds).
+    Local,
+    Static,
+    Const,
+    Field,
 }
 
 impl From<EnumData> for Def {
@@ -213,6 +221,8 @@ impl From<EnumData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: data.variants.into_iter().map(|id| From::from(id)).collect(),
+            decl_id: None,
         }
     }
 }
@@ -226,6 +236,8 @@ impl From<TupleVariantData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: vec![],
+            decl_id: None,
         }
     }
 }
@@ -238,6 +250,8 @@ impl From<StructVariantData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: vec![],
+            decl_id: None,
         }
     }
 }
@@ -250,6 +264,8 @@ impl From<StructData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: data.fields.into_iter().map(|id| From::from(id)).collect(),
+            decl_id: None,
         }
     }
 }
@@ -262,6 +278,8 @@ impl From<TraitData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: data.items.into_iter().map(|id| From::from(id)).collect(),
+            decl_id: None,
         }
     }
 }
@@ -274,18 +292,22 @@ impl From<FunctionData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: vec![],
+            decl_id: None,
         }
     }
 }
 impl From<MethodData> for Def {
     fn from(data: MethodData) -> Def {
         Def {
-            kind: DefKind::Function,
+            kind: DefKind::Method,
             id: From::from(data.id),
             span: data.span,
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: vec![],
+            decl_id: data.decl_id.map(|id| From::from(id)),
         }
     }
 }
@@ -298,6 +320,8 @@ impl From<MacroData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: String::new(),
+            children: vec![],
+            decl_id: None,
         }
     }
 }
@@ -310,6 +334,8 @@ impl From<ModData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.filename,
+            children: data.items.into_iter().map(|id| From::from(id)).collect(),
+            decl_id: None,
         }
     }
 }
@@ -322,18 +348,27 @@ impl From<TypeDefData> for Def {
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: vec![],
+            decl_id: None,
         }
     }
 }
 impl From<VariableData> for Def {
     fn from(data: VariableData) -> Def {
         Def {
-            kind: DefKind::Variable,
+            kind: match data.kind {
+                VariableKind::Static => DefKind::Static,
+                VariableKind::Const => DefKind::Const,
+                VariableKind::Local => DefKind::Local,
+                VariableKind::Field => DefKind::Field,
+            },
             id: From::from(data.id),
             span: data.span,
             name: data.name,
             qualname: data.qualname,
             value: data.value,
+            children: vec![],
+            decl_id: None,
         }
     }
 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 23c03670c1e..33351338160 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -153,6 +153,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 filter!(self.span_utils, sub_span, item.span, None);
                 Some(Data::VariableData(VariableData {
                     id: item.id,
+                    kind: VariableKind::Static,
                     name: item.ident.to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
@@ -167,6 +168,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 filter!(self.span_utils, sub_span, item.span, None);
                 Some(Data::VariableData(VariableData {
                     id: item.id,
+                    kind: VariableKind::Const,
                     name: item.ident.to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
@@ -190,6 +192,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     span: sub_span.unwrap(),
                     scope: self.enclosing_scope(item.id),
                     filename: filename,
+                    items: m.items.iter().map(|i| i.id).collect(),
                 }))
             }
             ast::ItemKind::Enum(ref def, _) => {
@@ -209,6 +212,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     span: sub_span.unwrap(),
                     qualname: qualname,
                     scope: self.enclosing_scope(item.id),
+                    variants: def.variants.iter().map(|v| v.node.data.id()).collect(),
                 }))
             }
             ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => {
@@ -266,6 +270,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             filter!(self.span_utils, sub_span, field.span, None);
             Some(VariableData {
                 id: field.id,
+                kind: VariableKind::Field,
                 name: ident.to_string(),
                 qualname: qualname,
                 span: sub_span.unwrap(),
@@ -465,11 +470,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     }
 
     pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
-        let def_map = self.tcx.def_map.borrow();
-        if !def_map.contains_key(&id) {
-            span_bug!(path.span, "def_map has no key for {} in visit_expr", id);
-        }
-        let def = def_map.get(&id).unwrap().full_def();
+        let def = self.tcx.expect_def(id);
         let sub_span = self.span_utils.span_for_last_ident(path.span);
         filter!(self.span_utils, sub_span, path.span, None);
         match def {
@@ -637,13 +638,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     }
 
     fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
-        if !self.tcx.def_map.borrow().contains_key(&ref_id) {
-            bug!("def_map has no key for {} in lookup_type_ref", ref_id);
-        }
-        let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
-        match def {
+        match self.tcx.expect_def(ref_id) {
             Def::PrimTy(_) | Def::SelfTy(..) => None,
-            _ => Some(def.def_id()),
+            def => Some(def.def_id()),
         }
     }
 
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index 3028fb1bfa4..4b3975faa80 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -81,7 +81,7 @@ impl<'a> SpanUtils<'a> {
         // are incompatible with spans over other filemaps.
         let filemap = self.sess
                           .codemap()
-                          .new_filemap(String::from("<anon-dxr>"), self.snippet(span));
+                          .new_filemap(String::from("<anon-dxr>"), None, self.snippet(span));
         let s = self.sess;
         lexer::StringReader::new(s.diagnostic(), filemap)
     }
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index 9a0580472b4..749ceda3db0 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -21,7 +21,6 @@ rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_llvm = { path = "../librustc_llvm" }
-rustc_mir = { path = "../librustc_mir" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
 serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
index f524bc8596a..8ad1ba2a614 100644
--- a/src/librustc_trans/_match.rs
+++ b/src/librustc_trans/_match.rs
@@ -505,14 +505,16 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                                           val: MatchInput,
                                           mut e: F)
                                           -> Vec<Match<'a, 'p, 'blk, 'tcx>> where
-    F: FnMut(&[&'p hir::Pat]) -> Option<Vec<&'p hir::Pat>>,
+    F: FnMut(&[(&'p hir::Pat, Option<Ty<'tcx>>)])
+             -> Option<Vec<(&'p hir::Pat, Option<Ty<'tcx>>)>>,
 {
     debug!("enter_match(bcx={}, m={:?}, col={}, val={:?})",
            bcx.to_str(), m, col, val);
     let _indenter = indenter();
 
     m.iter().filter_map(|br| {
-        e(&br.pats).map(|pats| {
+        let pats : Vec<_> = br.pats.iter().map(|p| (*p, None)).collect();
+        e(&pats).map(|pats| {
             let this = br.pats[col];
             let mut bound_ptrs = br.bound_ptrs.clone();
             match this.node {
@@ -530,7 +532,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                 _ => {}
             }
             Match {
-                pats: pats,
+                pats: pats.into_iter().map(|p| p.0).collect(),
                 data: br.data,
                 bound_ptrs: bound_ptrs,
                 pat_renaming_map: br.pat_renaming_map,
@@ -550,7 +552,7 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Collect all of the matches that can match against anything.
     enter_match(bcx, m, col, val, |pats| {
-        match pats[col].node {
+        match pats[col].0.node {
             PatKind::Binding(..) | PatKind::Wild => {
                 let mut r = pats[..col].to_vec();
                 r.extend_from_slice(&pats[col + 1..]);
@@ -655,9 +657,8 @@ fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 ConstantValue(ConstantExpr(&l), debug_loc)
             }
             PatKind::Path(..) | PatKind::TupleStruct(..) | PatKind::Struct(..) => {
-                let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def());
-                match opt_def {
-                    Some(Def::Variant(enum_id, var_id)) => {
+                match tcx.expect_def(cur.id) {
+                    Def::Variant(enum_id, var_id) => {
                         let variant = tcx.lookup_adt_def(enum_id).variant_with_id(var_id);
                         Variant(Disr::from(variant.disr_val),
                                 adt::represent_node(bcx, cur.id),
@@ -729,9 +730,16 @@ fn bind_subslice_pat(bcx: Block,
     let (base, len) = vec_datum.get_vec_base_and_len(bcx);
 
     let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]);
-    let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right);
+    let diff = offset_left + offset_right;
+    if let ty::TyArray(ty, n) = vec_ty_contents.sty {
+        let array_ty = bcx.tcx().mk_array(ty, n-diff);
+        let llty_array = type_of::type_of(bcx.ccx(), array_ty);
+        return PointerCast(bcx, slice_begin, llty_array.ptr_to());
+    }
+
+    let slice_len_offset = C_uint(bcx.ccx(), diff);
     let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None);
-    let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic),
+    let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased),
                                          bcx.tcx().mk_slice(unit_ty));
     let scratch = rvalue_scratch_datum(bcx, slice_ty, "");
     Store(bcx, slice_begin, expr::get_dataptr(bcx, scratch.val));
@@ -787,7 +795,7 @@ fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool {
         match pat.node {
             PatKind::Tuple(..) => true,
             PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => {
-                match tcx.def_map.borrow().get(&pat.id).unwrap().full_def() {
+                match tcx.expect_def(pat.id) {
                     Def::Struct(..) | Def::TyAlias(..) => true,
                     _ => false,
                 }
@@ -1205,7 +1213,12 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
         Some(field_vals)
     } else if any_uniq_pat(m, col) || any_region_pat(m, col) {
-        Some(vec!(Load(bcx, val.val)))
+        let ptr = if type_is_fat_ptr(bcx.tcx(), left_ty) {
+            val.val
+        } else {
+            Load(bcx, val.val)
+        };
+        Some(vec!(ptr))
     } else {
         match left_ty.sty {
             ty::TyArray(_, n) => {
@@ -1430,19 +1443,19 @@ pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// Checks whether the binding in `discr` is assigned to anywhere in the expression `body`
 fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool {
     let (vid, field) = match discr.node {
-        hir::ExprPath(..) => match bcx.def(discr.id) {
+        hir::ExprPath(..) => match bcx.tcx().expect_def(discr.id) {
             Def::Local(_, vid) | Def::Upvar(_, vid, _, _) => (vid, None),
             _ => return false
         },
         hir::ExprField(ref base, field) => {
-            let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
+            let vid = match bcx.tcx().expect_def_or_none(base.id) {
                 Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
                 _ => return false
             };
             (vid, Some(mc::NamedField(field.node)))
         },
         hir::ExprTupField(ref base, field) => {
-            let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
+            let vid = match bcx.tcx().expect_def_or_none(base.id) {
                 Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
                 _ => return false
             };
@@ -1821,9 +1834,8 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             }
         }
         PatKind::TupleStruct(_, ref sub_pats, ddpos) => {
-            let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
-            match opt_def {
-                Some(Def::Variant(enum_id, var_id)) => {
+            match bcx.tcx().expect_def(pat.id) {
+                Def::Variant(enum_id, var_id) => {
                     let repr = adt::represent_node(bcx, pat.id);
                     let vinfo = ccx.tcx().lookup_adt_def(enum_id).variant_with_id(var_id);
                     let args = extract_variant_args(bcx,
@@ -1839,7 +1851,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                             cleanup_scope);
                     }
                 }
-                Some(Def::Struct(..)) => {
+                Def::Struct(..) => {
                     let expected_len = match *ccx.tcx().pat_ty(&pat) {
                         ty::TyS{sty: ty::TyStruct(adt_def, _), ..} => {
                             adt_def.struct_variant().fields.len()
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 9bbe0cb5f69..df3d2d149b9 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -10,8 +10,8 @@
 
 use llvm::{self, ValueRef};
 use base;
-use builder::Builder;
-use common::{type_is_fat_ptr, BlockAndBuilder};
+use build::AllocaFcx;
+use common::{type_is_fat_ptr, BlockAndBuilder, C_uint};
 use context::CrateContext;
 use cabi_x86;
 use cabi_x86_64;
@@ -22,7 +22,7 @@ use cabi_powerpc;
 use cabi_powerpc64;
 use cabi_mips;
 use cabi_asmjs;
-use machine::{llalign_of_min, llsize_of, llsize_of_real};
+use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store};
 use type_::Type;
 use type_of;
 
@@ -30,6 +30,7 @@ use rustc::hir;
 use rustc::ty::{self, Ty};
 
 use libc::c_uint;
+use std::cmp;
 
 pub use syntax::abi::Abi;
 pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
@@ -150,26 +151,63 @@ impl ArgType {
     /// lvalue for the original Rust type of this argument/return.
     /// Can be used for both storing formal arguments into Rust variables
     /// or results of call/invoke instructions into their destinations.
-    pub fn store(&self, b: &Builder, mut val: ValueRef, dst: ValueRef) {
+    pub fn store(&self, bcx: &BlockAndBuilder, mut val: ValueRef, dst: ValueRef) {
         if self.is_ignore() {
             return;
         }
+        let ccx = bcx.ccx();
         if self.is_indirect() {
-            let llsz = llsize_of(b.ccx, self.ty);
-            let llalign = llalign_of_min(b.ccx, self.ty);
-            base::call_memcpy(b, dst, val, llsz, llalign as u32);
+            let llsz = llsize_of(ccx, self.ty);
+            let llalign = llalign_of_min(ccx, self.ty);
+            base::call_memcpy(bcx, dst, val, llsz, llalign as u32);
         } else if let Some(ty) = self.cast {
-            let cast_dst = b.pointercast(dst, ty.ptr_to());
-            let store = b.store(val, cast_dst);
-            let llalign = llalign_of_min(b.ccx, self.ty);
-            unsafe {
-                llvm::LLVMSetAlignment(store, llalign);
+            // FIXME(eddyb): Figure out when the simpler Store is safe, clang
+            // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
+            let can_store_through_cast_ptr = false;
+            if can_store_through_cast_ptr {
+                let cast_dst = bcx.pointercast(dst, ty.ptr_to());
+                let store = bcx.store(val, cast_dst);
+                let llalign = llalign_of_min(ccx, self.ty);
+                unsafe {
+                    llvm::LLVMSetAlignment(store, llalign);
+                }
+            } else {
+                // The actual return type is a struct, but the ABI
+                // adaptation code has cast it into some scalar type.  The
+                // code that follows is the only reliable way I have
+                // found to do a transform like i64 -> {i32,i32}.
+                // Basically we dump the data onto the stack then memcpy it.
+                //
+                // Other approaches I tried:
+                // - Casting rust ret pointer to the foreign type and using Store
+                //   is (a) unsafe if size of foreign type > size of rust type and
+                //   (b) runs afoul of strict aliasing rules, yielding invalid
+                //   assembly under -O (specifically, the store gets removed).
+                // - Truncating foreign type to correct integral type and then
+                //   bitcasting to the struct type yields invalid cast errors.
+
+                // We instead thus allocate some scratch space...
+                let llscratch = AllocaFcx(bcx.fcx(), ty, "abi_cast");
+                base::Lifetime::Start.call(bcx, llscratch);
+
+                // ...where we first store the value...
+                bcx.store(val, llscratch);
+
+                // ...and then memcpy it to the intended destination.
+                base::call_memcpy(bcx,
+                                  bcx.pointercast(dst, Type::i8p(ccx)),
+                                  bcx.pointercast(llscratch, Type::i8p(ccx)),
+                                  C_uint(ccx, llsize_of_store(ccx, self.ty)),
+                                  cmp::min(llalign_of_min(ccx, self.ty),
+                                           llalign_of_min(ccx, ty)) as u32);
+
+                base::Lifetime::End.call(bcx, llscratch);
             }
         } else {
-            if self.original_ty == Type::i1(b.ccx) {
-                val = b.zext(val, Type::i8(b.ccx));
+            if self.original_ty == Type::i1(ccx) {
+                val = bcx.zext(val, Type::i8(ccx));
             }
-            b.store(val, dst);
+            bcx.store(val, dst);
         }
     }
 
diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs
index aea61da18a0..29019f3683d 100644
--- a/src/librustc_trans/back/archive.rs
+++ b/src/librustc_trans/back/archive.rs
@@ -10,14 +10,10 @@
 
 //! A helper class for dealing with static archives
 
-use std::env;
 use std::ffi::{CString, CStr, OsString};
-use std::fs::{self, File};
-use std::io::prelude::*;
 use std::io;
 use std::mem;
 use std::path::{Path, PathBuf};
-use std::process::{Command, Output, Stdio};
 use std::ptr;
 use std::str;
 
@@ -25,7 +21,6 @@ use libc;
 use llvm::archive_ro::{ArchiveRO, Child};
 use llvm::{self, ArchiveKind};
 use rustc::session::Session;
-use rustc_back::tempdir::TempDir;
 
 pub struct ArchiveConfig<'a> {
     pub sess: &'a Session,
@@ -41,7 +36,6 @@ pub struct ArchiveConfig<'a> {
 #[must_use = "must call build() to finish building the archive"]
 pub struct ArchiveBuilder<'a> {
     config: ArchiveConfig<'a>,
-    work_dir: TempDir,
     removals: Vec<String>,
     additions: Vec<Addition>,
     should_update_symbols: bool,
@@ -55,17 +49,10 @@ enum Addition {
     },
     Archive {
         archive: ArchiveRO,
-        archive_name: String,
         skip: Box<FnMut(&str) -> bool>,
     },
 }
 
-enum Action<'a> {
-    Remove(&'a [String]),
-    AddObjects(&'a [&'a PathBuf], bool),
-    UpdateSymbols,
-}
-
 pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session)
                     -> PathBuf {
     // On Windows, static libraries sometimes show up as libfoo.a and other
@@ -102,7 +89,6 @@ impl<'a> ArchiveBuilder<'a> {
     pub fn new(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> {
         ArchiveBuilder {
             config: config,
-            work_dir: TempDir::new("rsar").unwrap(),
             removals: Vec::new(),
             additions: Vec::new(),
             should_update_symbols: false,
@@ -148,7 +134,7 @@ impl<'a> ArchiveBuilder<'a> {
     pub fn add_native_library(&mut self, name: &str) {
         let location = find_library(name, &self.config.lib_search_paths,
                                     self.config.sess);
-        self.add_archive(&location, name, |_| false).unwrap_or_else(|e| {
+        self.add_archive(&location, |_| false).unwrap_or_else(|e| {
             self.config.sess.fatal(&format!("failed to add native library {}: {}",
                                             location.to_string_lossy(), e));
         });
@@ -172,14 +158,14 @@ impl<'a> ArchiveBuilder<'a> {
         let metadata_filename =
             self.config.sess.cstore.metadata_filename().to_owned();
 
-        self.add_archive(rlib, &name[..], move |fname: &str| {
+        self.add_archive(rlib, move |fname: &str| {
             let skip_obj = lto && fname.starts_with(&obj_start)
                 && fname.ends_with(".o");
             skip_obj || fname.ends_with(bc_ext) || fname == metadata_filename
         })
     }
 
-    fn add_archive<F>(&mut self, archive: &Path, name: &str, skip: F)
+    fn add_archive<F>(&mut self, archive: &Path, skip: F)
                       -> io::Result<()>
         where F: FnMut(&str) -> bool + 'static
     {
@@ -190,7 +176,6 @@ impl<'a> ArchiveBuilder<'a> {
         };
         self.additions.push(Addition::Archive {
             archive: archive,
-            archive_name: name.to_string(),
             skip: Box::new(skip),
         });
         Ok(())
@@ -214,234 +199,23 @@ impl<'a> ArchiveBuilder<'a> {
     /// Combine the provided files, rlibs, and native libraries into a single
     /// `Archive`.
     pub fn build(&mut self) {
-        let res = match self.llvm_archive_kind() {
-            Some(kind) => self.build_with_llvm(kind),
-            None => self.build_with_ar_cmd(),
-        };
-        if let Err(e) = res {
-            self.config.sess.fatal(&format!("failed to build archive: {}", e));
-        }
-    }
-
-    pub fn llvm_archive_kind(&self) -> Option<ArchiveKind> {
-        if unsafe { llvm::LLVMVersionMinor() < 7 } {
-            return None
-        }
-
-        // Currently LLVM only supports writing archives in the 'gnu' format.
-        match &self.config.sess.target.target.options.archive_format[..] {
-            "gnu" => Some(ArchiveKind::K_GNU),
-            "mips64" => Some(ArchiveKind::K_MIPS64),
-            "bsd" => Some(ArchiveKind::K_BSD),
-            "coff" => Some(ArchiveKind::K_COFF),
-            _ => None,
-        }
-    }
-
-    pub fn using_llvm(&self) -> bool {
-        self.llvm_archive_kind().is_some()
-    }
-
-    fn build_with_ar_cmd(&mut self) -> io::Result<()> {
-        let removals = mem::replace(&mut self.removals, Vec::new());
-        let additions = mem::replace(&mut self.additions, Vec::new());
-        let should_update_symbols = mem::replace(&mut self.should_update_symbols,
-                                                 false);
-
-        // Don't use fs::copy because libs may be installed as read-only and we
-        // want to modify this archive, so we use `io::copy` to not preserve
-        // permission bits.
-        if let Some(ref s) = self.config.src {
-            io::copy(&mut File::open(s)?,
-                     &mut File::create(&self.config.dst)?)?;
-        }
-
-        if removals.len() > 0 {
-            self.run(None, Action::Remove(&removals));
-        }
-
-        let mut members = Vec::new();
-        for addition in additions {
-            match addition {
-                Addition::File { path, name_in_archive } => {
-                    let dst = self.work_dir.path().join(&name_in_archive);
-                    fs::copy(&path, &dst)?;
-                    members.push(PathBuf::from(name_in_archive));
-                }
-                Addition::Archive { archive, archive_name, mut skip } => {
-                    self.add_archive_members(&mut members, archive,
-                                             &archive_name, &mut *skip)?;
-                }
-            }
-        }
-
-        // Get an absolute path to the destination, so `ar` will work even
-        // though we run it from `self.work_dir`.
-        let mut objects = Vec::new();
-        let mut total_len = self.config.dst.to_string_lossy().len();
-
-        if members.is_empty() {
-            if should_update_symbols {
-                self.run(Some(self.work_dir.path()), Action::UpdateSymbols);
-            }
-            return Ok(())
-        }
-
-        // Don't allow the total size of `args` to grow beyond 32,000 bytes.
-        // Windows will raise an error if the argument string is longer than
-        // 32,768, and we leave a bit of extra space for the program name.
-        const ARG_LENGTH_LIMIT: usize = 32_000;
-
-        for member_name in &members {
-            let len = member_name.to_string_lossy().len();
-
-            // `len + 1` to account for the space that's inserted before each
-            // argument.  (Windows passes command-line arguments as a single
-            // string, not an array of strings.)
-            if total_len + len + 1 > ARG_LENGTH_LIMIT {
-                // Add the archive members seen so far, without updating the
-                // symbol table.
-                self.run(Some(self.work_dir.path()),
-                         Action::AddObjects(&objects, false));
-
-                objects.clear();
-                total_len = self.config.dst.to_string_lossy().len();
-            }
-
-            objects.push(member_name);
-            total_len += len + 1;
-        }
-
-        // Add the remaining archive members, and update the symbol table if
-        // necessary.
-        self.run(Some(self.work_dir.path()),
-                         Action::AddObjects(&objects, should_update_symbols));
-        Ok(())
-    }
-
-    fn add_archive_members(&mut self, members: &mut Vec<PathBuf>,
-                           archive: ArchiveRO, name: &str,
-                           skip: &mut FnMut(&str) -> bool) -> io::Result<()> {
-        // Next, we must rename all of the inputs to "guaranteed unique names".
-        // We write each file into `self.work_dir` under its new unique name.
-        // The reason for this renaming is that archives are keyed off the name
-        // of the files, so if two files have the same name they will override
-        // one another in the archive (bad).
-        //
-        // We skip any files explicitly desired for skipping, and we also skip
-        // all SYMDEF files as these are just magical placeholders which get
-        // re-created when we make a new archive anyway.
-        for file in archive.iter() {
-            let file = file.map_err(string_to_io_error)?;
-            if !is_relevant_child(&file) {
-                continue
-            }
-            let filename = file.name().unwrap();
-            if skip(filename) {
-                continue
+        let kind = match self.llvm_archive_kind() {
+            Ok(kind) => kind,
+            Err(kind) => {
+                self.config.sess.fatal(&format!("Don't know how to build archive of type: {}",
+                                                kind));
             }
-            let filename = Path::new(filename).file_name().unwrap()
-                                              .to_str().unwrap();
-
-            // Archives on unix systems typically do not have slashes in
-            // filenames as the `ar` utility generally only uses the last
-            // component of a path for the filename list in the archive. On
-            // Windows, however, archives assembled with `lib.exe` will preserve
-            // the full path to the file that was placed in the archive,
-            // including path separators.
-            //
-            // The code below is munging paths so it'll go wrong pretty quickly
-            // if there's some unexpected slashes in the filename, so here we
-            // just chop off everything but the filename component. Note that
-            // this can cause duplicate filenames, but that's also handled below
-            // as well.
-            let filename = Path::new(filename).file_name().unwrap()
-                                              .to_str().unwrap();
-
-            // An archive can contain files of the same name multiple times, so
-            // we need to be sure to not have them overwrite one another when we
-            // extract them. Consequently we need to find a truly unique file
-            // name for us!
-            let mut new_filename = String::new();
-            for n in 0.. {
-                let n = if n == 0 {String::new()} else {format!("-{}", n)};
-                new_filename = format!("r{}-{}-{}", n, name, filename);
-
-                // LLDB (as mentioned in back::link) crashes on filenames of
-                // exactly
-                // 16 bytes in length. If we're including an object file with
-                //    exactly 16-bytes of characters, give it some prefix so
-                //    that it's not 16 bytes.
-                new_filename = if new_filename.len() == 16 {
-                    format!("lldb-fix-{}", new_filename)
-                } else {
-                    new_filename
-                };
-
-                let present = members.iter().filter_map(|p| {
-                    p.file_name().and_then(|f| f.to_str())
-                }).any(|s| s == new_filename);
-                if !present {
-                    break
-                }
-            }
-            let dst = self.work_dir.path().join(&new_filename);
-            File::create(&dst)?.write_all(file.data())?;
-            members.push(PathBuf::from(new_filename));
-        }
-        Ok(())
-    }
-
-    fn run(&self, cwd: Option<&Path>, action: Action) -> Output {
-        let abs_dst = env::current_dir().unwrap().join(&self.config.dst);
-        let ar = &self.config.ar_prog;
-        let mut cmd = Command::new(ar);
-        cmd.env("PATH", &self.config.command_path);
-        cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
-        self.prepare_ar_action(&mut cmd, &abs_dst, action);
-        info!("{:?}", cmd);
+        };
 
-        if let Some(p) = cwd {
-            cmd.current_dir(p);
-            info!("inside {:?}", p.display());
+        if let Err(e) = self.build_with_llvm(kind) {
+            self.config.sess.fatal(&format!("failed to build archive: {}", e));
         }
 
-        let sess = &self.config.sess;
-        match cmd.spawn() {
-            Ok(prog) => {
-                let o = prog.wait_with_output().unwrap();
-                if !o.status.success() {
-                    sess.struct_err(&format!("{:?} failed with: {}", cmd, o.status))
-                        .note(&format!("stdout ---\n{}",
-                                       str::from_utf8(&o.stdout).unwrap()))
-                        .note(&format!("stderr ---\n{}",
-                                       str::from_utf8(&o.stderr).unwrap()))
-                        .emit();
-                    sess.abort_if_errors();
-                }
-                o
-            },
-            Err(e) => {
-                sess.fatal(&format!("could not exec `{}`: {}",
-                                    self.config.ar_prog, e));
-            }
-        }
     }
 
-    fn prepare_ar_action(&self, cmd: &mut Command, dst: &Path, action: Action) {
-        match action {
-            Action::Remove(files) => {
-                cmd.arg("d").arg(dst).args(files);
-            }
-            Action::AddObjects(objs, update_symbols) => {
-                cmd.arg(if update_symbols {"crs"} else {"crS"})
-                   .arg(dst)
-                   .args(objs);
-            }
-            Action::UpdateSymbols => {
-                cmd.arg("s").arg(dst);
-            }
-        }
+    fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
+        let kind = &self.config.sess.target.target.options.archive_format[..];
+        kind.parse().map_err(|_| kind)
     }
 
     fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
@@ -480,7 +254,7 @@ impl<'a> ArchiveBuilder<'a> {
                         strings.push(path);
                         strings.push(name);
                     }
-                    Addition::Archive { archive, archive_name: _, mut skip } => {
+                    Addition::Archive { archive, mut skip } => {
                         for child in archive.iter() {
                             let child = child.map_err(string_to_io_error)?;
                             if !is_relevant_child(&child) {
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 6e5964d83c0..4676b0a67e4 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -412,13 +412,6 @@ fn link_rlib<'a>(sess: &'a Session,
     // symbol table of the archive.
     ab.update_symbols();
 
-    // For OSX/iOS, we must be careful to update symbols only when adding
-    // object files.  We're about to start adding non-object files, so run
-    // `ar` now to process the object files.
-    if sess.target.target.options.is_like_osx && !ab.using_llvm() {
-        ab.build();
-    }
-
     // Note that it is important that we add all of our non-object "magical
     // files" *after* all of the object files in the archive. The reason for
     // this is as follows:
@@ -515,7 +508,7 @@ fn link_rlib<'a>(sess: &'a Session,
             // After adding all files to the archive, we need to update the
             // symbol table of the archive. This currently dies on OSX (see
             // #11162), and isn't necessary there anyway
-            if !sess.target.target.options.is_like_osx || ab.using_llvm() {
+            if !sess.target.target.options.is_like_osx {
                 ab.update_symbols();
             }
         }
@@ -575,9 +568,6 @@ fn write_rlib_bytecode_object_v1(writer: &mut Write,
 fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
                   tempdir: &Path) {
     let mut ab = link_rlib(sess, None, objects, out_filename, tempdir);
-    if sess.target.target.options.is_like_osx && !ab.using_llvm() {
-        ab.build();
-    }
     if !sess.target.target.options.no_compiler_rt {
         ab.add_native_library("compiler-rt");
     }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index cd20a75db81..5250361cd17 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1043,7 +1043,7 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) ->
     next_cx
 }
 
-enum Lifetime { Start, End }
+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`
@@ -1080,24 +1080,25 @@ fn core_lifetime_emit<'blk, 'tcx, F>(ccx: &'blk CrateContext<'blk, 'tcx>,
     emit(ccx, size, lifetime_intrinsic)
 }
 
-pub fn call_lifetime_start(cx: Block, ptr: ValueRef) {
-    core_lifetime_emit(cx.ccx(), ptr, Lifetime::Start, |ccx, size, lifetime_start| {
-        let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
-        Call(cx,
-             lifetime_start,
-             &[C_u64(ccx, size), ptr],
-             DebugLoc::None);
-    })
+impl Lifetime {
+    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);
+        });
+    }
 }
 
-pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
-    core_lifetime_emit(cx.ccx(), ptr, Lifetime::End, |ccx, size, lifetime_end| {
-        let ptr = PointerCast(cx, ptr, Type::i8p(ccx));
-        Call(cx,
-             lifetime_end,
-             &[C_u64(ccx, size), ptr],
-             DebugLoc::None);
-    })
+pub fn call_lifetime_start(bcx: Block, ptr: ValueRef) {
+    if !bcx.unreachable.get() {
+        Lifetime::Start.call(&bcx.build(), ptr);
+    }
+}
+
+pub fn call_lifetime_end(bcx: Block, ptr: ValueRef) {
+    if !bcx.unreachable.get() {
+        Lifetime::End.call(&bcx.build(), ptr);
+    }
 }
 
 // Generates code for resumption of unwind at the end of a landing pad.
@@ -1664,29 +1665,21 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
                                       arg_ty,
                                       datum::Lvalue::new("FunctionContext::bind_args"))
                 } else {
-                    let lltmp = if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
-                        let lltemp = alloc_ty(bcx, arg_ty, "");
-                        let b = &bcx.build();
-                        // 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 = &self.fn_ty.args[idx];
-                        idx += 1;
-                        arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, lltemp));
-                        meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, lltemp));
-                        lltemp
-                    } else  {
-                        // otherwise, arg is passed by value, so store it into a temporary.
-                        let llarg_ty = arg.cast.unwrap_or(arg.memory_ty(bcx.ccx()));
-                        let lltemp = alloca(bcx, llarg_ty, "");
+                    unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "",
+                                                                   uninit_reason,
+                                                                   arg_scope_id, |bcx, dst| {
+                        debug!("FunctionContext::bind_args: {:?}: {:?}", hir_arg, arg_ty);
                         let b = &bcx.build();
-                        arg.store_fn_arg(b, &mut llarg_idx, lltemp);
-                        // And coerce the temporary into the type we expect.
-                        b.pointercast(lltemp, arg.memory_ty(bcx.ccx()).ptr_to())
-                    };
-                    bcx.fcx.schedule_drop_mem(arg_scope_id, lltmp, arg_ty, None);
-                    datum::Datum::new(lltmp, arg_ty,
-                                      datum::Lvalue::new("bind_args"))
+                        if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
+                            let meta = &self.fn_ty.args[idx];
+                            idx += 1;
+                            arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst));
+                            meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst));
+                        } else {
+                            arg.store_fn_arg(b, &mut llarg_idx, dst);
+                        }
+                        bcx
+                    }))
                 }
             } else {
                 // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for.
@@ -1721,19 +1714,16 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
             };
 
             let pat = &hir_arg.pat;
-            bcx = match simple_name(pat) {
-                // The check for alloca is necessary because above for the immediate argument case
-                // we had to cast. At this point arg_datum is not an alloca anymore and thus
-                // breaks debuginfo if we allow this optimisation.
-                Some(name)
-                if unsafe { llvm::LLVMIsAAllocaInst(arg_datum.val) != ::std::ptr::null_mut() } => {
-                    // Generate nicer LLVM for the common case of fn a pattern
-                    // like `x: T`
-                    set_value_name(arg_datum.val, &bcx.name(name));
-                    self.lllocals.borrow_mut().insert(pat.id, arg_datum);
-                    bcx
-                },
-                _ => _match::bind_irrefutable_pat(bcx, pat, arg_datum.match_input(), arg_scope_id)
+            bcx = if let Some(name) = simple_name(pat) {
+                // Generate nicer LLVM for the common case of fn a pattern
+                // like `x: T`
+                set_value_name(arg_datum.val, &bcx.name(name));
+                self.lllocals.borrow_mut().insert(pat.id, arg_datum);
+                bcx
+            } else {
+                // General path. Copy out the values that are used in the
+                // pattern.
+                _match::bind_irrefutable_pat(bcx, pat, arg_datum.match_input(), arg_scope_id)
             };
             debuginfo::create_argument_metadata(bcx, hir_arg);
         }
@@ -1854,7 +1844,10 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         attributes::emit_uwtable(llfndecl, true);
     }
 
-    debug!("trans_closure(..., {})", instance);
+    // this is an info! to allow collecting monomorphization statistics
+    // and to allow finding the last function before LLVM aborts from
+    // release builds.
+    info!("trans_closure(..., {})", instance);
 
     let fn_ty = FnType::new(ccx, abi, sig, &[]);
 
@@ -2259,17 +2252,14 @@ pub fn update_linkage(ccx: &CrateContext,
 }
 
 fn set_global_section(ccx: &CrateContext, llval: ValueRef, i: &hir::Item) {
-    match attr::first_attr_value_str_by_name(&i.attrs, "link_section") {
-        Some(sect) => {
-            if contains_null(&sect) {
-                ccx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", &sect));
-            }
-            unsafe {
-                let buf = CString::new(sect.as_bytes()).unwrap();
-                llvm::LLVMSetSection(llval, buf.as_ptr());
-            }
-        },
-        None => ()
+    if let Some(sect) = attr::first_attr_value_str_by_name(&i.attrs, "link_section") {
+        if contains_null(&sect) {
+            ccx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", &sect));
+        }
+        unsafe {
+            let buf = CString::new(sect.as_bytes()).unwrap();
+            llvm::LLVMSetSection(llval, buf.as_ptr());
+        }
     }
 }
 
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 5b2cfbe4649..7099246c6ab 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -34,8 +34,7 @@ use build::*;
 use cleanup;
 use cleanup::CleanupMethods;
 use closure;
-use common::{self, Block, Result, CrateContext, FunctionContext};
-use common::{C_uint, C_undef};
+use common::{self, Block, Result, CrateContext, FunctionContext, C_undef};
 use consts;
 use datum::*;
 use debuginfo::DebugLoc;
@@ -44,7 +43,7 @@ use expr;
 use glue;
 use inline;
 use intrinsic;
-use machine::{llalign_of_min, llsize_of_store};
+use machine::llalign_of_min;
 use meth;
 use monomorphize::{self, Instance};
 use type_::Type;
@@ -58,8 +57,6 @@ use syntax::codemap::DUMMY_SP;
 use syntax::errors;
 use syntax::ptr::P;
 
-use std::cmp;
-
 #[derive(Debug)]
 pub enum CalleeData {
     /// Constructor for enum variant/tuple-like-struct.
@@ -328,7 +325,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     };
 
     let bare_fn_ty_maybe_ref = if is_by_ref {
-        tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty)
+        tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), bare_fn_ty)
     } else {
         bare_fn_ty
     };
@@ -689,49 +686,16 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let (llret, mut 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_ignore() && !fn_ty.ret.is_indirect() {
-        if let Some(llforeign_ret_ty) = fn_ty.ret.cast {
-            let llrust_ret_ty = fn_ty.ret.original_ty;
-            let llretslot = opt_llretslot.unwrap();
-
-            // The actual return type is a struct, but the ABI
-            // adaptation code has cast it into some scalar type.  The
-            // code that follows is the only reliable way I have
-            // found to do a transform like i64 -> {i32,i32}.
-            // Basically we dump the data onto the stack then memcpy it.
-            //
-            // Other approaches I tried:
-            // - Casting rust ret pointer to the foreign type and using Store
-            //   is (a) unsafe if size of foreign type > size of rust type and
-            //   (b) runs afoul of strict aliasing rules, yielding invalid
-            //   assembly under -O (specifically, the store gets removed).
-            // - Truncating foreign type to correct integral type and then
-            //   bitcasting to the struct type yields invalid cast errors.
-            let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
-            base::call_lifetime_start(bcx, llscratch);
-            Store(bcx, llret, llscratch);
-            let llscratch_i8 = PointerCast(bcx, llscratch, Type::i8(ccx).ptr_to());
-            let llretptr_i8 = PointerCast(bcx, llretslot, Type::i8(ccx).ptr_to());
-            let llrust_size = llsize_of_store(ccx, llrust_ret_ty);
-            let llforeign_align = llalign_of_min(ccx, llforeign_ret_ty);
-            let llrust_align = llalign_of_min(ccx, llrust_ret_ty);
-            let llalign = cmp::min(llforeign_align, llrust_align);
-            debug!("llrust_size={}", llrust_size);
-
-            if !bcx.unreachable.get() {
-                base::call_memcpy(&B(bcx), llretptr_i8, llscratch_i8,
-                                  C_uint(ccx, llrust_size), llalign as u32);
+        // 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);
             }
-            base::call_lifetime_end(bcx, llscratch);
-        } else if let Some(llretslot) = opt_llretslot {
-            base::store_ty(bcx, llret, llretslot, output.unwrap());
         }
     }
 
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 9cc5cbbbb65..9196cfce16f 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -123,10 +123,10 @@ fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            -> Ty<'tcx> {
     match tcx.closure_kind(closure_id) {
         ty::ClosureKind::Fn => {
-            tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), fn_ty)
+            tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), fn_ty)
         }
         ty::ClosureKind::FnMut => {
-            tcx.mk_mut_ref(tcx.mk_region(ty::ReStatic), fn_ty)
+            tcx.mk_mut_ref(tcx.mk_region(ty::ReErased), fn_ty)
         }
         ty::ClosureKind::FnOnce => fn_ty,
     }
@@ -344,7 +344,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     // Find a version of the closure type. Substitute static for the
     // region since it doesn't really matter.
     let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, substs);
-    let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), closure_ty);
+    let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
 
     // Make a version with the type of by-ref closure.
     let ty::ClosureTy { unsafety, abi, mut sig } =
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 884833ca79a..6b8198881c8 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -260,8 +260,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> {
 
     /// Return the variant corresponding to a given node (e.g. expr)
     pub fn of_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, id: ast::NodeId) -> Self {
-        let node_def = tcx.def_map.borrow().get(&id).map(|v| v.full_def());
-        Self::from_ty(tcx, ty, node_def)
+        Self::from_ty(tcx, ty, Some(tcx.expect_def(id)))
     }
 
     pub fn field_index(&self, name: ast::Name) -> usize {
@@ -656,15 +655,6 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
         self.tcx().map.node_to_string(id).to_string()
     }
 
-    pub fn def(&self, nid: ast::NodeId) -> Def {
-        match self.tcx().def_map.borrow().get(&nid) {
-            Some(v) => v.full_def(),
-            None => {
-                bug!("no def associated with node id {}", nid);
-            }
-        }
-    }
-
     pub fn to_str(&self) -> String {
         format!("[block {:p}]", self)
     }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 6788d5de6d8..e988d2e6ac3 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -297,8 +297,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // `def` must be its own statement and cannot be in the `match`
         // otherwise the `def_map` will be borrowed for the entire match instead
         // of just to get the `def` value
-        let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
-        match def {
+        match ccx.tcx().expect_def(expr.id) {
             Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                 if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
                     debug!("get_const_expr_as_global ({:?}): found const {:?}",
@@ -382,7 +381,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     // Don't copy data to do a deref+ref
                     // (i.e., skip the last auto-deref).
                     llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref");
-                    ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty);
+                    ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReErased), ty);
                 }
             } else if adj.autoderefs > 0 {
                 let (dv, dt) = const_deref(cx, llconst, ty);
@@ -803,8 +802,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     _ => break,
                 }
             }
-            let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
-            if let Some(Def::Static(def_id, _)) = opt_def {
+            if let Some(Def::Static(def_id, _)) = cx.tcx().expect_def_or_none(cur.id) {
                 get_static(cx, def_id).val
             } else {
                 // If this isn't the address of a static, then keep going through
@@ -891,8 +889,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }
         },
         hir::ExprPath(..) => {
-            let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
-            match def {
+            match cx.tcx().expect_def(e.id) {
                 Def::Local(_, id) => {
                     if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
                         val
@@ -937,9 +934,8 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     _ => break,
                 };
             }
-            let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
             let arg_vals = map_list(args)?;
-            match def {
+            match cx.tcx().expect_def(callee.id) {
                 Def::Fn(did) | Def::Method(did) => {
                     const_fn_call(
                         cx,
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 1ddcbc79aed..bfcb1ae33b3 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -495,7 +495,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         assert!(scheme.generics.types.is_empty());
         self.tcx().mk_substs(
             Substs::new(VecPerParamSpace::empty(),
-                        scheme.generics.regions.map(|_| ty::ReStatic)))
+                        scheme.generics.regions.map(|_| ty::ReErased)))
     }
 
     pub fn symbol_hasher(&self) -> &RefCell<Sha256> {
@@ -1097,45 +1097,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option<ValueRef> {
     ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p);
     ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p);
 
-    // Some intrinsics were introduced in later versions of LLVM, but they have
-    // fallbacks in libc or libm and such.
-    macro_rules! compatible_ifn {
-        ($name:expr, noop($cname:ident ($($arg:expr),*) -> void), $llvm_version:expr) => (
-            if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
-                // The `if key == $name` is already in ifn!
-                ifn!($name, fn($($arg),*) -> void);
-            } else if key == $name {
-                let f = declare::declare_cfn(ccx, stringify!($cname),
-                                             Type::func(&[$($arg),*], &void));
-                llvm::SetLinkage(f, llvm::InternalLinkage);
-
-                let bld = ccx.builder();
-                let llbb = unsafe {
-                    llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), f,
-                                                        "entry-block\0".as_ptr() as *const _)
-                };
-
-                bld.position_at_end(llbb);
-                bld.ret_void();
-
-                ccx.intrinsics().borrow_mut().insert($name, f.clone());
-                return Some(f);
-            }
-        );
-        ($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr, $llvm_version:expr) => (
-            if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
-                // The `if key == $name` is already in ifn!
-                ifn!($name, fn($($arg),*) -> $ret);
-            } else if key == $name {
-                let f = declare::declare_cfn(ccx, stringify!($cname),
-                                             Type::func(&[$($arg),*], &$ret));
-                ccx.intrinsics().borrow_mut().insert($name, f.clone());
-                return Some(f);
-            }
-        )
-    }
-
-    compatible_ifn!("llvm.assume", noop(llvmcompat_assume(i1) -> void), 6);
+    ifn!("llvm.assume", fn(i1) -> void);
 
     if ccx.sess().opts.debuginfo != NoDebugInfo {
         ifn!("llvm.dbg.declare", fn(Type::metadata(ccx), Type::metadata(ccx)) -> void);
diff --git a/src/librustc_trans/controlflow.rs b/src/librustc_trans/controlflow.rs
index 0f686227c6f..8845f124218 100644
--- a/src/librustc_trans/controlflow.rs
+++ b/src/librustc_trans/controlflow.rs
@@ -318,8 +318,8 @@ pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let loop_id = match opt_label {
         None => fcx.top_loop_scope(),
         Some(_) => {
-            match bcx.tcx().def_map.borrow().get(&expr.id).map(|d| d.full_def())  {
-                Some(Def::Label(loop_id)) => loop_id,
+            match bcx.tcx().expect_def(expr.id) {
+                Def::Label(loop_id) => loop_id,
                 r => {
                     bug!("{:?} in def-map for label", r)
                 }
diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs
index bba0edd5f04..b29ca515f8f 100644
--- a/src/librustc_trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/debuginfo/create_scope_map.rs
@@ -16,7 +16,7 @@ use llvm;
 use llvm::debuginfo::{DIScope, DISubprogram};
 use common::{CrateContext, FunctionContext};
 use rustc::hir::pat_util;
-use rustc::mir::repr::{Mir, ScopeId};
+use rustc::mir::repr::{Mir, VisibilityScope};
 use rustc::util::nodemap::NodeMap;
 
 use libc::c_uint;
@@ -26,6 +26,7 @@ use syntax::codemap::{Span, Pos};
 use syntax::{ast, codemap};
 
 use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc::hir::{self, PatKind};
 
 // This procedure builds the *scope map* for a given function, which maps any
@@ -50,7 +51,7 @@ pub fn create_scope_map(cx: &CrateContext,
     for arg in args {
         pat_util::pat_bindings(&arg.pat, |_, node_id, _, path1| {
             scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
-                                               name: Some(path1.node.unhygienize()) });
+                                               name: Some(path1.node) });
             scope_map.insert(node_id, fn_metadata);
         })
     }
@@ -69,9 +70,9 @@ pub fn create_scope_map(cx: &CrateContext,
 
 /// 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) -> Vec<DIScope> {
+pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, DIScope> {
     let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
-    let mut scopes = vec![ptr::null_mut(); mir.scopes.len()];
+    let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes);
 
     let fn_metadata = match fcx.debug_context {
         FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
@@ -82,14 +83,14 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec<DIScope> {
     };
 
     // Find all the scopes with variables defined in them.
-    let mut has_variables = BitVector::new(mir.scopes.len());
+    let mut has_variables = BitVector::new(mir.visibility_scopes.len());
     for var in &mir.var_decls {
-        has_variables.insert(var.scope.index());
+        has_variables.insert(var.source_info.scope.index());
     }
 
     // Instantiate all scopes.
-    for idx in 0..mir.scopes.len() {
-        let scope = ScopeId::new(idx);
+    for idx in 0..mir.visibility_scopes.len() {
+        let scope = VisibilityScope::new(idx);
         make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
     }
 
@@ -100,24 +101,23 @@ fn make_mir_scope(ccx: &CrateContext,
                   mir: &Mir,
                   has_variables: &BitVector,
                   fn_metadata: DISubprogram,
-                  scope: ScopeId,
-                  scopes: &mut [DIScope]) {
-    let idx = scope.index();
-    if !scopes[idx].is_null() {
+                  scope: VisibilityScope,
+                  scopes: &mut IndexVec<VisibilityScope, DIScope>) {
+    if !scopes[scope].is_null() {
         return;
     }
 
-    let scope_data = &mir.scopes[scope];
+    let scope_data = &mir.visibility_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
         make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
-        scopes[parent.index()]
+        scopes[parent]
     } else {
         // The root is the function itself.
-        scopes[idx] = fn_metadata;
+        scopes[scope] = fn_metadata;
         return;
     };
 
-    if !has_variables.contains(idx) {
+    if !has_variables.contains(scope.index()) {
         // Do not create a DIScope if there are no variables
         // defined in this MIR Scope, to avoid debuginfo bloat.
 
@@ -125,14 +125,14 @@ fn make_mir_scope(ccx: &CrateContext,
         // our parent is the root, because we might want to
         // put arguments in the root and not have shadowing.
         if parent_scope != fn_metadata {
-            scopes[idx] = parent_scope;
+            scopes[scope] = parent_scope;
             return;
         }
     }
 
     let loc = span_start(ccx, scope_data.span);
-    let file_metadata = file_metadata(ccx, &loc.file.name);
-    scopes[idx] = unsafe {
+    scopes[scope] = unsafe {
+    let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
         llvm::LLVMDIBuilderCreateLexicalBlock(
             DIB(ccx),
             parent_scope,
@@ -152,7 +152,7 @@ fn with_new_scope<F>(cx: &CrateContext,
 {
     // Create a new lexical scope and push it onto the stack
     let loc = span_start(cx, scope_span);
-    let file_metadata = file_metadata(cx, &loc.file.name);
+    let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
     let parent_scope = scope_stack.last().unwrap().scope_metadata;
 
     let scope_metadata = unsafe {
@@ -260,7 +260,7 @@ fn walk_pattern(cx: &CrateContext,
             // N.B.: this comparison must be UNhygienic... because
             // gdb knows nothing about the context, so any two
             // variables with the same name will cause the problem.
-            let name = path1.node.unhygienize();
+            let name = path1.node;
             let need_new_scope = scope_stack
                 .iter()
                 .any(|entry| entry.name == Some(name));
@@ -268,7 +268,7 @@ fn walk_pattern(cx: &CrateContext,
             if need_new_scope {
                 // Create a new lexical scope and push it onto the stack
                 let loc = span_start(cx, pat.span);
-                let file_metadata = file_metadata(cx, &loc.file.name);
+                let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
                 let parent_scope = scope_stack.last().unwrap().scope_metadata;
 
                 let scope_metadata = unsafe {
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index ab4860dff15..c6c28fc9ba6 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -563,7 +563,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     assert!(member_descriptions.len() == member_llvm_types.len());
 
     let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, &loc.file.name);
+    let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
 
     let metadata = composite_type_metadata(cx,
                                            slice_llvm_type,
@@ -853,17 +853,19 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     metadata
 }
 
-pub fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile {
+pub fn file_metadata(cx: &CrateContext, path: &str, full_path: &Option<String>) -> DIFile {
     // FIXME (#9639): This needs to handle non-utf8 paths
     let work_dir = cx.sess().working_dir.to_str().unwrap();
     let file_name =
-        if full_path.starts_with(work_dir) {
-            &full_path[work_dir.len() + 1..full_path.len()]
-        } else {
-            full_path
-        };
+        full_path.as_ref().map(|p| p.as_str()).unwrap_or_else(|| {
+            if path.starts_with(work_dir) {
+                &path[work_dir.len() + 1..path.len()]
+            } else {
+                path
+            }
+        });
 
-    file_metadata_(cx, full_path, file_name, &work_dir)
+    file_metadata_(cx, path, file_name, &work_dir)
 }
 
 pub fn unknown_file_metadata(cx: &CrateContext) -> DIFile {
@@ -874,9 +876,8 @@ pub fn unknown_file_metadata(cx: &CrateContext) -> DIFile {
 }
 
 fn file_metadata_(cx: &CrateContext, key: &str, file_name: &str, work_dir: &str) -> DIFile {
-    match debug_context(cx).created_files.borrow().get(key) {
-        Some(file_metadata) => return *file_metadata,
-        None => ()
+    if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(key) {
+        return *file_metadata;
     }
 
     debug!("file_metadata: file_name: {}, work_dir: {}", file_name, work_dir);
@@ -1850,7 +1851,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
 
     let (file_metadata, line_number) = if span != codemap::DUMMY_SP {
         let loc = span_start(cx, span);
-        (file_metadata(cx, &loc.file.name), loc.line as c_uint)
+        (file_metadata(cx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint)
     } else {
         (NO_FILE_METADATA, UNKNOWN_LINE_NUMBER)
     };
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index 6c1bd715f13..92b151c7c40 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -247,7 +247,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     }
 
     let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, &loc.file.name);
+    let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
 
     let function_type_metadata = unsafe {
         let fn_signature = get_function_signature(cx, sig, abi);
@@ -476,8 +476,9 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  span: Span) {
     let cx: &CrateContext = bcx.ccx();
 
-    let filename = span_start(cx, span).file.name.clone();
-    let file_metadata = file_metadata(cx, &filename[..]);
+    let file = span_start(cx, span).file;
+    let filename = file.name.clone();
+    let file_metadata = file_metadata(cx, &filename[..], &file.abs_path);
 
     let loc = span_start(cx, span);
     let type_metadata = type_metadata(cx, variable_type, span);
diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs
index fc31eaa4e74..a37fbdccc8f 100644
--- a/src/librustc_trans/debuginfo/namespace.rs
+++ b/src/librustc_trans/debuginfo/namespace.rs
@@ -72,7 +72,7 @@ pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope {
     let span = ccx.tcx().map.def_id_span(def_id, DUMMY_SP);
     let (file, line) = if span != DUMMY_SP {
         let loc = span_start(ccx, span);
-        (file_metadata(ccx, &loc.file.name), loc.line as c_uint)
+        (file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint)
     } else {
         (NO_FILE_METADATA, UNKNOWN_LINE_NUMBER)
     };
diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs
index 09fd3abd91f..652886ff2a0 100644
--- a/src/librustc_trans/expr.rs
+++ b/src/librustc_trans/expr.rs
@@ -153,7 +153,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             // have side effects. This seems to be reached through tuple struct constructors being
             // passed zero-size constants.
             if let hir::ExprPath(..) = expr.node {
-                match bcx.def(expr.id) {
+                match bcx.tcx().expect_def(expr.id) {
                     Def::Const(_) | Def::AssociatedConst(_) => {
                         assert!(type_is_zero_size(bcx.ccx(), bcx.tcx().node_id_to_type(expr.id)));
                         return bcx;
@@ -172,7 +172,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             // `[x; N]` somewhere within.
             match expr.node {
                 hir::ExprPath(..) => {
-                    match bcx.def(expr.id) {
+                    match bcx.tcx().expect_def(expr.id) {
                         Def::Const(did) | Def::AssociatedConst(did) => {
                             let empty_substs = bcx.tcx().mk_substs(Substs::empty());
                             let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
@@ -651,7 +651,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             trans(bcx, &e)
         }
         hir::ExprPath(..) => {
-            let var = trans_var(bcx, bcx.def(expr.id));
+            let var = trans_var(bcx, bcx.tcx().expect_def(expr.id));
             DatumBlock::new(bcx, var.to_expr_datum())
         }
         hir::ExprField(ref base, name) => {
@@ -1073,7 +1073,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             trans_into(bcx, &e, dest)
         }
         hir::ExprPath(..) => {
-            trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
+            trans_def_dps_unadjusted(bcx, expr, bcx.tcx().expect_def(expr.id), dest)
         }
         hir::ExprIf(ref cond, ref thn, ref els) => {
             controlflow::trans_if(bcx, expr.id, &cond, &thn, els.as_ref().map(|e| &**e), dest)
@@ -1978,7 +1978,7 @@ fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // Compute final type. Note that we are loose with the region and
     // mutability, since those things don't matter in trans.
     let referent_ty = lv_datum.ty;
-    let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), referent_ty);
+    let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased), referent_ty);
 
     // Construct the resulting datum. The right datum to return here would be an Lvalue datum,
     // because there is cleanup scheduled and the datum doesn't own the data, but for thin pointers
@@ -2373,7 +2373,7 @@ fn expr_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expr: &hir::Expr) -> ExprKin
 
     match expr.node {
         hir::ExprPath(..) => {
-            match tcx.resolve_expr(expr) {
+            match tcx.expect_def(expr.id) {
                 // Put functions and ctors with the ADTs, as they
                 // are zero-sized, so DPS is the cheapest option.
                 Def::Struct(..) | Def::Variant(..) |
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 0188a6d54de..8724945ed90 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -48,7 +48,6 @@ extern crate rustc_back;
 extern crate rustc_data_structures;
 extern crate rustc_incremental;
 pub extern crate rustc_llvm as llvm;
-extern crate rustc_mir;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate serialize;
 extern crate rustc_const_math;
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 4b81d993e02..062b3d4a6e4 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -271,7 +271,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // the method may have some early-bound lifetimes, add
             // regions for those
             let num_dummy_regions = trait_method_type.generics.regions.len(FnSpace);
-            let dummy_regions = vec![ty::ReStatic; num_dummy_regions];
+            let dummy_regions = vec![ty::ReErased; num_dummy_regions];
             let method_substs = substs.clone()
                                       .with_method(vec![], dummy_regions);
             let method_substs = tcx.mk_substs(method_substs);
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index 59143bc01bf..dac7afab6e3 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -8,27 +8,33 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! An analysis to determine which temporaries require allocas and
+//! An analysis to determine which locals require allocas and
 //! which do not.
 
 use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc::mir::repr as mir;
 use rustc::mir::repr::TerminatorKind;
 use rustc::mir::visit::{Visitor, LvalueContext};
-use rustc_mir::traversal;
+use rustc::mir::traversal;
 use common::{self, Block, BlockAndBuilder};
+use glue;
 use super::rvalue;
 
-pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
-                               mir: &mir::Mir<'tcx>) -> BitVector {
+pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
+                                 mir: &mir::Mir<'tcx>) -> BitVector {
     let bcx = bcx.build();
-    let mut analyzer = TempAnalyzer::new(mir, &bcx, mir.temp_decls.len());
+    let mut analyzer = LocalAnalyzer::new(mir, &bcx);
 
     analyzer.visit_mir(mir);
 
-    for (index, temp_decl) in mir.temp_decls.iter().enumerate() {
-        let ty = bcx.monomorphize(&temp_decl.ty);
-        debug!("temp {:?} has type {:?}", index, ty);
+    let local_types = mir.arg_decls.iter().map(|a| a.ty)
+               .chain(mir.var_decls.iter().map(|v| v.ty))
+               .chain(mir.temp_decls.iter().map(|t| t.ty))
+               .chain(mir.return_ty.maybe_converging());
+    for (index, ty) in local_types.enumerate() {
+        let ty = bcx.monomorphize(&ty);
+        debug!("local {} has type {:?}", index, ty);
         if ty.is_scalar() ||
             ty.is_unique() ||
             ty.is_region_ptr() ||
@@ -48,66 +54,87 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
             // (e.g. structs) into an alloca unconditionally, just so
             // that we don't have to deal with having two pathways
             // (gep vs extractvalue etc).
-            analyzer.mark_as_lvalue(index);
+            analyzer.mark_as_lvalue(mir::Local::new(index));
         }
     }
 
-    analyzer.lvalue_temps
+    analyzer.lvalue_locals
 }
 
-struct TempAnalyzer<'mir, 'bcx: 'mir, 'tcx: 'bcx> {
+struct LocalAnalyzer<'mir, 'bcx: 'mir, 'tcx: 'bcx> {
     mir: &'mir mir::Mir<'tcx>,
     bcx: &'mir BlockAndBuilder<'bcx, 'tcx>,
-    lvalue_temps: BitVector,
+    lvalue_locals: BitVector,
     seen_assigned: BitVector
 }
 
-impl<'mir, 'bcx, 'tcx> TempAnalyzer<'mir, 'bcx, 'tcx> {
+impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
     fn new(mir: &'mir mir::Mir<'tcx>,
-           bcx: &'mir BlockAndBuilder<'bcx, 'tcx>,
-           temp_count: usize) -> TempAnalyzer<'mir, 'bcx, 'tcx> {
-        TempAnalyzer {
+           bcx: &'mir BlockAndBuilder<'bcx, 'tcx>)
+           -> LocalAnalyzer<'mir, 'bcx, 'tcx> {
+        let local_count = mir.count_locals();
+        LocalAnalyzer {
             mir: mir,
             bcx: bcx,
-            lvalue_temps: BitVector::new(temp_count),
-            seen_assigned: BitVector::new(temp_count)
+            lvalue_locals: BitVector::new(local_count),
+            seen_assigned: BitVector::new(local_count)
         }
     }
 
-    fn mark_as_lvalue(&mut self, temp: usize) {
-        debug!("marking temp {} as lvalue", temp);
-        self.lvalue_temps.insert(temp);
+    fn mark_as_lvalue(&mut self, local: mir::Local) {
+        debug!("marking {:?} as lvalue", local);
+        self.lvalue_locals.insert(local.index());
     }
 
-    fn mark_assigned(&mut self, temp: usize) {
-        if !self.seen_assigned.insert(temp) {
-            self.mark_as_lvalue(temp);
+    fn mark_assigned(&mut self, local: mir::Local) {
+        if !self.seen_assigned.insert(local.index()) {
+            self.mark_as_lvalue(local);
         }
     }
 }
 
-impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
+impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
     fn visit_assign(&mut self,
                     block: mir::BasicBlock,
                     lvalue: &mir::Lvalue<'tcx>,
                     rvalue: &mir::Rvalue<'tcx>) {
         debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
 
-        match *lvalue {
-            mir::Lvalue::Temp(index) => {
-                self.mark_assigned(index as usize);
-                if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
-                    self.mark_as_lvalue(index as usize);
-                }
-            }
-            _ => {
-                self.visit_lvalue(lvalue, LvalueContext::Store);
+        if let Some(index) = self.mir.local_index(lvalue) {
+            self.mark_assigned(index);
+            if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
+                self.mark_as_lvalue(index);
             }
+        } else {
+            self.visit_lvalue(lvalue, LvalueContext::Store);
         }
 
         self.visit_rvalue(rvalue);
     }
 
+    fn visit_terminator_kind(&mut self,
+                             block: mir::BasicBlock,
+                             kind: &mir::TerminatorKind<'tcx>) {
+        match *kind {
+            mir::TerminatorKind::Call {
+                func: mir::Operand::Constant(mir::Constant {
+                    literal: mir::Literal::Item { def_id, .. }, ..
+                }),
+                ref args, ..
+            } if Some(def_id) == self.bcx.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.
+                if let mir::Operand::Consume(ref lvalue) = args[0] {
+                    self.visit_lvalue(lvalue, LvalueContext::Drop);
+                }
+            }
+            _ => {}
+        }
+
+        self.super_terminator_kind(block, kind);
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &mir::Lvalue<'tcx>,
                     context: LvalueContext) {
@@ -115,9 +142,9 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
 
         // Allow uses of projections of immediate pair fields.
         if let mir::Lvalue::Projection(ref proj) = *lvalue {
-            if let mir::Lvalue::Temp(index) = proj.base {
-                let ty = self.mir.temp_decls[index as usize].ty;
-                let ty = self.bcx.monomorphize(&ty);
+            if self.mir.local_index(&proj.base).is_some() {
+                let ty = self.mir.lvalue_ty(self.bcx.tcx(), &proj.base);
+                let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
                 if common::type_is_imm_pair(self.bcx.ccx(), ty) {
                     if let mir::ProjectionElem::Field(..) = proj.elem {
                         if let LvalueContext::Consume = context {
@@ -128,25 +155,36 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
             }
         }
 
-        match *lvalue {
-            mir::Lvalue::Temp(index) => {
-                match context {
-                    LvalueContext::Call => {
-                        self.mark_assigned(index as usize);
-                    }
-                    LvalueContext::Consume => {
-                    }
-                    LvalueContext::Store |
-                    LvalueContext::Drop |
-                    LvalueContext::Inspect |
-                    LvalueContext::Borrow { .. } |
-                    LvalueContext::Slice { .. } |
-                    LvalueContext::Projection => {
-                        self.mark_as_lvalue(index as usize);
+        if let Some(index) = self.mir.local_index(lvalue) {
+            match context {
+                LvalueContext::Call => {
+                    self.mark_assigned(index);
+                }
+                LvalueContext::Consume => {
+                }
+                LvalueContext::Store |
+                LvalueContext::Inspect |
+                LvalueContext::Borrow { .. } |
+                LvalueContext::Slice { .. } |
+                LvalueContext::Projection => {
+                    self.mark_as_lvalue(index);
+                }
+                LvalueContext::Drop => {
+                    let ty = self.mir.lvalue_ty(self.bcx.tcx(), lvalue);
+                    let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
+
+                    // Only need the lvalue if we're actually dropping it.
+                    if glue::type_needs_drop(self.bcx.tcx(), ty) {
+                        self.mark_as_lvalue(index);
                     }
                 }
             }
-            _ => {
+        }
+
+        // A deref projection only reads the pointer, never needs the lvalue.
+        if let mir::Lvalue::Projection(ref proj) = *lvalue {
+            if let mir::ProjectionElem::Deref = proj.elem {
+                return self.visit_lvalue(&proj.base, LvalueContext::Consume);
             }
         }
 
@@ -163,15 +201,16 @@ pub enum CleanupKind {
 
 pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>,
                                 mir: &mir::Mir<'tcx>)
-                                -> Vec<CleanupKind>
+                                -> IndexVec<mir::BasicBlock, CleanupKind>
 {
-    fn discover_masters<'tcx>(result: &mut [CleanupKind], mir: &mir::Mir<'tcx>) {
-        for bb in mir.all_basic_blocks() {
-            let data = mir.basic_block_data(bb);
+    fn discover_masters<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
+                              mir: &mir::Mir<'tcx>) {
+        for (bb, data) in mir.basic_blocks().iter_enumerated() {
             match data.terminator().kind {
                 TerminatorKind::Goto { .. } |
                 TerminatorKind::Resume |
                 TerminatorKind::Return |
+                TerminatorKind::Unreachable |
                 TerminatorKind::If { .. } |
                 TerminatorKind::Switch { .. } |
                 TerminatorKind::SwitchInt { .. } => {
@@ -184,19 +223,19 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>,
                     if let Some(unwind) = unwind {
                         debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
                                bb, data, unwind);
-                        result[unwind.index()] = CleanupKind::Funclet;
+                        result[unwind] = CleanupKind::Funclet;
                     }
                 }
             }
         }
     }
 
-    fn propagate<'tcx>(result: &mut [CleanupKind], mir: &mir::Mir<'tcx>) {
-        let mut funclet_succs : Vec<_> =
-            mir.all_basic_blocks().iter().map(|_| None).collect();
+    fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
+                       mir: &mir::Mir<'tcx>) {
+        let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks());
 
         let mut set_successor = |funclet: mir::BasicBlock, succ| {
-            match funclet_succs[funclet.index()] {
+            match funclet_succs[funclet] {
                 ref mut s @ None => {
                     debug!("set_successor: updating successor of {:?} to {:?}",
                            funclet, succ);
@@ -210,22 +249,22 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>,
         };
 
         for (bb, data) in traversal::reverse_postorder(mir) {
-            let funclet = match result[bb.index()] {
+            let funclet = match result[bb] {
                 CleanupKind::NotCleanup => continue,
                 CleanupKind::Funclet => bb,
                 CleanupKind::Internal { funclet } => funclet,
             };
 
             debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
-                   bb, data, result[bb.index()], funclet);
+                   bb, data, result[bb], funclet);
 
             for &succ in data.terminator().successors().iter() {
-                let kind = result[succ.index()];
+                let kind = result[succ];
                 debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}",
                        funclet, succ, kind);
                 match kind {
                     CleanupKind::NotCleanup => {
-                        result[succ.index()] = CleanupKind::Internal { funclet: funclet };
+                        result[succ] = CleanupKind::Internal { funclet: funclet };
                     }
                     CleanupKind::Funclet => {
                         set_successor(funclet, succ);
@@ -237,7 +276,7 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>,
 
                             debug!("promoting {:?} to a funclet and updating {:?}", succ,
                                    succ_funclet);
-                            result[succ.index()] = CleanupKind::Funclet;
+                            result[succ] = CleanupKind::Funclet;
                             set_successor(succ_funclet, succ);
                             set_successor(funclet, succ);
                         }
@@ -247,8 +286,7 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>,
         }
     }
 
-    let mut result : Vec<_> =
-        mir.all_basic_blocks().iter().map(|_| CleanupKind::NotCleanup).collect();
+    let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks());
 
     discover_masters(&mut result, mir);
     propagate(&mut result, mir);
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index b7aca4c8d7f..7a7f1901736 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -19,11 +19,11 @@ use base;
 use build;
 use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
 use common::{self, Block, BlockAndBuilder, LandingPad};
-use common::{C_bool, C_str_slice, C_struct, C_u32, C_uint, C_undef};
+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, llsize_of_store};
+use machine::{llalign_of_min, llbitsize_of_real};
 use meth;
 use type_of;
 use glue;
@@ -32,20 +32,18 @@ use type_::Type;
 use rustc_data_structures::fnv::FnvHashMap;
 use syntax::parse::token;
 
-use super::{MirContext, TempRef};
+use super::{MirContext, LocalRef};
 use super::analyze::CleanupKind;
 use super::constant::Const;
 use super::lvalue::{LvalueRef, load_fat_ptr};
 use super::operand::OperandRef;
 use super::operand::OperandValue::*;
 
-use std::cmp;
-
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn trans_block(&mut self, bb: mir::BasicBlock) {
         let mut bcx = self.bcx(bb);
         let mir = self.mir.clone();
-        let data = mir.basic_block_data(bb);
+        let data = &mir[bb];
 
         debug!("trans_block({:?}={:?})", bb, data);
 
@@ -54,9 +52,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         let cleanup_bundle = bcx.lpad().and_then(|l| l.bundle());
 
         let funclet_br = |this: &Self, bcx: BlockAndBuilder, bb: mir::BasicBlock| {
-            let lltarget = this.blocks[bb.index()].llbb;
+            let lltarget = this.blocks[bb].llbb;
             if let Some(cp) = cleanup_pad {
-                match this.cleanup_kind(bb) {
+                match this.cleanup_kinds[bb] {
                     CleanupKind::Funclet => {
                         // micro-optimization: generate a `ret` rather than a jump
                         // to a return block
@@ -71,10 +69,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         };
 
         let llblock = |this: &mut Self, target: mir::BasicBlock| {
-            let lltarget = this.blocks[target.index()].llbb;
+            let lltarget = this.blocks[target].llbb;
 
             if let Some(cp) = cleanup_pad {
-                match this.cleanup_kind(target) {
+                match this.cleanup_kinds[target] {
                     CleanupKind::Funclet => {
                         // MSVC cross-funclet jump - need a trampoline
 
@@ -91,7 +89,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 }
             } else {
                 if let (CleanupKind::NotCleanup, CleanupKind::Funclet) =
-                    (this.cleanup_kind(bb), this.cleanup_kind(target))
+                    (this.cleanup_kinds[bb], this.cleanup_kinds[target])
                 {
                     // jump *into* cleanup - need a landing pad if GNU
                     this.landing_pad_to(target).llbb
@@ -108,8 +106,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         let terminator = data.terminator();
         debug!("trans_block: terminator: {:?}", terminator);
 
-        let debug_loc = DebugLoc::ScopeAt(self.scopes[terminator.scope.index()],
-                                          terminator.span);
+        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());
         match terminator.kind {
@@ -188,19 +186,60 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             }
 
             mir::TerminatorKind::Return => {
-                bcx.with_block(|bcx| {
-                    self.fcx.build_return_block(bcx, debug_loc);
-                })
+                let ret = bcx.fcx().fn_ty.ret;
+                if ret.is_ignore() || ret.is_indirect() {
+                    bcx.ret_void();
+                    return;
+                }
+
+                let llval = if let Some(cast_ty) = ret.cast {
+                    let index = mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
+                    let op = match self.locals[index] {
+                        LocalRef::Operand(Some(op)) => op,
+                        LocalRef::Operand(None) => bug!("use of return before def"),
+                        LocalRef::Lvalue(tr_lvalue) => {
+                            OperandRef {
+                                val: Ref(tr_lvalue.llval),
+                                ty: tr_lvalue.ty.to_ty(bcx.tcx())
+                            }
+                        }
+                    };
+                    let llslot = match op.val {
+                        Immediate(_) | Pair(..) => {
+                            let llscratch = build::AllocaFcx(bcx.fcx(), 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);
+                    unsafe {
+                        llvm::LLVMSetAlignment(load, llalign);
+                    }
+                    load
+                } else {
+                    let op = self.trans_consume(&bcx, &mir::Lvalue::ReturnPointer);
+                    op.pack_if_pair(&bcx).immediate()
+                };
+                bcx.ret(llval);
+            }
+
+            mir::TerminatorKind::Unreachable => {
+                bcx.unreachable();
             }
 
             mir::TerminatorKind::Drop { ref location, target, unwind } => {
-                let lvalue = self.trans_lvalue(&bcx, location);
-                let ty = lvalue.ty.to_ty(bcx.tcx());
+                let ty = mir.lvalue_ty(bcx.tcx(), location).to_ty(bcx.tcx());
+                let ty = bcx.monomorphize(&ty);
+
                 // Double check for necessity to drop
                 if !glue::type_needs_drop(bcx.tcx(), 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 llvalue = if drop_ty != ty {
@@ -211,7 +250,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 if let Some(unwind) = unwind {
                     bcx.invoke(drop_fn,
                                &[llvalue],
-                               self.blocks[target.index()].llbb,
+                               self.blocks[target].llbb,
                                llblock(self, unwind),
                                cleanup_bundle);
                 } else {
@@ -247,7 +286,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 bcx = panic_block.build();
 
                 // Get the location information.
-                let loc = bcx.sess().codemap().lookup_char_pos(terminator.span.lo);
+                let loc = bcx.sess().codemap().lookup_char_pos(span.lo);
                 let filename = token::intern_and_get_ident(&loc.file.name);
                 let filename = C_str_slice(bcx.ccx(), filename);
                 let line = C_u32(bcx.ccx(), loc.line as u32);
@@ -298,15 +337,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 // is also constant, then we can produce a warning.
                 if const_cond == Some(!expected) {
                     if let Some(err) = const_err {
-                        let _ = consts::const_err(bcx.ccx(),
-                                                  terminator.span,
+                        let _ = consts::const_err(bcx.ccx(), span,
                                                   Err::<(), _>(err),
                                                   consts::TrueConst::No);
                     }
                 }
 
                 // Obtain the panic entry point.
-                let def_id = common::langcall(bcx.tcx(), Some(terminator.span), "", lang_item);
+                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()).val;
@@ -419,8 +457,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     if is_shuffle && idx == 2 {
                         match *arg {
                             mir::Operand::Consume(_) => {
-                                span_bug!(terminator.span,
-                                          "shuffle indices must be constant");
+                                span_bug!(span, "shuffle indices must be constant");
                             }
                             mir::Operand::Constant(ref constant) => {
                                 let val = self.trans_constant(&bcx, constant);
@@ -492,7 +529,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 // Many different ways to call a function handled here
                 if let &Some(cleanup) = cleanup {
                     let ret_bcx = if let Some((_, target)) = *destination {
-                        self.blocks[target.index()]
+                        self.blocks[target]
                     } else {
                         self.unreachable_block()
                     };
@@ -534,7 +571,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
     fn trans_argument(&mut self,
                       bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                      mut op: OperandRef<'tcx>,
+                      op: OperandRef<'tcx>,
                       llargs: &mut Vec<ValueRef>,
                       fn_ty: &FnType,
                       next_idx: &mut usize,
@@ -562,8 +599,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, callee);
                 return;
             }
-
-            op = op.pack_if_pair(bcx);
         }
 
         let arg = &fn_ty.args[*next_idx];
@@ -580,14 +615,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
         // Force by-ref if we have to load through a cast pointer.
         let (mut llval, by_ref) = match op.val {
-            Immediate(llval) if arg.is_indirect() || arg.cast.is_some() => {
-                let llscratch = build::AllocaFcx(bcx.fcx(), arg.original_ty, "arg");
-                bcx.store(llval, llscratch);
-                (llscratch, true)
+            Immediate(_) | Pair(..) => {
+                if arg.is_indirect() || arg.cast.is_some() {
+                    let llscratch = build::AllocaFcx(bcx.fcx(), arg.original_ty, "arg");
+                    self.store_operand(bcx, llscratch, op);
+                    (llscratch, true)
+                } else {
+                    (op.pack_if_pair(bcx).immediate(), false)
+                }
             }
-            Immediate(llval) => (llval, false),
-            Ref(llval) => (llval, true),
-            Pair(..) => bug!("pairs handled above")
+            Ref(llval) => (llval, true)
         };
 
         if by_ref && !arg.is_indirect() {
@@ -697,27 +734,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         }
     }
 
-    fn cleanup_kind(&self, bb: mir::BasicBlock) -> CleanupKind {
-        self.cleanup_kinds[bb.index()]
-    }
-
     /// 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>
     {
-        if let Some(block) = self.landing_pads[target_bb.index()] {
+        if let Some(block) = self.landing_pads[target_bb] {
             return block;
         }
 
         if base::wants_msvc_seh(self.fcx.ccx.sess()) {
-            return self.blocks[target_bb.index()];
+            return self.blocks[target_bb];
         }
 
         let target = self.bcx(target_bb);
 
         let block = self.fcx.new_block("cleanup", None);
-        self.landing_pads[target_bb.index()] = Some(block);
+        self.landing_pads[target_bb] = Some(block);
 
         let bcx = block.build();
         let ccx = bcx.ccx();
@@ -733,10 +766,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
     pub fn init_cpad(&mut self, bb: mir::BasicBlock) {
         let bcx = self.bcx(bb);
-        let data = self.mir.basic_block_data(bb);
+        let data = &self.mir[bb];
         debug!("init_cpad({:?})", data);
 
-        match self.cleanup_kinds[bb.index()] {
+        match self.cleanup_kinds[bb] {
             CleanupKind::NotCleanup => {
                 bcx.set_lpad(None)
             }
@@ -767,7 +800,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     fn bcx(&self, bb: mir::BasicBlock) -> BlockAndBuilder<'bcx, 'tcx> {
-        self.blocks[bb.index()].build()
+        self.blocks[bb].build()
     }
 
     fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
@@ -777,42 +810,39 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         if fn_ret_ty.is_ignore() {
             return ReturnDest::Nothing;
         }
-        let dest = match *dest {
-            mir::Lvalue::Temp(idx) => {
-                let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), dest);
-                let lvalue_ty = bcx.monomorphize(&lvalue_ty);
-                let ret_ty = lvalue_ty.to_ty(bcx.tcx());
-                match self.temps[idx as usize] {
-                    TempRef::Lvalue(dest) => dest,
-                    TempRef::Operand(None) => {
-                        // Handle temporary lvalues, specifically Operand ones, as
-                        // they don't have allocas
-                        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")
-                            });
-                            llargs.push(tmp);
-                            ReturnDest::IndirectOperand(tmp, idx)
-                        } 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")
-                            });
-                            ReturnDest::IndirectOperand(tmp, idx)
-                        } else {
-                            ReturnDest::DirectOperand(idx)
-                        };
-                    }
-                    TempRef::Operand(Some(_)) => {
-                        bug!("lvalue temp already assigned to");
-                    }
+        let dest = if let Some(index) = self.mir.local_index(dest) {
+            let ret_ty = self.lvalue_ty(dest);
+            match self.locals[index] {
+                LocalRef::Lvalue(dest) => dest,
+                LocalRef::Operand(None) => {
+                    // Handle temporary lvalues, specifically Operand ones, as
+                    // they don't have allocas
+                    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")
+                        });
+                        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")
+                        });
+                        ReturnDest::IndirectOperand(tmp, index)
+                    } else {
+                        ReturnDest::DirectOperand(index)
+                    };
+                }
+                LocalRef::Operand(Some(_)) => {
+                    bug!("lvalue local already assigned to");
                 }
             }
-            _ => self.trans_lvalue(bcx, dest)
+        } else {
+            self.trans_lvalue(bcx, dest)
         };
         if fn_ret_ty.is_indirect() {
             llargs.push(dest.llval);
@@ -844,6 +874,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         self.store_operand(bcx, cast_ptr, val);
     }
 
+
     // Stores the return value of a function call into it's final location.
     fn store_return(&mut self,
                     bcx: &BlockAndBuilder<'bcx, 'tcx>,
@@ -852,74 +883,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     op: OperandRef<'tcx>) {
         use self::ReturnDest::*;
 
-        // Handle the simple cases that don't require casts, first.
-        let llcast_ty = match dest {
-            Nothing => return,
-            Store(dst) => {
-                if let Some(llcast_ty) = ret_ty.cast {
-                    llcast_ty
-                } else {
-                    ret_ty.store(bcx, op.immediate(), dst);
-                    return;
-                }
-            }
-            IndirectOperand(tmp, idx) => {
+        match dest {
+            Nothing => (),
+            Store(dst) => ret_ty.store(bcx, op.immediate(), dst),
+            IndirectOperand(tmp, index) => {
                 let op = self.trans_load(bcx, tmp, op.ty);
-                self.temps[idx as usize] = TempRef::Operand(Some(op));
-                return;
+                self.locals[index] = LocalRef::Operand(Some(op));
             }
-            DirectOperand(idx) => {
-                if let Some(llcast_ty) = ret_ty.cast {
-                    llcast_ty
+            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")
+                    });
+                    ret_ty.store(bcx, op.immediate(), tmp);
+                    self.trans_load(bcx, tmp, op.ty)
                 } else {
-                    let op = op.unpack_if_pair(bcx);
-                    self.temps[idx as usize] = TempRef::Operand(Some(op));
-                    return;
-                }
-            }
-        };
-
-        // The actual return type is a struct, but the ABI
-        // adaptation code has cast it into some scalar type.  The
-        // code that follows is the only reliable way I have
-        // found to do a transform like i64 -> {i32,i32}.
-        // Basically we dump the data onto the stack then memcpy it.
-        //
-        // Other approaches I tried:
-        // - Casting rust ret pointer to the foreign type and using Store
-        //   is (a) unsafe if size of foreign type > size of rust type and
-        //   (b) runs afoul of strict aliasing rules, yielding invalid
-        //   assembly under -O (specifically, the store gets removed).
-        // - Truncating foreign type to correct integral type and then
-        //   bitcasting to the struct type yields invalid cast errors.
-
-        // We instead thus allocate some scratch space...
-        let llscratch = bcx.alloca(llcast_ty, "fn_ret_cast");
-        bcx.with_block(|bcx| base::call_lifetime_start(bcx, llscratch));
-
-        // ...where we first store the value...
-        bcx.store(op.immediate(), llscratch);
-
-        let ccx = bcx.ccx();
-        match dest {
-            Store(dst) => {
-                // ...and then memcpy it to the intended destination.
-                base::call_memcpy(bcx,
-                                  bcx.pointercast(dst, Type::i8p(ccx)),
-                                  bcx.pointercast(llscratch, Type::i8p(ccx)),
-                                  C_uint(ccx, llsize_of_store(ccx, ret_ty.original_ty)),
-                                  cmp::min(llalign_of_min(ccx, ret_ty.original_ty),
-                                           llalign_of_min(ccx, llcast_ty)) as u32);
-            }
-            DirectOperand(idx) => {
-                let llptr = bcx.pointercast(llscratch, ret_ty.original_ty.ptr_to());
-                let op = self.trans_load(bcx, llptr, op.ty);
-                self.temps[idx as usize] = TempRef::Operand(Some(op));
+                    op.unpack_if_pair(bcx)
+                };
+                self.locals[index] = LocalRef::Operand(Some(op));
             }
-            Nothing | IndirectOperand(_, _) => bug!()
         }
-
-        bcx.with_block(|bcx| base::call_lifetime_end(bcx, llscratch));
     }
 }
 
@@ -928,8 +912,8 @@ enum ReturnDest {
     Nothing,
     // Store the return value to the pointer
     Store(ValueRef),
-    // Stores an indirect return value to an operand temporary lvalue
-    IndirectOperand(ValueRef, u32),
-    // Stores a direct return value to an operand temporary lvalue
-    DirectOperand(u32)
+    // Stores an indirect return value to an operand local lvalue
+    IndirectOperand(ValueRef, mir::Local),
+    // Stores a direct return value to an operand local lvalue
+    DirectOperand(mir::Local)
 }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index f5fdd87b167..30be4a97372 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -22,6 +22,7 @@ use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::Substs;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use {abi, adt, base, Disr};
 use callee::Callee;
 use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
@@ -125,10 +126,10 @@ impl<'tcx> Const<'tcx> {
         let llty = type_of::immediate_type_of(ccx, self.ty);
         let llvalty = val_ty(self.llval);
 
-        let val = if common::type_is_imm_pair(ccx, self.ty) {
+        let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
             let (a, b) = self.get_pair();
             OperandValue::Pair(a, b)
-        } else if common::type_is_immediate(ccx, self.ty) && llty == llvalty {
+        } else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
             // If the types match, we can use the value directly.
             OperandValue::Immediate(self.llval)
         } else {
@@ -202,17 +203,8 @@ struct MirConstContext<'a, 'tcx: 'a> {
     /// Type parameters for const fn and associated constants.
     substs: &'tcx Substs<'tcx>,
 
-    /// Arguments passed to a const fn.
-    args: Vec<Const<'tcx>>,
-
-    /// Variable values - specifically, argument bindings of a const fn.
-    vars: Vec<Option<Const<'tcx>>>,
-
-    /// Temp values.
-    temps: Vec<Option<Const<'tcx>>>,
-
-    /// Value assigned to Return, which is the resulting constant.
-    return_value: Option<Const<'tcx>>
+    /// Values of locals in a constant or const fn.
+    locals: IndexVec<mir::Local, Option<Const<'tcx>>>
 }
 
 
@@ -220,22 +212,24 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     fn new(ccx: &'a CrateContext<'a, 'tcx>,
            mir: &'a mir::Mir<'tcx>,
            substs: &'tcx Substs<'tcx>,
-           args: Vec<Const<'tcx>>)
+           args: IndexVec<mir::Arg, Const<'tcx>>)
            -> MirConstContext<'a, 'tcx> {
-        MirConstContext {
+        let mut context = MirConstContext {
             ccx: ccx,
             mir: mir,
             substs: substs,
-            args: args,
-            vars: vec![None; mir.var_decls.len()],
-            temps: vec![None; mir.temp_decls.len()],
-            return_value: None
+            locals: (0..mir.count_locals()).map(|_| None).collect(),
+        };
+        for (i, arg) in args.into_iter().enumerate() {
+            let index = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(i))).unwrap();
+            context.locals[index] = Some(arg);
         }
+        context
     }
 
     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
                  mut instance: Instance<'tcx>,
-                 args: Vec<Const<'tcx>>)
+                 args: IndexVec<mir::Arg, Const<'tcx>>)
                  -> Result<Const<'tcx>, ConstEvalFailure> {
         // Try to resolve associated constants.
         if instance.substs.self_ty().is_some() {
@@ -279,14 +273,15 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
         let mut failure = Ok(());
 
         loop {
-            let data = self.mir.basic_block_data(bb);
+            let data = &self.mir[bb];
             for statement in &data.statements {
+                let span = statement.source_info.span;
                 match statement.kind {
                     mir::StatementKind::Assign(ref dest, ref rvalue) => {
                         let ty = self.mir.lvalue_ty(tcx, dest);
                         let ty = self.monomorphize(&ty).to_ty(tcx);
-                        match self.const_rvalue(rvalue, ty, statement.span) {
-                            Ok(value) => self.store(dest, value, statement.span),
+                        match self.const_rvalue(rvalue, ty, span) {
+                            Ok(value) => self.store(dest, value, span),
                             Err(err) => if failure.is_ok() { failure = Err(err); }
                         }
                     }
@@ -294,15 +289,16 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
             }
 
             let terminator = data.terminator();
-            let span = terminator.span;
+            let span = terminator.source_info.span;
             bb = match terminator.kind {
                 mir::TerminatorKind::Drop { target, .. } | // No dropping.
                 mir::TerminatorKind::Goto { target } => target,
                 mir::TerminatorKind::Return => {
                     failure?;
-                    return Ok(self.return_value.unwrap_or_else(|| {
+                    let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
+                    return Ok(self.locals[index].unwrap_or_else(|| {
                         span_bug!(span, "no returned value in constant");
-                    }))
+                    }));
                 }
 
                 mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
@@ -341,10 +337,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                                        func, fn_ty)
                     };
 
-                    let mut const_args = Vec::with_capacity(args.len());
+                    let mut const_args = IndexVec::with_capacity(args.len());
                     for arg in args {
                         match self.const_operand(arg, span) {
-                            Ok(arg) => const_args.push(arg),
+                            Ok(arg) => { const_args.push(arg); },
                             Err(err) => if failure.is_ok() { failure = Err(err); }
                         }
                     }
@@ -364,30 +360,28 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     }
 
     fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
-        let dest = match *dest {
-            mir::Lvalue::Var(index) => &mut self.vars[index as usize],
-            mir::Lvalue::Temp(index) => &mut self.temps[index as usize],
-            mir::Lvalue::ReturnPointer => &mut self.return_value,
-            _ => span_bug!(span, "assignment to {:?} in constant", dest)
-        };
-        *dest = Some(value);
+        if let Some(index) = self.mir.local_index(dest) {
+            self.locals[index] = Some(value);
+        } else {
+            span_bug!(span, "assignment to {:?} in constant", dest);
+        }
     }
 
     fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
                     -> Result<ConstLvalue<'tcx>, ConstEvalFailure> {
         let tcx = self.ccx.tcx();
+
+        if let Some(index) = self.mir.local_index(lvalue) {
+            return Ok(self.locals[index].unwrap_or_else(|| {
+                span_bug!(span, "{:?} not initialized", lvalue)
+            }).as_lvalue());
+        }
+
         let lvalue = match *lvalue {
-            mir::Lvalue::Var(index) => {
-                self.vars[index as usize].unwrap_or_else(|| {
-                    span_bug!(span, "var{} not initialized", index)
-                }).as_lvalue()
-            }
-            mir::Lvalue::Temp(index) => {
-                self.temps[index as usize].unwrap_or_else(|| {
-                    span_bug!(span, "tmp{} not initialized", index)
-                }).as_lvalue()
-            }
-            mir::Lvalue::Arg(index) => self.args[index as usize].as_lvalue(),
+            mir::Lvalue::Var(_) |
+            mir::Lvalue::Temp(_) |
+            mir::Lvalue::Arg(_) |
+            mir::Lvalue::ReturnPointer => bug!(), // handled above
             mir::Lvalue::Static(def_id) => {
                 ConstLvalue {
                     base: Base::Static(consts::get_static(self.ccx, def_id).val),
@@ -395,9 +389,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     ty: self.mir.lvalue_ty(tcx, lvalue).to_ty(tcx)
                 }
             }
-            mir::Lvalue::ReturnPointer => {
-                span_bug!(span, "accessing Lvalue::ReturnPointer in constant")
-            }
             mir::Lvalue::Projection(ref projection) => {
                 let tr_base = self.const_lvalue(&projection.base, span)?;
                 let projected_ty = LvalueTy::Ty { ty: tr_base.ty }
@@ -488,11 +479,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
                         let substs = self.monomorphize(&substs);
                         let instance = Instance::new(def_id, substs);
-                        MirConstContext::trans_def(self.ccx, instance, vec![])
+                        MirConstContext::trans_def(self.ccx, instance, IndexVec::new())
                     }
                     mir::Literal::Promoted { index } => {
                         let mir = &self.mir.promoted[index];
-                        MirConstContext::new(self.ccx, mir, self.substs, vec![]).trans()
+                        MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
                     }
                     mir::Literal::Value { value } => {
                         Ok(Const::from_constval(self.ccx, value, ty))
@@ -715,7 +706,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 let tr_lvalue = self.const_lvalue(lvalue, span)?;
 
                 let ty = tr_lvalue.ty;
-                let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReStatic),
+                let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased),
                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
 
                 let base = match tr_lvalue.base {
@@ -913,11 +904,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 let substs = bcx.monomorphize(&substs);
                 let instance = Instance::new(def_id, substs);
-                MirConstContext::trans_def(bcx.ccx(), instance, vec![])
+                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, vec![]).trans()
+                MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs,
+                                     IndexVec::new()).trans()
             }
             mir::Literal::Value { value } => {
                 Ok(Const::from_constval(bcx.ccx(), value, ty))
@@ -944,5 +936,5 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
                                 -> Result<ValueRef, ConstEvalFailure> {
     let instance = Instance::mono(ccx.shared(), def_id);
-    MirConstContext::trans_def(ccx, instance, vec![]).map(|c| c.llval)
+    MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
 }
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index bc79482666c..ceaba2a40ca 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -12,6 +12,7 @@ use llvm::ValueRef;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
+use rustc_data_structures::indexed_vec::Idx;
 use abi;
 use adt;
 use base;
@@ -20,13 +21,15 @@ use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
 use consts;
 use machine;
 use type_of::type_of;
+use type_of;
 use Disr;
 
 use std::ptr;
 
-use super::{MirContext, TempRef};
+use super::{MirContext, LocalRef};
+use super::operand::OperandValue;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct LvalueRef<'tcx> {
     /// Pointer to the contents of the lvalue
     pub llval: ValueRef,
@@ -85,39 +88,50 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         -> LvalueRef<'tcx> {
         debug!("trans_lvalue(lvalue={:?})", lvalue);
 
-        let fcx = bcx.fcx();
         let ccx = bcx.ccx();
         let tcx = bcx.tcx();
-        match *lvalue {
-            mir::Lvalue::Var(index) => self.vars[index as usize],
-            mir::Lvalue::Temp(index) => match self.temps[index as usize] {
-                TempRef::Lvalue(lvalue) =>
-                    lvalue,
-                TempRef::Operand(..) =>
-                    bug!("using operand temp {:?} as lvalue", lvalue),
-            },
-            mir::Lvalue::Arg(index) => self.args[index as usize],
+
+        if let Some(index) = self.mir.local_index(lvalue) {
+            match self.locals[index] {
+                LocalRef::Lvalue(lvalue) => {
+                    return lvalue;
+                }
+                LocalRef::Operand(..) => {
+                    bug!("using operand local {:?} as lvalue", lvalue);
+                }
+            }
+        }
+
+        let result = match *lvalue {
+            mir::Lvalue::Var(_) |
+            mir::Lvalue::Temp(_) |
+            mir::Lvalue::Arg(_) |
+            mir::Lvalue::ReturnPointer => bug!(), // handled above
             mir::Lvalue::Static(def_id) => {
-                let const_ty = self.mir.lvalue_ty(tcx, lvalue);
-                LvalueRef::new_sized(consts::get_static(ccx, def_id).val, const_ty)
+                let const_ty = self.lvalue_ty(lvalue);
+                LvalueRef::new_sized(consts::get_static(ccx, def_id).val,
+                                     LvalueTy::from_ty(const_ty))
             },
-            mir::Lvalue::ReturnPointer => {
-                let llval = if !fcx.fn_ty.ret.is_ignore() {
-                    bcx.with_block(|bcx| {
-                        fcx.get_ret_slot(bcx, "")
-                    })
-                } else {
-                    // This is a void return; that is, there’s no place to store the value and
-                    // there cannot really be one (or storing into it doesn’t make sense, anyway).
-                    // Ergo, we return an undef ValueRef, so we do not have to special-case every
-                    // place using lvalues, and could use it the same way you use a regular
-                    // ReturnPointer LValue (i.e. store into it, load from it etc).
-                    C_undef(fcx.fn_ty.ret.original_ty.ptr_to())
+            mir::Lvalue::Projection(box mir::Projection {
+                ref base,
+                elem: mir::ProjectionElem::Deref
+            }) => {
+                // Load the pointer from its location.
+                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 (llptr, llextra) = match ptr.val {
+                    OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
+                    OperandValue::Pair(llptr, llextra) => (llptr, llextra),
+                    OperandValue::Ref(_) => bug!("Deref of by-Ref type {:?}", ptr.ty)
                 };
-                let fn_return_ty = bcx.monomorphize(&self.mir.return_ty);
-                let return_ty = fn_return_ty.unwrap();
-                LvalueRef::new_sized(llval, LvalueTy::from_ty(return_ty))
-            },
+                LvalueRef {
+                    llval: llptr,
+                    llextra: llextra,
+                    ty: projected_ty,
+                }
+            }
             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);
@@ -131,19 +145,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         let zero = common::C_uint(bcx.ccx(), 0u64);
                         bcx.inbounds_gep(tr_base.llval, &[zero, llindex])
                     };
-                    (element, ptr::null_mut())
+                    element
                 };
 
                 let (llprojected, llextra) = match projection.elem {
-                    mir::ProjectionElem::Deref => {
-                        let base_ty = tr_base.ty.to_ty(tcx);
-                        if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
-                            (base::load_ty_builder(bcx, tr_base.llval, base_ty),
-                             ptr::null_mut())
-                        } else {
-                            load_fat_ptr(bcx, tr_base.llval)
-                        }
-                    }
+                    mir::ProjectionElem::Deref => bug!(),
                     mir::ProjectionElem::Field(ref field, _) => {
                         let base_ty = tr_base.ty.to_ty(tcx);
                         let base_repr = adt::represent_type(ccx, base_ty);
@@ -169,13 +175,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     }
                     mir::ProjectionElem::Index(ref index) => {
                         let index = self.trans_operand(bcx, index);
-                        project_index(self.prepare_index(bcx, index.immediate()))
+                        (project_index(self.prepare_index(bcx, index.immediate())), ptr::null_mut())
                     }
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: false,
                                                          min_length: _ } => {
                         let lloffset = C_uint(bcx.ccx(), offset);
-                        project_index(self.prepare_index(bcx, lloffset))
+                        (project_index(lloffset), ptr::null_mut())
                     }
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: true,
@@ -183,7 +189,30 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         let lloffset = C_uint(bcx.ccx(), offset);
                         let lllen = tr_base.len(bcx.ccx());
                         let llindex = bcx.sub(lllen, lloffset);
-                        project_index(self.prepare_index(bcx, llindex))
+                        (project_index(llindex), ptr::null_mut())
+                    }
+                    mir::ProjectionElem::Subslice { from, to } => {
+                        let llindex = C_uint(bcx.ccx(), from);
+                        let llbase = project_index(llindex);
+
+                        let base_ty = tr_base.ty.to_ty(bcx.tcx());
+                        match base_ty.sty {
+                            ty::TyArray(..) => {
+                                // must cast the lvalue pointer type to the new
+                                // array type (*[%_; new_len]).
+                                let base_ty = self.lvalue_ty(lvalue);
+                                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));
+                                (llbase, lllen)
+                            }
+                            _ => bug!("unexpected type {:?} in Subslice", base_ty)
+                        }
                     }
                     mir::ProjectionElem::Downcast(..) => {
                         (tr_base.llval, tr_base.llextra)
@@ -195,52 +224,47 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     ty: projected_ty,
                 }
             }
-        }
+        };
+        debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
+        result
     }
 
     // Perform an action using the given Lvalue.
-    // If the Lvalue is an empty TempRef::Operand, then a temporary stack slot
+    // 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>,
                                  lvalue: &mir::Lvalue<'tcx>, f: F) -> U
     where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
     {
-        match *lvalue {
-            mir::Lvalue::Temp(idx) => {
-                match self.temps[idx as usize] {
-                    TempRef::Lvalue(lvalue) => f(self, lvalue),
-                    TempRef::Operand(None) => {
-                        let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
-                        let lvalue_ty = bcx.monomorphize(&lvalue_ty);
-                        let lvalue = LvalueRef::alloca(bcx,
-                                                       lvalue_ty.to_ty(bcx.tcx()),
-                                                       "lvalue_temp");
-                        let ret = f(self, lvalue);
-                        let op = self.trans_load(bcx, lvalue.llval, lvalue_ty.to_ty(bcx.tcx()));
-                        self.temps[idx as usize] = TempRef::Operand(Some(op));
-                        ret
-                    }
-                    TempRef::Operand(Some(_)) => {
-                        let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
-                        let lvalue_ty = bcx.monomorphize(&lvalue_ty);
-
-                        // See comments in TempRef::new_operand as to why
-                        // we always have Some in a ZST TempRef::Operand.
-                        let ty = lvalue_ty.to_ty(bcx.tcx());
-                        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());
-                            f(self, LvalueRef::new_sized(llptr, lvalue_ty))
-                        } else {
-                            bug!("Lvalue temp already set");
-                        }
+        if let Some(index) = self.mir.local_index(lvalue) {
+            match self.locals[index] {
+                LocalRef::Lvalue(lvalue) => f(self, lvalue),
+                LocalRef::Operand(None) => {
+                    let lvalue_ty = self.lvalue_ty(lvalue);
+                    let lvalue = LvalueRef::alloca(bcx,
+                                                   lvalue_ty,
+                                                   "lvalue_temp");
+                    let ret = f(self, lvalue);
+                    let op = self.trans_load(bcx, lvalue.llval, lvalue_ty);
+                    self.locals[index] = LocalRef::Operand(Some(op));
+                    ret
+                }
+                LocalRef::Operand(Some(_)) => {
+                    // See comments in LocalRef::new_operand as to why
+                    // we always have Some in a ZST LocalRef::Operand.
+                    let ty = self.lvalue_ty(lvalue);
+                    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());
+                        f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty)))
+                    } else {
+                        bug!("Lvalue local already set");
                     }
                 }
             }
-            _ => {
-                let lvalue = self.trans_lvalue(bcx, lvalue);
-                f(self, lvalue)
-            }
+        } else {
+            let lvalue = self.trans_lvalue(bcx, lvalue);
+            f(self, lvalue)
         }
     }
 
@@ -264,4 +288,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             llindex
         }
     }
+
+    pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
+        let tcx = self.fcx.ccx.tcx();
+        let lvalue_ty = self.mir.lvalue_ty(tcx, lvalue);
+        self.fcx.monomorphize(&lvalue_ty.to_ty(tcx))
+    }
 }
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index d1206550b13..0db5d3ae4d1 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -16,7 +16,7 @@ use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
 use session::config::FullDebugInfo;
 use base;
-use common::{self, Block, BlockAndBuilder, CrateContext, FunctionContext};
+use common::{self, Block, BlockAndBuilder, CrateContext, FunctionContext, C_null};
 use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind};
 use machine;
 use type_of;
@@ -30,11 +30,12 @@ use std::rc::Rc;
 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::lvalue::{LvalueRef, get_dataptr, get_meta};
-use rustc_mir::traversal;
+use rustc::mir::traversal;
 
 use self::operand::{OperandRef, OperandValue};
 
@@ -71,28 +72,25 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
     llpersonalityslot: Option<ValueRef>,
 
     /// A `Block` for each MIR `BasicBlock`
-    blocks: Vec<Block<'bcx, 'tcx>>,
+    blocks: IndexVec<mir::BasicBlock, Block<'bcx, 'tcx>>,
 
     /// The funclet status of each basic block
-    cleanup_kinds: Vec<analyze::CleanupKind>,
+    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: Vec<Option<Block<'bcx, 'tcx>>>,
+    landing_pads: IndexVec<mir::BasicBlock, Option<Block<'bcx, 'tcx>>>,
 
     /// Cached unreachable block
     unreachable_block: Option<Block<'bcx, 'tcx>>,
 
-    /// An LLVM alloca for each MIR `VarDecl`
-    vars: Vec<LvalueRef<'tcx>>,
-
-    /// The location where each MIR `TempDecl` is stored. This is
+    /// The location where each MIR arg/var/tmp/ret is stored. This is
     /// usually an `LvalueRef` representing an alloca, but not always:
     /// sometimes we can skip the alloca and just store the value
     /// directly using an `OperandRef`, which makes for tighter LLVM
     /// IR. The conditions for using an `OperandRef` are as follows:
     ///
-    /// - the type of the temporary must be judged "immediate" by `type_is_immediate`
+    /// - the type of the local must be judged "immediate" by `type_is_immediate`
     /// - the operand must never be referenced indirectly
     ///     - we should not take its address using the `&` operator
     ///     - nor should it appear in an lvalue path like `tmp.a`
@@ -101,37 +99,44 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
     ///
     /// Avoiding allocs can also be important for certain intrinsics,
     /// notably `expect`.
-    temps: Vec<TempRef<'tcx>>,
-
-    /// The arguments to the function; as args are lvalues, these are
-    /// always indirect, though we try to avoid creating an alloca
-    /// when we can (and just reuse the pointer the caller provided).
-    args: Vec<LvalueRef<'tcx>>,
+    locals: IndexVec<mir::Local, LocalRef<'tcx>>,
 
     /// Debug information for MIR scopes.
-    scopes: Vec<DIScope>
+    scopes: IndexVec<mir::VisibilityScope, DIScope>
+}
+
+impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
+    pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc {
+        DebugLoc::ScopeAt(self.scopes[source_info.scope], source_info.span)
+    }
 }
 
-enum TempRef<'tcx> {
+enum LocalRef<'tcx> {
     Lvalue(LvalueRef<'tcx>),
     Operand(Option<OperandRef<'tcx>>),
 }
 
-impl<'tcx> TempRef<'tcx> {
+impl<'tcx> LocalRef<'tcx> {
     fn new_operand<'bcx>(ccx: &CrateContext<'bcx, 'tcx>,
-                         ty: ty::Ty<'tcx>) -> TempRef<'tcx> {
+                         ty: ty::Ty<'tcx>) -> LocalRef<'tcx> {
         if common::type_is_zero_size(ccx, ty) {
             // Zero-size temporaries aren't always initialized, which
             // doesn't matter because they don't contain data, but
             // we need something in the operand.
-            let val = OperandValue::Immediate(common::C_nil(ccx));
+            let llty = type_of::type_of(ccx, ty);
+            let val = if common::type_is_imm_pair(ccx, ty) {
+                let fields = llty.field_types();
+                OperandValue::Pair(C_null(fields[0]), C_null(fields[1]))
+            } else {
+                OperandValue::Immediate(C_null(llty))
+            };
             let op = OperandRef {
                 val: val,
                 ty: ty
             };
-            TempRef::Operand(Some(op))
+            LocalRef::Operand(Some(op))
         } else {
-            TempRef::Operand(None)
+            LocalRef::Operand(None)
         }
     }
 }
@@ -142,12 +147,10 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
     let bcx = fcx.init(false, None).build();
     let mir = bcx.mir();
 
-    let mir_blocks = mir.all_basic_blocks();
-
     // Analyze the temps to determine which must be lvalues
     // FIXME
-    let (lvalue_temps, cleanup_kinds) = bcx.with_block(|bcx| {
-        (analyze::lvalue_temps(bcx, &mir),
+    let (lvalue_locals, cleanup_kinds) = bcx.with_block(|bcx| {
+        (analyze::lvalue_locals(bcx, &mir),
          analyze::cleanup_kinds(bcx, &mir))
     });
 
@@ -155,52 +158,62 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
     let scopes = debuginfo::create_mir_scopes(fcx);
 
     // Allocate variable and temp allocas
-    let args = arg_value_refs(&bcx, &mir, &scopes);
-    let vars = mir.var_decls.iter()
-                            .map(|decl| (bcx.monomorphize(&decl.ty), decl))
-                            .map(|(mty, decl)| {
-        let lvalue = LvalueRef::alloca(&bcx, mty, &decl.name.as_str());
-
-        let scope = scopes[decl.scope.index()];
-        if !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
-            bcx.with_block(|bcx| {
-                declare_local(bcx, decl.name, mty, scope,
-                              VariableAccess::DirectVariable { alloca: lvalue.llval },
-                              VariableKind::LocalVariable, decl.span);
-            });
-        }
+    let locals = {
+        let args = arg_local_refs(&bcx, &mir, &scopes, &lvalue_locals);
+        let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| {
+            let ty = bcx.monomorphize(&decl.ty);
+            let scope = scopes[decl.source_info.scope];
+            let dbg = !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo;
+
+            let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap();
+            if !lvalue_locals.contains(local.index()) && !dbg {
+                return LocalRef::new_operand(bcx.ccx(), ty);
+            }
 
-        lvalue
-    }).collect();
-    let temps = mir.temp_decls.iter()
-                              .map(|decl| bcx.monomorphize(&decl.ty))
-                              .enumerate()
-                              .map(|(i, mty)| if lvalue_temps.contains(i) {
-                                  TempRef::Lvalue(LvalueRef::alloca(&bcx,
-                                                                    mty,
-                                                                    &format!("temp{:?}", i)))
-                              } else {
-                                  // If this is an immediate temp, we do not create an
-                                  // alloca in advance. Instead we wait until we see the
-                                  // definition and update the operand there.
-                                  TempRef::new_operand(bcx.ccx(), mty)
-                              })
-                              .collect();
+            let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str());
+            if dbg {
+                bcx.with_block(|bcx| {
+                    declare_local(bcx, decl.name, ty, scope,
+                                VariableAccess::DirectVariable { alloca: lvalue.llval },
+                                VariableKind::LocalVariable, decl.source_info.span);
+                });
+            }
+            LocalRef::Lvalue(lvalue)
+        });
+
+        let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| {
+            (mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty)
+        }).chain(mir.return_ty.maybe_converging().map(|ty| (mir::Lvalue::ReturnPointer, ty)));
+
+        args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| {
+            let ty = bcx.monomorphize(&ty);
+            let local = mir.local_index(&lvalue).unwrap();
+            if lvalue == mir::Lvalue::ReturnPointer && fcx.fn_ty.ret.is_indirect() {
+                let llretptr = llvm::get_param(fcx.llfn, 0);
+                LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
+            } else if lvalue_locals.contains(local.index()) {
+                LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", lvalue)))
+            } else {
+                // If this is an immediate local, we do not create an
+                // alloca in advance. Instead we wait until we see the
+                // definition and update the operand there.
+                LocalRef::new_operand(bcx.ccx(), ty)
+            }
+        })).collect()
+    };
 
     // Allocate a `Block` for every basic block
-    let block_bcxs: Vec<Block<'blk,'tcx>> =
-        mir_blocks.iter()
-                  .map(|&bb|{
-                      if bb == mir::START_BLOCK {
-                          fcx.new_block("start", None)
-                      } else {
-                          fcx.new_block(&format!("{:?}", bb), None)
-                      }
-                  })
-                  .collect();
+    let block_bcxs: IndexVec<mir::BasicBlock, Block<'blk,'tcx>> =
+        mir.basic_blocks().indices().map(|bb| {
+            if bb == mir::START_BLOCK {
+                fcx.new_block("start", None)
+            } else {
+                fcx.new_block(&format!("{:?}", bb), None)
+            }
+        }).collect();
 
     // Branch to the START block
-    let start_bcx = block_bcxs[mir::START_BLOCK.index()];
+    let start_bcx = block_bcxs[mir::START_BLOCK];
     bcx.br(start_bcx.llbb);
 
     // Up until here, IR instructions for this function have explicitly not been annotated with
@@ -215,14 +228,12 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
         blocks: block_bcxs,
         unreachable_block: None,
         cleanup_kinds: cleanup_kinds,
-        landing_pads: mir_blocks.iter().map(|_| None).collect(),
-        vars: vars,
-        temps: temps,
-        args: args,
+        landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
+        locals: locals,
         scopes: scopes
     };
 
-    let mut visited = BitVector::new(mir_blocks.len());
+    let mut visited = BitVector::new(mir.basic_blocks().len());
 
     let mut rpo = traversal::reverse_postorder(&mir);
 
@@ -240,8 +251,8 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
 
     // Remove blocks that haven't been visited, or have no
     // predecessors.
-    for &bb in &mir_blocks {
-        let block = mircx.blocks[bb.index()];
+    for bb in mir.basic_blocks().indices() {
+        let block = mircx.blocks[bb];
         let block = BasicBlock(block.llbb);
         // Unreachable block
         if !visited.contains(bb.index()) {
@@ -257,28 +268,27 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
 /// Produce, for each argument, a `ValueRef` pointing at the
 /// argument's value. As arguments are lvalues, these are always
 /// indirect.
-fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
+fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                               mir: &mir::Mir<'tcx>,
-                              scopes: &[DIScope])
-                              -> Vec<LvalueRef<'tcx>> {
+                              scopes: &IndexVec<mir::VisibilityScope, DIScope>,
+                              lvalue_locals: &BitVector)
+                              -> Vec<LocalRef<'tcx>> {
     let fcx = bcx.fcx();
     let tcx = bcx.tcx();
     let mut idx = 0;
     let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
 
-    // Get the argument scope assuming ScopeId(0) has no parent.
-    let arg_scope = mir.scopes.get(0).and_then(|data| {
-        let scope = scopes[0];
-        if data.parent_scope.is_none() && !scope.is_null() &&
-           bcx.sess().opts.debuginfo == FullDebugInfo {
-            Some(scope)
-        } else {
-            None
-        }
-    });
+    // Get the argument scope, if it exists and if we need it.
+    let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE];
+    let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
+        Some(arg_scope)
+    } else {
+        None
+    };
 
     mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
         let arg_ty = bcx.monomorphize(&arg_decl.ty);
+        let local = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(arg_index))).unwrap();
         if arg_decl.spread {
             // This argument (e.g. the last argument in the "rust-call" ABI)
             // is a tuple that was spread at the ABI level and now we have
@@ -299,8 +309,8 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                 let arg = &fcx.fn_ty.args[idx];
                 idx += 1;
                 if common::type_is_fat_ptr(tcx, 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.
+                    // 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];
                     idx += 1;
                     arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst));
@@ -329,7 +339,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                                   bcx.fcx().span.unwrap_or(DUMMY_SP));
                 }));
             }
-            return LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty));
+            return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
         }
 
         let arg = &fcx.fn_ty.args[idx];
@@ -339,14 +349,47 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
             // already put it in a temporary alloca and gave it up, unless
             // we emit extra-debug-info, which requires local allocas :(.
             // FIXME: lifetimes
+            if arg.pad.is_some() {
+                llarg_idx += 1;
+            }
             let llarg = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
             llarg_idx += 1;
             llarg
+        } else if !lvalue_locals.contains(local.index()) &&
+                  !arg.is_indirect() && arg.cast.is_none() &&
+                  arg_scope.is_none() {
+            if arg.is_ignore() {
+                return LocalRef::new_operand(bcx.ccx(), arg_ty);
+            }
+
+            // We don't have to cast or keep the argument in the alloca.
+            // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
+            // of putting everything in allocas just so we can use llvm.dbg.declare.
+            if arg.pad.is_some() {
+                llarg_idx += 1;
+            }
+            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];
+                idx += 1;
+                assert_eq!((meta.cast, meta.pad), (None, None));
+                let llmeta = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
+                llarg_idx += 1;
+                OperandValue::Pair(llarg, llmeta)
+            } else {
+                OperandValue::Immediate(llarg)
+            };
+            let operand = OperandRef {
+                val: val,
+                ty: arg_ty
+            };
+            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 = bcx.with_block(|bcx| {
-                    base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
-                });
                 // 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.
@@ -354,17 +397,12 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                 idx += 1;
                 arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, lltemp));
                 meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, lltemp));
-                lltemp
             } else  {
-                // otherwise, arg is passed by value, so store it into a temporary.
-                let llarg_ty = arg.cast.unwrap_or(arg.memory_ty(bcx.ccx()));
-                let lltemp = bcx.with_block(|bcx| {
-                    base::alloca(bcx, llarg_ty, &format!("arg{}", arg_index))
-                });
+                // otherwise, arg is passed by value, so make a
+                // temporary and store it there
                 arg.store_fn_arg(bcx, &mut llarg_idx, lltemp);
-                // And coerce the temporary into the type we expect.
-                bcx.pointercast(lltemp, arg.memory_ty(bcx.ccx()).ptr_to())
             }
+            lltemp
         };
         bcx.with_block(|bcx| arg_scope.map(|scope| {
             // Is this a regular argument?
@@ -440,7 +478,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                               bcx.fcx().span.unwrap_or(DUMMY_SP));
             }
         }));
-        LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty))
+        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 c21f112b5f6..446ac91b1f5 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -11,6 +11,8 @@
 use llvm::ValueRef;
 use rustc::ty::Ty;
 use rustc::mir::repr as mir;
+use rustc_data_structures::indexed_vec::Idx;
+
 use base;
 use common::{self, Block, BlockAndBuilder};
 use value::Value;
@@ -19,7 +21,7 @@ use type_::Type;
 
 use std::fmt;
 
-use super::{MirContext, TempRef};
+use super::{MirContext, LocalRef};
 
 /// The representation of a Rust value. The enum variant is in fact
 /// uniquely determined by the value's type, but is kept as a
@@ -110,6 +112,8 @@ impl<'bcx, 'tcx> OperandRef<'tcx> {
         if let OperandValue::Immediate(llval) = self.val {
             // Deconstruct the immediate aggregate.
             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);
 
@@ -162,56 +166,65 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         OperandRef { val: val, ty: ty }
     }
 
-    pub fn trans_operand(&mut self,
+    pub fn trans_consume(&mut self,
                          bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                         operand: &mir::Operand<'tcx>)
+                         lvalue: &mir::Lvalue<'tcx>)
                          -> OperandRef<'tcx>
     {
-        debug!("trans_operand(operand={:?})", operand);
+        debug!("trans_consume(lvalue={:?})", lvalue);
 
-        match *operand {
-            mir::Operand::Consume(ref lvalue) => {
-                // watch out for temporaries that do not have an
-                // alloca; they are handled somewhat differently
-                if let &mir::Lvalue::Temp(index) = lvalue {
-                    match self.temps[index as usize] {
-                        TempRef::Operand(Some(o)) => {
-                            return o;
-                        }
-                        TempRef::Operand(None) => {
-                            bug!("use of {:?} before def", lvalue);
-                        }
-                        TempRef::Lvalue(..) => {
-                            // use path below
-                        }
-                    }
+        // watch out for locals that do not have an
+        // alloca; they are handled somewhat differently
+        if let Some(index) = self.mir.local_index(lvalue) {
+            match self.locals[index] {
+                LocalRef::Operand(Some(o)) => {
+                    return o;
                 }
+                LocalRef::Operand(None) => {
+                    bug!("use of {:?} before def", lvalue);
+                }
+                LocalRef::Lvalue(..) => {
+                    // use path below
+                }
+            }
+        }
 
-                // Moves out of pair fields are trivial.
-                if let &mir::Lvalue::Projection(ref proj) = lvalue {
-                    if let mir::Lvalue::Temp(index) = proj.base {
-                        let temp_ref = &self.temps[index as usize];
-                        if let &TempRef::Operand(Some(o)) = temp_ref {
-                            match (o.val, &proj.elem) {
-                                (OperandValue::Pair(a, b),
-                                 &mir::ProjectionElem::Field(ref f, ty)) => {
-                                    let llval = [a, b][f.index()];
-                                    return OperandRef {
-                                        val: OperandValue::Immediate(llval),
-                                        ty: bcx.monomorphize(&ty)
-                                    };
-                                }
-                                _ => {}
-                            }
+        // Moves out of pair fields are trivial.
+        if let &mir::Lvalue::Projection(ref proj) = lvalue {
+            if let Some(index) = self.mir.local_index(&proj.base) {
+                if let LocalRef::Operand(Some(o)) = self.locals[index] {
+                    match (o.val, &proj.elem) {
+                        (OperandValue::Pair(a, b),
+                         &mir::ProjectionElem::Field(ref f, ty)) => {
+                            let llval = [a, b][f.index()];
+                            return OperandRef {
+                                val: OperandValue::Immediate(llval),
+                                ty: bcx.monomorphize(&ty)
+                            };
                         }
+                        _ => {}
                     }
                 }
+            }
+        }
+
+        // for most lvalues, to consume them we just load them
+        // out from their home
+        let tr_lvalue = self.trans_lvalue(bcx, lvalue);
+        let ty = tr_lvalue.ty.to_ty(bcx.tcx());
+        self.trans_load(bcx, tr_lvalue.llval, ty)
+    }
+
+    pub fn trans_operand(&mut self,
+                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                         operand: &mir::Operand<'tcx>)
+                         -> OperandRef<'tcx>
+    {
+        debug!("trans_operand(operand={:?})", operand);
 
-                // for most lvalues, to consume them we just load them
-                // out from their home
-                let tr_lvalue = self.trans_lvalue(bcx, lvalue);
-                let ty = tr_lvalue.ty.to_ty(bcx.tcx());
-                self.trans_load(bcx, tr_lvalue.llval, ty)
+        match *operand {
+            mir::Operand::Consume(ref lvalue) => {
+                self.trans_consume(bcx, lvalue)
             }
 
             mir::Operand::Constant(ref constant) => {
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index ba351d07016..09b07c1440e 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -29,7 +29,7 @@ use Disr;
 use super::MirContext;
 use super::constant::const_scalar_checked_binop;
 use super::operand::{OperandRef, OperandValue};
-use super::lvalue::{LvalueRef, get_dataptr, get_meta};
+use super::lvalue::{LvalueRef, get_dataptr};
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn trans_rvalue(&mut self,
@@ -170,26 +170,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 bcx
             }
 
-            mir::Rvalue::Slice { ref input, from_start, from_end } => {
-                let ccx = bcx.ccx();
-                let input = self.trans_lvalue(&bcx, input);
-                let ty = input.ty.to_ty(bcx.tcx());
-                let (llbase1, lllen) = match ty.sty {
-                    ty::TyArray(_, n) => {
-                        (bcx.gepi(input.llval, &[0, from_start]), C_uint(ccx, n))
-                    }
-                    ty::TySlice(_) | ty::TyStr => {
-                        (bcx.gepi(input.llval, &[from_start]), input.llextra)
-                    }
-                    _ => bug!("cannot slice {}", ty)
-                };
-                let adj = C_uint(ccx, from_start + from_end);
-                let lllen1 = bcx.sub(lllen, adj);
-                bcx.store(llbase1, get_dataptr(&bcx, dest.llval));
-                bcx.store(lllen1, get_meta(&bcx, dest.llval));
-                bcx
-            }
-
             mir::Rvalue::InlineAsm { ref asm, ref outputs, ref inputs } => {
                 let outputs = outputs.iter().map(|output| {
                     let lvalue = self.trans_lvalue(&bcx, output);
@@ -373,7 +353,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 let ty = tr_lvalue.ty.to_ty(bcx.tcx());
                 let ref_ty = bcx.tcx().mk_ref(
-                    bcx.tcx().mk_region(ty::ReStatic),
+                    bcx.tcx().mk_region(ty::ReErased),
                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }
                 );
 
@@ -498,7 +478,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             }
             mir::Rvalue::Repeat(..) |
             mir::Rvalue::Aggregate(..) |
-            mir::Rvalue::Slice { .. } |
             mir::Rvalue::InlineAsm { .. } => {
                 bug!("cannot generate operand from rvalue {:?}", rvalue);
 
@@ -652,7 +631,6 @@ pub fn rvalue_creates_operand<'bcx, 'tcx>(_mir: &mir::Mir<'tcx>,
             true,
         mir::Rvalue::Repeat(..) |
         mir::Rvalue::Aggregate(..) |
-        mir::Rvalue::Slice { .. } |
         mir::Rvalue::InlineAsm { .. } =>
             false,
     }
diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs
index c9a4e540fa0..55efa75b173 100644
--- a/src/librustc_trans/mir/statement.rs
+++ b/src/librustc_trans/mir/statement.rs
@@ -9,11 +9,11 @@
 // except according to those terms.
 
 use rustc::mir::repr as mir;
+
 use common::{self, BlockAndBuilder};
-use debuginfo::DebugLoc;
 
 use super::MirContext;
-use super::TempRef;
+use super::LocalRef;
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn trans_statement(&mut self,
@@ -22,45 +22,39 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                            -> BlockAndBuilder<'bcx, 'tcx> {
         debug!("trans_statement(statement={:?})", statement);
 
-        let debug_loc = DebugLoc::ScopeAt(self.scopes[statement.scope.index()],
-                                          statement.span);
+        let debug_loc = self.debug_loc(statement.source_info);
         debug_loc.apply_to_bcx(&bcx);
         debug_loc.apply(bcx.fcx());
         match statement.kind {
             mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
-                match *lvalue {
-                    mir::Lvalue::Temp(index) => {
-                        let index = index as usize;
-                        match self.temps[index as usize] {
-                            TempRef::Lvalue(tr_dest) => {
-                                self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
-                            }
-                            TempRef::Operand(None) => {
-                                let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue,
-                                                                               debug_loc);
-                                self.temps[index] = TempRef::Operand(Some(operand));
-                                bcx
-                            }
-                            TempRef::Operand(Some(_)) => {
-                                let ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
-                                let ty = bcx.monomorphize(&ty.to_ty(bcx.tcx()));
+                if let Some(index) = self.mir.local_index(lvalue) {
+                    match self.locals[index] {
+                        LocalRef::Lvalue(tr_dest) => {
+                            self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
+                        }
+                        LocalRef::Operand(None) => {
+                            let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue,
+                                                                           debug_loc);
+                            self.locals[index] = LocalRef::Operand(Some(operand));
+                            bcx
+                        }
+                        LocalRef::Operand(Some(_)) => {
+                            let ty = self.lvalue_ty(lvalue);
 
-                                if !common::type_is_zero_size(bcx.ccx(), ty) {
-                                    span_bug!(statement.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
-                                }
+                            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
                             }
                         }
                     }
-                    _ => {
-                        let tr_dest = self.trans_lvalue(&bcx, lvalue);
-                        self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
-                    }
+                } else {
+                    let tr_dest = self.trans_lvalue(&bcx, lvalue);
+                    self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
                 }
             }
         }
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index cf84dd57d02..dad82167a76 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -50,12 +50,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty);
     debug!("mono_ty = {:?} (post-substitution)", mono_ty);
 
-    match ccx.instances().borrow().get(&instance) {
-        Some(&val) => {
-            debug!("leaving monomorphic fn {:?}", instance);
-            return (val, mono_ty);
-        }
-        None => ()
+    if let Some(&val) = ccx.instances().borrow().get(&instance) {
+        debug!("leaving monomorphic fn {:?}", instance);
+        return (val, mono_ty);
     }
 
     debug!("monomorphic_fn({:?})", instance);
@@ -180,7 +177,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
 impl<'tcx> Instance<'tcx> {
     pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
                -> Instance<'tcx> {
-        assert!(substs.regions.iter().all(|&r| r == ty::ReStatic));
+        assert!(substs.regions.iter().all(|&r| r == ty::ReErased));
         Instance { def: def_id, substs: substs }
     }
     pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 472d6ac67f4..350ebf20165 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -734,7 +734,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
         let path = &trait_ref.path;
-        match ::lookup_full_def(self.tcx(), path.span, trait_ref.ref_id) {
+        match self.tcx().expect_def(trait_ref.ref_id) {
             Def::Trait(trait_def_id) => trait_def_id,
             Def::Err => {
                 self.tcx().sess.fatal("cannot continue compilation due to previous error");
@@ -1064,12 +1064,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         match ty.node {
             hir::TyPath(None, ref path) => {
-                let def = match self.tcx().def_map.borrow().get(&ty.id) {
-                    Some(&def::PathResolution { base_def, depth: 0, .. }) => Some(base_def),
-                    _ => None
-                };
-                match def {
-                    Some(Def::Trait(trait_def_id)) => {
+                let resolution = self.tcx().expect_resolution(ty.id);
+                match resolution.base_def {
+                    Def::Trait(trait_def_id) if resolution.depth == 0 => {
                         let mut projection_bounds = Vec::new();
                         let trait_ref =
                             self.object_path_to_poly_trait_ref(rscope,
@@ -1721,17 +1718,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             hir::TyPath(ref maybe_qself, ref path) => {
                 debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
-                let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) {
-                    d
-                } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
-                    // Create some fake resolution that can't possibly be a type.
-                    def::PathResolution {
-                        base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
-                        depth: path.segments.len()
-                    }
-                } else {
-                    span_bug!(ast_ty.span, "unbound path {:?}", ast_ty)
-                };
+                let path_res = tcx.expect_resolution(ast_ty.id);
                 let def = path_res.base_def;
                 let base_ty_end = path.segments.len() - path_res.depth;
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| {
@@ -1748,10 +1735,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
                 if path_res.depth != 0 && ty.sty != ty::TyError {
                     // Write back the new resolution.
-                    tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution {
-                        base_def: def,
-                        depth: 0
-                    });
+                    tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution::new(def));
                 }
 
                 ty
@@ -2232,7 +2216,7 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     for ast_bound in ast_bounds {
         match *ast_bound {
             hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
-                match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
+                match tcx.expect_def(b.trait_ref.ref_id) {
                     Def::Trait(trait_did) => {
                         if tcx.try_add_builtin_trait(trait_did,
                                                      &mut builtin_bounds) {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 99b443e2924..1cff392cf83 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use hir::def::{self, Def};
+use hir::def::Def;
 use rustc::infer::{self, InferOk, TypeOrigin};
-use hir::pat_util::{PatIdMap, pat_id_map};
 use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
@@ -19,9 +18,8 @@ use lint;
 use util::nodemap::FnvHashMap;
 use session::Session;
 
-use std::cmp;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
-use std::ops::Deref;
+use std::cmp;
 use syntax::ast;
 use syntax::codemap::{Span, Spanned};
 use syntax::ptr::P;
@@ -29,18 +27,6 @@ use syntax::ptr::P;
 use rustc::hir::{self, PatKind};
 use rustc::hir::print as pprust;
 
-pub struct PatCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    pub fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-    pub map: PatIdMap,
-}
-
-impl<'a, 'gcx, 'tcx> Deref for PatCtxt<'a, 'gcx, 'tcx> {
-    type Target = FnCtxt<'a, 'gcx, 'tcx>;
-    fn deref(&self) -> &Self::Target {
-        self.fcx
-    }
-}
-
 // This function exists due to the warning "diagnostic code E0164 already used"
 fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
     let name = pprust::path_to_string(path);
@@ -55,7 +41,7 @@ fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: b
     }
 }
 
-impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
         let tcx = self.tcx;
 
@@ -150,26 +136,22 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
                 self.demand_eqtype(pat.span, expected, lhs_ty);
             }
             PatKind::Path(..) if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
-                if let Some(pat_def) = tcx.def_map.borrow().get(&pat.id) {
-                    let const_did = pat_def.def_id();
-                    let const_scheme = tcx.lookup_item_type(const_did);
-                    assert!(const_scheme.generics.is_empty());
-                    let const_ty = self.instantiate_type_scheme(pat.span,
-                                                                &Substs::empty(),
-                                                                &const_scheme.ty);
-                    self.write_ty(pat.id, const_ty);
-
-                    // FIXME(#20489) -- we should limit the types here to scalars or something!
-
-                    // As with PatKind::Lit, what we really want here is that there
-                    // exist a LUB, but for the cases that can occur, subtype
-                    // is good enough.
-                    self.demand_suptype(pat.span, expected, const_ty);
-                } else {
-                    self.write_error(pat.id);
-                }
-            }
-            PatKind::Binding(bm, ref path, ref sub) => {
+                let const_did = tcx.expect_def(pat.id).def_id();
+                let const_scheme = tcx.lookup_item_type(const_did);
+                assert!(const_scheme.generics.is_empty());
+                let const_ty = self.instantiate_type_scheme(pat.span,
+                                                            &Substs::empty(),
+                                                            &const_scheme.ty);
+                self.write_ty(pat.id, const_ty);
+
+                // FIXME(#20489) -- we should limit the types here to scalars or something!
+
+                // As with PatKind::Lit, what we really want here is that there
+                // exist a LUB, but for the cases that can occur, subtype
+                // is good enough.
+                self.demand_suptype(pat.span, expected, const_ty);
+            }
+            PatKind::Binding(bm, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
                 match bm {
                     hir::BindByRef(mutbl) => {
@@ -198,15 +180,19 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
 
                 // if there are multiple arms, make sure they all agree on
                 // what the type of the binding `x` ought to be
-                if let Some(&canon_id) = self.map.get(&path.node) {
-                    if canon_id != pat.id {
-                        let ct = self.local_ty(pat.span, canon_id);
-                        self.demand_eqtype(pat.span, ct, typ);
+                match tcx.expect_def(pat.id) {
+                    Def::Err => {}
+                    Def::Local(_, var_id) => {
+                        if var_id != pat.id {
+                            let vt = self.local_ty(pat.span, var_id);
+                            self.demand_eqtype(pat.span, vt, typ);
+                        }
                     }
+                    d => bug!("bad def for pattern binding `{:?}`", d)
+                }
 
-                    if let Some(ref p) = *sub {
-                        self.check_pat(&p, expected);
-                    }
+                if let Some(ref p) = *sub {
+                    self.check_pat(&p, expected);
                 }
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
@@ -217,25 +203,12 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
             }
             PatKind::QPath(ref qself, ref path) => {
                 let self_ty = self.to_ty(&qself.ty);
-                let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
-                    if d.base_def == Def::Err {
-                        self.set_tainted_by_errors();
-                        self.write_error(pat.id);
-                        return;
-                    }
-                    d
-                } else if qself.position == 0 {
-                    // This is just a sentinel for finish_resolving_def_to_ty.
-                    let sentinel = self.tcx.map.local_def_id(ast::CRATE_NODE_ID);
-                    def::PathResolution {
-                        base_def: Def::Mod(sentinel),
-                        depth: path.segments.len()
-                    }
-                } else {
-                    debug!("unbound path {:?}", pat);
+                let path_res = tcx.expect_resolution(pat.id);
+                if path_res.base_def == Def::Err {
+                    self.set_tainted_by_errors();
                     self.write_error(pat.id);
                     return;
-                };
+                }
                 if let Some((opt_ty, segments, def)) =
                         self.resolve_ty_and_def_ufcs(path_res, Some(self_ty),
                                                      path, pat.span, pat.id) {
@@ -323,44 +296,53 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
             }
             PatKind::Vec(ref before, ref slice, ref after) => {
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
-                let inner_ty = self.next_ty_var();
-                let pat_ty = match expected_ty.sty {
-                    ty::TyArray(_, size) => tcx.mk_array(inner_ty, {
+                let (inner_ty, slice_ty) = match expected_ty.sty {
+                    ty::TyArray(inner_ty, size) => {
                         let min_len = before.len() + after.len();
-                        match *slice {
-                            Some(_) => cmp::max(min_len, size),
-                            None => min_len
+                        if slice.is_none() {
+                            if min_len != size {
+                                span_err!(tcx.sess, pat.span, E0527,
+                                          "pattern requires {} elements but array has {}",
+                                          min_len, size);
+                            }
+                            (inner_ty, tcx.types.err)
+                        } else if let Some(rest) = size.checked_sub(min_len) {
+                            (inner_ty, tcx.mk_array(inner_ty, rest))
+                        } else {
+                            span_err!(tcx.sess, pat.span, E0528,
+                                      "pattern requires at least {} elements but array has {}",
+                                      min_len, size);
+                            (inner_ty, tcx.types.err)
                         }
-                    }),
+                    }
+                    ty::TySlice(inner_ty) => (inner_ty, expected_ty),
                     _ => {
-                        let region = self.next_region_var(infer::PatternRegion(pat.span));
-                        tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
-                            ty: tcx.mk_slice(inner_ty),
-                            mutbl: expected_ty.builtin_deref(true, ty::NoPreference)
-                                              .map_or(hir::MutImmutable, |mt| mt.mutbl)
-                        })
+                        if !expected_ty.references_error() {
+                            let mut err = struct_span_err!(
+                                tcx.sess, pat.span, E0529,
+                                "expected an array or slice, found `{}`",
+                                expected_ty);
+                            if let ty::TyRef(_, ty::TypeAndMut { mutbl: _, ty }) = expected_ty.sty {
+                                match ty.sty {
+                                    ty::TyArray(..) | ty::TySlice(..) => {
+                                        err.help("the semantics of slice patterns changed \
+                                                  recently; see issue #23121");
+                                    }
+                                    _ => {}
+                                }
+                            }
+                            err.emit();
+                        }
+                        (tcx.types.err, tcx.types.err)
                     }
                 };
 
-                self.write_ty(pat.id, pat_ty);
-
-                // `demand::subtype` would be good enough, but using
-                // `eqtype` turns out to be equally general. See (*)
-                // below for details.
-                self.demand_eqtype(pat.span, expected, pat_ty);
+                self.write_ty(pat.id, expected_ty);
 
                 for elt in before {
                     self.check_pat(&elt, inner_ty);
                 }
                 if let Some(ref slice) = *slice {
-                    let region = self.next_region_var(infer::PatternRegion(pat.span));
-                    let mutbl = expected_ty.builtin_deref(true, ty::NoPreference)
-                        .map_or(hir::MutImmutable, |mt| mt.mutbl);
-
-                    let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
-                        ty: tcx.mk_slice(inner_ty),
-                        mutbl: mutbl
-                    });
                     self.check_pat(&slice, slice_ty);
                 }
                 for elt in after {
@@ -369,7 +351,6 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-
         // (*) In most of the cases above (literals and constants being
         // the exception), we relate types using strict equality, evewn
         // though subtyping would be sufficient. There are a few reasons
@@ -485,12 +466,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Typecheck the patterns first, so that we get types for all the
         // bindings.
         for arm in arms {
-            let pcx = PatCtxt {
-                fcx: self,
-                map: pat_id_map(&arm.pats[0]),
-            };
             for p in &arm.pats {
-                pcx.check_pat(&p, discrim_ty);
+                self.check_pat(&p, discrim_ty);
             }
         }
 
@@ -575,13 +552,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn check_pat_struct(&self, pat: &'gcx hir::Pat,
                             path: &hir::Path, fields: &'gcx [Spanned<hir::FieldPat>],
                             etc: bool, expected: Ty<'tcx>) {
         let tcx = self.tcx;
 
-        let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
+        let def = tcx.expect_def(pat.id);
         let variant = match self.def_struct_variant(def, path.span) {
             Some((_, variant)) => variant,
             None => {
@@ -622,18 +599,16 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
         // Typecheck the path.
         let tcx = self.tcx;
 
-        let path_res = match tcx.def_map.borrow().get(&pat.id) {
-            Some(&path_res) if path_res.base_def != Def::Err => path_res,
-            _ => {
-                self.set_tainted_by_errors();
-                self.write_error(pat.id);
+        let path_res = tcx.expect_resolution(pat.id);
+        if path_res.base_def == Def::Err {
+            self.set_tainted_by_errors();
+            self.write_error(pat.id);
 
-                for pat in subpats {
-                    self.check_pat(&pat, tcx.types.err);
-                }
-                return;
+            for pat in subpats {
+                self.check_pat(&pat, tcx.types.err);
             }
-        };
+            return;
+        }
 
         let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res,
                                                                          None, path,
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 417b2fafecf..58abf8db2c3 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -222,7 +222,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let tcx = self.tcx;
                     if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
                         if pr.depth == 0 && pr.base_def != Def::Err {
-                            if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
+                            if let Some(span) = tcx.map.span_if_local(pr.base_def.def_id()) {
                                 err.span_note(span, "defined here");
                             }
                         }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 0bb078dfbcb..d6b696a2548 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -976,7 +976,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         // In general, during probing we erase regions. See
         // `impl_self_ty()` for an explanation.
-        let region = tcx.mk_region(ty::ReStatic);
+        let region = tcx.mk_region(ty::ReErased);
 
         // Search through mutabilities in order to find one where pick works:
         [hir::MutImmutable, hir::MutMutable].iter().filter_map(|&m| {
@@ -1240,7 +1240,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             let method_regions =
                 method.generics.regions.get_slice(subst::FnSpace)
                 .iter()
-                .map(|_| ty::ReStatic)
+                .map(|_| ty::ReErased)
                 .collect();
 
             placeholder = (*substs).clone().with_method(Vec::new(), method_regions);
@@ -1276,7 +1276,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         let region_placeholders =
             impl_pty.generics.regions.map(
-                |_| ty::ReStatic); // see erase_late_bound_regions() for an expl of why 'static
+                |_| ty::ReErased); // see erase_late_bound_regions() for an expl of why 'erased
 
         let substs = subst::Substs::new(type_vars, region_placeholders);
         (impl_pty.ty, substs)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index de45883c872..6f7f33fe24d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -81,14 +81,13 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl};
 use self::TupleArgumentsFlag::*;
 
 use astconv::{AstConv, ast_region_to_region, PathParamMode};
-use check::_match::PatCtxt;
 use dep_graph::DepNode;
 use fmt_macros::{Parser, Piece, Position};
 use middle::cstore::LOCAL_CRATE;
 use hir::def::{self, Def};
 use hir::def_id::DefId;
+use hir::pat_util;
 use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
-use hir::pat_util::{self, pat_id_map};
 use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
 use rustc::traits::{self, ProjectionMode};
 use rustc::ty::{GenericPredicates, TypeScheme};
@@ -102,7 +101,7 @@ use rustc::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
 use session::{Session, CompileResult};
-use {CrateCtxt, lookup_full_def};
+use CrateCtxt;
 use TypeAndSubsts;
 use lint;
 use util::common::{block_query, ErrorReported, indenter, loop_query};
@@ -672,11 +671,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
             });
 
             // Check the pattern.
-            let pcx = PatCtxt {
-                fcx: &fcx,
-                map: pat_id_map(&input.pat),
-            };
-            pcx.check_pat(&input.pat, *arg_ty);
+            fcx.check_pat(&input.pat, *arg_ty);
         }
 
         visit.visit_block(body);
@@ -2407,29 +2402,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let mut expected_arg_tys = expected_arg_tys;
         let expected_arg_count = fn_inputs.len();
+
+        fn parameter_count_error<'tcx>(sess: &Session, sp: Span, fn_inputs: &[Ty<'tcx>],
+                                       expected_count: usize, arg_count: usize, error_code: &str,
+                                       variadic: bool) {
+            let mut err = sess.struct_span_err_with_code(sp,
+                &format!("this function takes {}{} parameter{} but {} parameter{} supplied",
+                    if variadic {"at least "} else {""},
+                    expected_count,
+                    if expected_count == 1 {""} else {"s"},
+                    arg_count,
+                    if arg_count == 1 {" was"} else {"s were"}),
+                error_code);
+            let input_types = fn_inputs.iter().map(|i| format!("{:?}", i)).collect::<Vec<String>>();
+            if input_types.len() > 0 {
+                err.note(&format!("the following parameter type{} expected: {}",
+                        if expected_count == 1 {" was"} else {"s were"},
+                        input_types.join(", ")));
+            }
+            err.emit();
+        }
+
         let formal_tys = if tuple_arguments == TupleArguments {
             let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
             match tuple_type.sty {
+                ty::TyTuple(arg_types) if arg_types.len() != args.len() => {
+                    parameter_count_error(tcx.sess, sp, fn_inputs, arg_types.len(), args.len(),
+                                          "E0057", false);
+                    expected_arg_tys = &[];
+                    self.err_args(args.len())
+                }
                 ty::TyTuple(arg_types) => {
-                    if arg_types.len() != args.len() {
-                        span_err!(tcx.sess, sp, E0057,
-                            "this function takes {} parameter{} but {} parameter{} supplied",
-                            arg_types.len(),
-                            if arg_types.len() == 1 {""} else {"s"},
-                            args.len(),
-                            if args.len() == 1 {" was"} else {"s were"});
-                        expected_arg_tys = &[];
-                        self.err_args(args.len())
-                    } else {
-                        expected_arg_tys = match expected_arg_tys.get(0) {
-                            Some(&ty) => match ty.sty {
-                                ty::TyTuple(ref tys) => &tys,
-                                _ => &[]
-                            },
-                            None => &[]
-                        };
-                        arg_types.to_vec()
-                    }
+                    expected_arg_tys = match expected_arg_tys.get(0) {
+                        Some(&ty) => match ty.sty {
+                            ty::TyTuple(ref tys) => &tys,
+                            _ => &[]
+                        },
+                        None => &[]
+                    };
+                    arg_types.to_vec()
                 }
                 _ => {
                     span_err!(tcx.sess, sp, E0059,
@@ -2445,23 +2456,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if supplied_arg_count >= expected_arg_count {
                 fn_inputs.to_vec()
             } else {
-                span_err!(tcx.sess, sp, E0060,
-                    "this function takes at least {} parameter{} \
-                     but {} parameter{} supplied",
-                    expected_arg_count,
-                    if expected_arg_count == 1 {""} else {"s"},
-                    supplied_arg_count,
-                    if supplied_arg_count == 1 {" was"} else {"s were"});
+                parameter_count_error(tcx.sess, sp, fn_inputs, expected_arg_count,
+                                      supplied_arg_count, "E0060", true);
                 expected_arg_tys = &[];
                 self.err_args(supplied_arg_count)
             }
         } else {
-            span_err!(tcx.sess, sp, E0061,
-                "this function takes {} parameter{} but {} parameter{} supplied",
-                expected_arg_count,
-                if expected_arg_count == 1 {""} else {"s"},
-                supplied_arg_count,
-                if supplied_arg_count == 1 {" was"} else {"s were"});
+            parameter_count_error(tcx.sess, sp, fn_inputs, expected_arg_count, supplied_arg_count,
+                                  "E0061", false);
             expected_arg_tys = &[];
             self.err_args(supplied_arg_count)
         };
@@ -3158,7 +3160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let tcx = self.tcx;
 
         // Find the relevant variant
-        let def = lookup_full_def(tcx, path.span, expr.id);
+        let def = tcx.expect_def(expr.id);
         if def == Def::Err {
             self.set_tainted_by_errors();
             self.check_struct_fields_on_error(expr.id, fields, base_expr);
@@ -3350,18 +3352,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   self.to_ty(&qself.ty)
               });
 
-              let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) {
-                  d
-              } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
-                    // Create some fake resolution that can't possibly be a type.
-                    def::PathResolution {
-                        base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
-                        depth: path.segments.len()
-                    }
-                } else {
-                  span_bug!(expr.span, "unbound path {:?}", expr)
-              };
-
+              let path_res = tcx.expect_resolution(id);
               if let Some((opt_ty, segments, def)) =
                       self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path,
                                                    expr.span, expr.id) {
@@ -3752,10 +3743,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(def) = def {
                 // Write back the new resolution.
-                self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution {
-                    base_def: def,
-                    depth: 0,
-                });
+                self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution::new(def));
                 Some((Some(ty), slice::ref_slice(item_segment), def))
             } else {
                 self.write_error(node_id);
@@ -3800,11 +3788,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        let pcx = PatCtxt {
-            fcx: self,
-            map: pat_id_map(&local.pat),
-        };
-        pcx.check_pat(&local.pat, t);
+        self.check_pat(&local.pat, t);
         let pat_ty = self.node_ty(local.pat.id);
         if pat_ty.references_error() {
             self.write_ty(local.id, pat_ty);
@@ -4562,7 +4546,7 @@ pub fn may_break(tcx: TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool {
     // <id> nested anywhere inside the loop?
     (block_query(b, |e| {
         if let hir::ExprBreak(Some(_)) = e.node {
-            lookup_full_def(tcx, e.span, e.id) == Def::Label(id)
+            tcx.expect_def(e.id) == Def::Label(id)
         } else {
             false
         }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index fd1b6055173..a8cb21126c0 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -1157,25 +1157,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
                discr_cmt,
                root_pat);
-        let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
+    let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
                 match sub_pat.node {
                     // `ref x` pattern
                     PatKind::Binding(hir::BindByRef(mutbl), _, _) => {
                         self.link_region_from_node_type(sub_pat.span, sub_pat.id,
                                                         mutbl, sub_cmt);
                     }
-
-                    // `[_, ..slice, _]` pattern
-                    PatKind::Vec(_, Some(ref slice_pat), _) => {
-                        match mc.cat_slice_pattern(sub_cmt, &slice_pat) {
-                            Ok((slice_cmt, slice_mutbl, slice_r)) => {
-                                self.link_region(sub_pat.span, &slice_r,
-                                                 ty::BorrowKind::from_mutbl(slice_mutbl),
-                                                 slice_cmt);
-                            }
-                            Err(()) => {}
-                        }
-                    }
                     _ => {}
                 }
             });
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index e65f3f0ff41..586c4f5c185 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -532,17 +532,13 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       -> bool
 {
     if let hir::TyPath(None, _) = ast_ty.node {
-        let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
+        let path_res = tcx.expect_resolution(ast_ty.id);
         match path_res.base_def {
-            Def::SelfTy(Some(def_id), None) => {
-                path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
-            }
-            Def::TyParam(_, _, def_id, _) => {
-                path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
-            }
-            _ => {
-                false
+            Def::SelfTy(Some(def_id), None) |
+            Def::TyParam(_, _, def_id, _) if path_res.depth == 0 => {
+                def_id == tcx.map.local_def_id(param_id)
             }
+            _ => false
         }
     } else {
         false
@@ -1719,7 +1715,7 @@ fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
     match unbound {
         Some(ref tpb) => {
             // FIXME(#8559) currently requires the unbound to be built-in.
-            let trait_def_id = tcx.trait_ref_to_def_id(tpb);
+            let trait_def_id = tcx.expect_def(tpb.ref_id).def_id();
             match kind_id {
                 Ok(kind_id) if trait_def_id != kind_id => {
                     tcx.sess.span_warn(span,
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 67a082ee520..c0cca08b676 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1174,7 +1174,7 @@ Erroneous code example:
 
 ```compile_fail
 #[repr(i32)]
-enum NightWatch {} // error: unsupported representation for zero-variant enum
+enum NightsWatch {} // error: unsupported representation for zero-variant enum
 ```
 
 It is impossible to define an integer type to be used to represent zero-variant
@@ -1184,8 +1184,8 @@ two solutions. Either you add variants in your enum:
 
 ```
 #[repr(i32)]
-enum NightWatch {
-    JohnSnow,
+enum NightsWatch {
+    JonSnow,
     Commander,
 }
 ```
@@ -1193,7 +1193,7 @@ enum NightWatch {
 or you remove the integer represention of your enum:
 
 ```
-enum NightWatch {}
+enum NightsWatch {}
 ```
 "##,
 
@@ -4125,7 +4125,7 @@ register_diagnostics! {
 //  E0239, // `next` method of `Iterator` trait has unexpected type
 //  E0240,
 //  E0241,
-    E0242, // internal error looking up a definition
+//  E0242,
     E0245, // not a trait
 //  E0246, // invalid recursive type
 //  E0247,
@@ -4139,5 +4139,8 @@ register_diagnostics! {
            // type `{}` was overridden
     E0436, // functional record update requires a struct
     E0513, // no type for local variable ..
-    E0521  // redundant default implementations of trait
+    E0521, // redundant default implementations of trait
+    E0527, // expected {} elements, found {}
+    E0528, // expected at least {} elements, found {}
+    E0529, // slice pattern expects array or slice, not `{}`
 }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 0b23951db36..c6c575719c0 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -103,7 +103,6 @@ pub use rustc::util;
 
 use dep_graph::DepNode;
 use hir::map as hir_map;
-use hir::def::Def;
 use rustc::infer::TypeOrigin;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -176,15 +175,6 @@ fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn lookup_full_def(tcx: TyCtxt, sp: Span, id: ast::NodeId) -> Def {
-    match tcx.def_map.borrow().get(&id) {
-        Some(x) => x.full_def(),
-        None => {
-            span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
-        }
-    }
-}
-
 fn require_c_abi_if_variadic(tcx: TyCtxt,
                              decl: &hir::FnDecl,
                              abi: Abi,
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 612007da0e9..01a310da25d 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -520,7 +520,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) |
-            ty::ReSkolemized(..) | ty::ReEmpty => {
+            ty::ReSkolemized(..) | ty::ReEmpty | ty::ReErased => {
                 // We don't expect to see anything but 'static or bound
                 // regions when visiting member types or method types.
                 bug!("unexpected region encountered in variance \
diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs
index 77de51b32e2..f570375de5e 100644
--- a/src/librustc_unicode/char.rs
+++ b/src/librustc_unicode/char.rs
@@ -668,10 +668,13 @@ impl char {
     /// Basic usage:
     ///
     /// ```
-    /// assert_eq!('C'.to_lowercase().next(), Some('c'));
+    /// assert_eq!('C'.to_lowercase().collect::<String>(), "c");
+    ///
+    /// // Sometimes the result is more than one character:
+    /// assert_eq!('İ'.to_lowercase().collect::<String>(), "i\u{307}");
     ///
     /// // Japanese scripts do not have case, and so:
-    /// assert_eq!('山'.to_lowercase().next(), Some('山'));
+    /// assert_eq!('山'.to_lowercase().collect::<String>(), "山");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -702,10 +705,13 @@ impl char {
     /// Basic usage:
     ///
     /// ```
-    /// assert_eq!('c'.to_uppercase().next(), Some('C'));
+    /// assert_eq!('c'.to_uppercase().collect::<String>(), "C");
+    ///
+    /// // Sometimes the result is more than one character:
+    /// assert_eq!('ß'.to_uppercase().collect::<String>(), "SS");
     ///
     /// // Japanese does not have case, and so:
-    /// assert_eq!('山'.to_uppercase().next(), Some('山'));
+    /// assert_eq!('山'.to_uppercase().collect::<String>(), "山");
     /// ```
     ///
     /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two:
@@ -716,17 +722,17 @@ impl char {
     /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore:
     ///
     /// ```
-    /// let upper_i = 'i'.to_uppercase().next();
+    /// let upper_i: String = 'i'.to_uppercase().collect();
     /// ```
     ///
     /// The value of `upper_i` here relies on the language of the text: if we're
-    /// in `en-US`, it should be `Some('I')`, but if we're in `tr_TR`, it should
-    /// be `Some('İ')`. `to_uppercase()` does not take this into account, and so:
+    /// in `en-US`, it should be `"I"`, but if we're in `tr_TR`, it should
+    /// be `"İ"`. `to_uppercase()` does not take this into account, and so:
     ///
     /// ```
-    /// let upper_i = 'i'.to_uppercase().next();
+    /// let upper_i: String = 'i'.to_uppercase().collect();
     ///
-    /// assert_eq!(Some('I'), upper_i);
+    /// assert_eq!(upper_i, "I");
     /// ```
     ///
     /// holds across languages.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index f5d54123f37..e49b96cbfd0 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -22,6 +22,7 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::print as pprust;
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::subst;
+use rustc::util::common::slice_pat;
 
 use rustc_const_eval::lookup_const_by_id;
 
@@ -49,8 +50,8 @@ pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option<ast::Name>)
         Some(tcx) => tcx,
         None => return None,
     };
-    let def = match tcx.def_map.borrow().get(&id) {
-        Some(d) => d.full_def(),
+    let def = match tcx.expect_def_or_none(id) {
+        Some(def) => def,
         None => return None,
     };
     let did = def.def_id();
@@ -197,10 +198,10 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let variant = tcx.lookup_adt_def(did).struct_variant();
 
     clean::Struct {
-        struct_type: match &*variant.fields {
-            [] => doctree::Unit,
-            [_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype,
-            [..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple,
+        struct_type: match slice_pat(&&*variant.fields) {
+            &[] => doctree::Unit,
+            &[_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype,
+            &[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple,
             _ => doctree::Plain,
         },
         generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0f3c62aca2a..0801da19c82 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -827,7 +827,8 @@ impl Clean<Option<Lifetime>> for ty::Region {
             ty::ReScope(..) |
             ty::ReVar(..) |
             ty::ReSkolemized(..) |
-            ty::ReEmpty => None
+            ty::ReEmpty |
+            ty::ReErased => None
         }
     }
 }
@@ -2388,9 +2389,11 @@ impl Clean<Vec<Item>> for doctree::Import {
         // We consider inlining the documentation of `pub use` statements, but we
         // forcefully don't inline if this is not public or if the
         // #[doc(no_inline)] attribute is present.
+        // Don't inline doc(hidden) imports so they can be stripped at a later stage.
         let denied = self.vis != hir::Public || self.attrs.iter().any(|a| {
             &a.name()[..] == "doc" && match a.meta_item_list() {
-                Some(l) => attr::contains_name(l, "no_inline"),
+                Some(l) => attr::contains_name(l, "no_inline") ||
+                           attr::contains_name(l, "hidden"),
                 None => false,
             }
         });
@@ -2630,7 +2633,7 @@ fn resolve_type(cx: &DocContext,
             };
         }
     };
-    let def = tcx.def_map.borrow().get(&id).expect("unresolved id not in defmap").full_def();
+    let def = tcx.expect_def(id);
     debug!("resolve_type: def={:?}", def);
 
     let is_generic = match def {
@@ -2699,7 +2702,7 @@ fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSou
 
 fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<DefId> {
     cx.tcx_opt().and_then(|tcx| {
-        tcx.def_map.borrow().get(&id).map(|d| register_def(cx, d.full_def()))
+        tcx.expect_def_or_none(id).map(|def| register_def(cx, def))
     })
 }
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 92401a5c55f..760e84622cf 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -20,6 +20,7 @@ use std::iter::repeat;
 
 use rustc::middle::cstore::LOCAL_CRATE;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::util::common::slice_pat;
 use syntax::abi::Abi;
 use rustc::hir;
 
@@ -474,9 +475,9 @@ impl fmt::Display for clean::Type {
                        decl.decl)
             }
             clean::Tuple(ref typs) => {
-                match &**typs {
-                    [] => primitive_link(f, clean::PrimitiveTuple, "()"),
-                    [ref one] => {
+                match slice_pat(&&**typs) {
+                    &[] => primitive_link(f, clean::PrimitiveTuple, "()"),
+                    &[ref one] => {
                         primitive_link(f, clean::PrimitiveTuple, "(")?;
                         write!(f, "{},", one)?;
                         primitive_link(f, clean::PrimitiveTuple, ")")
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 7ccf51a4629..321bc51f903 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -35,7 +35,7 @@ use syntax::parse;
 pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>) -> String {
     debug!("highlighting: ================\n{}\n==============", src);
     let sess = parse::ParseSess::new();
-    let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
+    let fm = sess.codemap().new_filemap("<stdin>".to_string(), None, src.to_string());
 
     let mut out = Vec::new();
     write_header(class, id, &mut out).unwrap();
@@ -55,7 +55,7 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>
 /// an enclosing `<pre>` block.
 pub fn render_inner_with_highlighting(src: &str) -> io::Result<String> {
     let sess = parse::ParseSess::new();
-    let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
+    let fm = sess.codemap().new_filemap("<stdin>".to_string(), None, src.to_string());
 
     let mut out = Vec::new();
     let mut classifier = Classifier::new(lexer::StringReader::new(&sess.span_diagnostic, fm),
@@ -337,7 +337,7 @@ impl Class {
             Class::MacroNonTerminal => "macro-nonterminal",
             Class::String => "string",
             Class::Number => "number",
-            Class::Bool => "boolvalue",
+            Class::Bool => "bool-val",
             Class::Ident => "ident",
             Class::Lifetime => "lifetime",
             Class::PreludeTy => "prelude-ty",
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 3baf22b38ef..139e1033175 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -408,7 +408,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
             tests.add_test(text.to_owned(),
                            block_info.should_panic, block_info.no_run,
                            block_info.ignore, block_info.test_harness,
-                           block_info.compile_fail);
+                           block_info.compile_fail, block_info.error_codes);
         }
     }
 
@@ -454,6 +454,7 @@ struct LangString {
     rust: bool,
     test_harness: bool,
     compile_fail: bool,
+    error_codes: Vec<String>,
 }
 
 impl LangString {
@@ -465,6 +466,7 @@ impl LangString {
             rust: true,  // NB This used to be `notrust = false`
             test_harness: false,
             compile_fail: false,
+            error_codes: Vec::new(),
         }
     }
 
@@ -472,9 +474,14 @@ impl LangString {
         let mut seen_rust_tags = false;
         let mut seen_other_tags = false;
         let mut data = LangString::all_false();
-        let allow_compile_fail = match get_unstable_features_setting() {
-            UnstableFeatures::Allow | UnstableFeatures::Cheat=> true,
-            _ => false,
+        let mut allow_compile_fail = false;
+        let mut allow_error_code_check = false;
+        match get_unstable_features_setting() {
+            UnstableFeatures::Allow | UnstableFeatures::Cheat => {
+                allow_compile_fail = true;
+                allow_error_code_check = true;
+            }
+            _ => {},
         };
 
         let tokens = string.split(|c: char|
@@ -493,7 +500,15 @@ impl LangString {
                     data.compile_fail = true;
                     seen_rust_tags = true;
                     data.no_run = true;
-                },
+                }
+                x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => {
+                    if let Ok(_) = x[1..].parse::<u32>() {
+                        data.error_codes.push(x.to_owned());
+                        seen_rust_tags = true;
+                    } else {
+                        seen_other_tags = true;
+                    }
+                }
                 _ => { seen_other_tags = true }
             }
         }
@@ -577,7 +592,7 @@ mod tests {
     fn test_lang_string_parse() {
         fn t(s: &str,
             should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
-            compile_fail: bool) {
+            compile_fail: bool, error_codes: Vec<String>) {
             assert_eq!(LangString::parse(s), LangString {
                 should_panic: should_panic,
                 no_run: no_run,
@@ -585,22 +600,26 @@ mod tests {
                 rust: rust,
                 test_harness: test_harness,
                 compile_fail: compile_fail,
+                error_codes: error_codes,
             })
         }
 
         // marker                | should_panic| no_run| ignore| rust | test_harness| compile_fail
-        t("",                      false,        false,  false,  true,  false,        false);
-        t("rust",                  false,        false,  false,  true,  false,        false);
-        t("sh",                    false,        false,  false,  false, false,        false);
-        t("ignore",                false,        false,  true,   true,  false,        false);
-        t("should_panic",          true,         false,  false,  true,  false,        false);
-        t("no_run",                false,        true,   false,  true,  false,        false);
-        t("test_harness",          false,        false,  false,  true,  true,         false);
-        t("compile_fail",          false,        true,   false,  true,  false,        true);
-        t("{.no_run .example}",    false,        true,   false,  true,  false,        false);
-        t("{.sh .should_panic}",   true,         false,  false,  true,  false,        false);
-        t("{.example .rust}",      false,        false,  false,  true,  false,        false);
-        t("{.test_harness .rust}", false,        false,  false,  true,  true,         false);
+        //                       | error_codes
+        t("",                      false,        false,  false,  true,  false, false, Vec::new());
+        t("rust",                  false,        false,  false,  true,  false, false, Vec::new());
+        t("sh",                    false,        false,  false,  false, false, false, Vec::new());
+        t("ignore",                false,        false,  true,   true,  false, false, Vec::new());
+        t("should_panic",          true,         false,  false,  true,  false, false, Vec::new());
+        t("no_run",                false,        true,   false,  true,  false, false, Vec::new());
+        t("test_harness",          false,        false,  false,  true,  true,  false, Vec::new());
+        t("compile_fail",          false,        true,   false,  true,  false, true,  Vec::new());
+        t("E0450",                 false,        false,  false,  true,  false, false,
+                                   vec!("E0450".to_owned()));
+        t("{.no_run .example}",    false,        true,   false,  true,  false, false, Vec::new());
+        t("{.sh .should_panic}",   true,         false,  false,  true,  false, false, Vec::new());
+        t("{.example .rust}",      false,        false,  false,  true,  false, false, Vec::new());
+        t("{.test_harness .rust}", false,        false,  false,  true,  true,  false, Vec::new());
     }
 
     #[test]
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 396f71173f8..493d3d6abc9 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1120,7 +1120,9 @@ impl DocFolder for Cache {
             clean::StructItem(..) | clean::EnumItem(..) |
             clean::TypedefItem(..) | clean::TraitItem(..) |
             clean::FunctionItem(..) | clean::ModuleItem(..) |
-            clean::ForeignFunctionItem(..) if !self.stripped_mod => {
+            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
+            clean::ConstantItem(..) | clean::StaticItem(..)
+            if !self.stripped_mod => {
                 // Reexported items mean that the same id can show up twice
                 // in the rustdoc ast that we're looking at. We know,
                 // however, that a reexported item doesn't show up in the
@@ -1255,7 +1257,6 @@ impl Context {
 
         info!("Recursing into {}", self.dst.display());
 
-        mkdir(&self.dst).unwrap();
         let ret = f(self);
 
         info!("Recursed; leaving {}", self.dst.display());
@@ -1299,7 +1300,7 @@ impl Context {
     fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
         F: FnMut(&mut Context, clean::Item),
     {
-        fn render(w: File, cx: &Context, it: &clean::Item,
+        fn render(writer: &mut io::Write, cx: &Context, it: &clean::Item,
                   pushname: bool) -> io::Result<()> {
             // A little unfortunate that this is done like this, but it sure
             // does make formatting *a lot* nicer.
@@ -1334,28 +1335,24 @@ impl Context {
 
             reset_ids(true);
 
-            // We have a huge number of calls to write, so try to alleviate some
-            // of the pain by using a buffered writer instead of invoking the
-            // write syscall all the time.
-            let mut writer = BufWriter::new(w);
             if !cx.render_redirect_pages {
-                layout::render(&mut writer, &cx.shared.layout, &page,
+                layout::render(writer, &cx.shared.layout, &page,
                                &Sidebar{ cx: cx, item: it },
                                &Item{ cx: cx, item: it },
                                cx.shared.css_file_extension.is_some())?;
             } else {
                 let mut url = repeat("../").take(cx.current.len())
                                            .collect::<String>();
-                if let Some(&(ref names, _)) = cache().paths.get(&it.def_id) {
+                if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
                     for name in &names[..names.len() - 1] {
                         url.push_str(name);
                         url.push_str("/");
                     }
-                    url.push_str(&item_path(it));
-                    layout::redirect(&mut writer, &url)?;
+                    url.push_str(&item_path(ty, names.last().unwrap()));
+                    layout::redirect(writer, &url)?;
                 }
             }
-            writer.flush()
+            Ok(())
         }
 
         // Stripped modules survive the rustdoc passes (i.e. `strip-private`)
@@ -1376,9 +1373,16 @@ impl Context {
             let mut item = Some(item);
             self.recurse(name, |this| {
                 let item = item.take().unwrap();
-                let joint_dst = this.dst.join("index.html");
-                let dst = try_err!(File::create(&joint_dst), &joint_dst);
-                try_err!(render(dst, this, &item, false), &joint_dst);
+
+                let mut buf = Vec::new();
+                render(&mut buf, this, &item, false).unwrap();
+                // buf will be empty if the module is stripped and there is no redirect for it
+                if !buf.is_empty() {
+                    let joint_dst = this.dst.join("index.html");
+                    try_err!(fs::create_dir_all(&this.dst), &this.dst);
+                    let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
+                    try_err!(dst.write_all(&buf), &joint_dst);
+                }
 
                 let m = match item.inner {
                     clean::StrippedItem(box clean::ModuleItem(m)) |
@@ -1387,7 +1391,7 @@ impl Context {
                 };
 
                 // render sidebar-items.js used throughout this module
-                {
+                if !this.render_redirect_pages {
                     let items = this.build_sidebar_items(&m);
                     let js_dst = this.dst.join("sidebar-items.js");
                     let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst));
@@ -1401,10 +1405,16 @@ impl Context {
                 Ok(())
             })
         } else if item.name.is_some() {
-            let joint_dst = self.dst.join(&item_path(&item));
-
-            let dst = try_err!(File::create(&joint_dst), &joint_dst);
-            try_err!(render(dst, self, &item, true), &joint_dst);
+            let mut buf = Vec::new();
+            render(&mut buf, self, &item, true).unwrap();
+            // buf will be empty if the item is stripped and there is no redirect for it
+            if !buf.is_empty() {
+                let joint_dst = self.dst.join(&item_path(shortty(&item),
+                                                         item.name.as_ref().unwrap()));
+                try_err!(fs::create_dir_all(&self.dst), &self.dst);
+                let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
+                try_err!(dst.write_all(&buf), &joint_dst);
+            }
             Ok(())
         } else {
             Ok(())
@@ -1522,7 +1532,7 @@ impl<'a> Item<'a> {
             Some(format!("{root}{path}/{file}?gotosrc={goto}",
                          root = root,
                          path = path[..path.len() - 1].join("/"),
-                         file = item_path(self.item),
+                         file = item_path(shortty(self.item), self.item.name.as_ref().unwrap()),
                          goto = self.item.def_id.index.as_usize()))
         }
     }
@@ -1614,13 +1624,10 @@ impl<'a> fmt::Display for Item<'a> {
     }
 }
 
-fn item_path(item: &clean::Item) -> String {
-    if item.is_mod() {
-        format!("{}/index.html", item.name.as_ref().unwrap())
-    } else {
-        format!("{}.{}.html",
-                shortty(item).to_static_str(),
-                *item.name.as_ref().unwrap())
+fn item_path(ty: ItemType, name: &str) -> String {
+    match ty {
+        ItemType::Module => format!("{}/index.html", name),
+        _ => format!("{}.{}.html", ty.to_static_str(), name),
     }
 }
 
@@ -1649,12 +1656,8 @@ fn plain_summary_line(s: Option<&str>) -> String {
 }
 
 fn document(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)?;
-    }
-    if let Some(s) = item.doc_value() {
-        write!(w, "<div class='docblock'>{}</div>", Markdown(s))?;
-    }
+    document_stability(w, cx, item)?;
+    document_full(w, item)?;
     Ok(())
 }
 
@@ -1671,6 +1674,20 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
     Ok(())
 }
 
+fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
+    if let Some(s) = item.doc_value() {
+        write!(w, "<div class='docblock'>{}</div>", Markdown(s))?;
+    }
+    Ok(())
+}
+
+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)?;
+    }
+    Ok(())
+}
+
 fn item_module(w: &mut fmt::Formatter, cx: &Context,
                item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
     document(w, cx, item)?;
@@ -1812,13 +1829,16 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
                        docs = shorter(Some(&Markdown(doc_value).to_string())),
                        class = shortty(myitem),
                        stab = myitem.stability_class(),
-                       href = item_path(myitem),
+                       href = item_path(shortty(myitem), myitem.name.as_ref().unwrap()),
                        title = full_path(cx, myitem))?;
             }
         }
     }
 
-    write!(w, "</table>")
+    if curty.is_some() {
+        write!(w, "</table>")?;
+    }
+    Ok(())
 }
 
 fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<String> {
@@ -2253,8 +2273,8 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         if fields.peek().is_some() {
             write!(w, "<h2 class='fields'>Fields</h2>")?;
             for (field, ty) in fields {
-                write!(w, "<span id='{shortty}.{name}'><code>{name}: {ty}</code></span>
-                           <span class='stab {stab}'></span>",
+                write!(w, "<span id='{shortty}.{name}' class='{shortty}'><code>{name}: {ty}</code>
+                           </span><span class='stab {stab}'></span>",
                        shortty = ItemType::StructField,
                        stab = field.stability_class(),
                        name = field.name.as_ref().unwrap(),
@@ -2628,20 +2648,23 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
 
         if !is_static || render_static {
             if !is_default_item {
-
-                if item.doc_value().is_some() {
-                    document(w, cx, item)?;
-                } else {
-                    // In case the item isn't documented,
-                    // provide short documentation from the trait
-                    if let Some(t) = trait_ {
-                        if let Some(it) = t.items.iter()
-                                           .find(|i| i.name == item.name) {
-                            document_short(w, it, link)?;
-                        }
+                if let Some(t) = trait_ {
+                    let it = t.items.iter().find(|i| i.name == item.name).unwrap();
+                    // We need the stability of the item from the trait because
+                    // impls can't have a stability.
+                    document_stability(w, cx, it)?;
+                    if item.doc_value().is_some() {
+                        document_full(w, item)?;
+                    } else {
+                        // In case the item isn't documented,
+                        // provide short documentation from the trait.
+                        document_short(w, it, link)?;
                     }
+                } else {
+                    document(w, cx, item)?;
                 }
             } else {
+                document_stability(w, cx, item)?;
                 document_short(w, item, link)?;
             }
         }
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 45dacb68e91..6d2b315502e 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -554,7 +554,7 @@ td.summary-column {
 pre.rust .kw { color: #8959A8; }
 pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
 pre.rust .number, pre.rust .string { color: #718C00; }
-pre.rust .self, pre.rust .boolval, pre.rust .prelude-val,
+pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
 pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
 pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
 pre.rust .lifetime { color: #B76514; }
@@ -659,6 +659,10 @@ span.since {
     margin-bottom: 25px;
 }
 
+.variant, .structfield {
+    display: block;
+}
+
 :target > code {
    background: #FDFFD3;
 }
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index f0ca89097f7..c17af55ca10 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -176,7 +176,7 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions {
 fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
            externs: core::Externs,
            should_panic: bool, no_run: bool, as_test_harness: bool,
-           compile_fail: bool, opts: &TestOptions) {
+           compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions) {
     // the test harness wants its own `main` & top level functions, so
     // never wrap the test in `fn main() { ... }`
     let test = maketest(test, Some(cratename), as_test_harness, opts);
@@ -232,7 +232,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
                                                       None,
                                                       codemap.clone());
     let old = io::set_panic(box Sink(data.clone()));
-    let _bomb = Bomb(data, old.unwrap_or(box io::stdout()));
+    let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
 
     // Compile the code
     let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
@@ -273,13 +273,28 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
                     } else if count == 0 && compile_fail == true {
                         panic!("test compiled while it wasn't supposed to")
                     }
+                    if count > 0 && error_codes.len() > 0 {
+                        let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
+                        error_codes.retain(|err| !out.contains(err));
+                    }
                 }
                 Ok(()) if compile_fail => panic!("test compiled while it wasn't supposed to"),
                 _ => {}
             }
         }
-        Err(_) if compile_fail == false => panic!("couldn't compile the test"),
-        _ => {}
+        Err(_) => {
+            if compile_fail == false {
+                panic!("couldn't compile the test");
+            }
+            if error_codes.len() > 0 {
+                let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
+                error_codes.retain(|err| !out.contains(err));
+            }
+        }
+    }
+
+    if error_codes.len() > 0 {
+        panic!("Some expected error codes were not found: {:?}", error_codes);
     }
 
     if no_run { return }
@@ -411,7 +426,7 @@ impl Collector {
 
     pub fn add_test(&mut self, test: String,
                     should_panic: bool, no_run: bool, should_ignore: bool,
-                    as_test_harness: bool, compile_fail: bool) {
+                    as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>) {
         let name = if self.use_headers {
             let s = self.current_header.as_ref().map(|s| &**s).unwrap_or("");
             format!("{}_{}", s, self.cnt)
@@ -442,6 +457,7 @@ impl Collector {
                         no_run,
                         as_test_harness,
                         compile_fail,
+                        error_codes,
                         &opts);
             })
         });
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index d5309d74334..b0b55a76e26 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -241,20 +241,22 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             Some(tcx) => tcx,
             None => return false
         };
-        let def = tcx.def_map.borrow()[&id];
+        let def = tcx.expect_def(id);
         let def_did = def.def_id();
 
         let use_attrs = tcx.map.attrs(id).clean(self.cx);
-        let is_no_inline = use_attrs.list("doc").has_word("no_inline");
+        // Don't inline doc(hidden) imports so they can be stripped at a later stage.
+        let is_no_inline = use_attrs.list("doc").has_word("no_inline") ||
+                           use_attrs.list("doc").has_word("hidden");
 
         // For cross-crate impl inlining we need to know whether items are
         // reachable in documentation - a previously nonreachable item can be
         // made reachable by cross-crate inlining which we're checking here.
         // (this is done here because we need to know this upfront)
-        if !def.def_id().is_local() && !is_no_inline {
+        if !def_did.is_local() && !is_no_inline {
             let attrs = clean::inline::load_attrs(self.cx, tcx, def_did);
             let self_is_hidden = attrs.list("doc").has_word("hidden");
-            match def.base_def {
+            match def {
                 Def::Trait(did) |
                 Def::Struct(did) |
                 Def::Enum(did) |
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index ff9dacbb679..9c408366f8b 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -80,7 +80,8 @@ fn build_libbacktrace(host: &str, target: &str) {
     }
 
     let compiler = gcc::Config::new().get_compiler();
-    let ar = build_helper::cc2ar(compiler.path(), target);
+    // only msvc returns None for ar so unwrap is okay
+    let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
     let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                          .collect::<Vec<_>>().join(" ");
     run(Command::new("sh")
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 37045822d47..536f168e401 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -1552,6 +1552,12 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
         self.elem.read().0
     }
 
+    /// Take the ownership of the key and value from the map.
+    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    pub fn remove_pair(self) -> (K, V) {
+        pop_internal(self.elem)
+    }
+
     /// Gets a reference to the value in the entry.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get(&self) -> &V {
@@ -1584,6 +1590,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
     pub fn remove(self) -> V {
         pop_internal(self.elem).1
     }
+
     /// Returns a key that was used for search.
     ///
     /// The key was retained for further use.
@@ -1600,6 +1607,12 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
         &self.key
     }
 
+    /// Take ownership of the key.
+    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    pub fn into_key(self) -> K {
+        self.key
+    }
+
     /// Sets the value of the entry with the VacantEntry's key,
     /// and returns a mutable reference to it
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index cf64e5d3336..c4c4cb45313 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::heap::{allocate, deallocate, EMPTY};
+use alloc::heap::{EMPTY, allocate, deallocate};
 
 use cmp;
-use hash::{Hash, Hasher, BuildHasher};
+use hash::{BuildHasher, Hash, Hasher};
 use intrinsics::needs_drop;
 use marker;
 use mem::{align_of, size_of};
@@ -62,12 +62,12 @@ const EMPTY_BUCKET: u64 = 0;
 #[unsafe_no_drop_flag]
 pub struct RawTable<K, V> {
     capacity: usize,
-    size:     usize,
-    hashes:   Unique<u64>,
+    size: usize,
+    hashes: Unique<u64>,
 
     // Because K/V do not appear directly in any of the types in the struct,
     // inform rustc that in fact instances of K and V are reachable from here.
-    marker:   marker::PhantomData<(K,V)>,
+    marker: marker::PhantomData<(K, V)>,
 }
 
 unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
@@ -77,44 +77,48 @@ struct RawBucket<K, V> {
     hash: *mut u64,
 
     // We use *const to ensure covariance with respect to K and V
-    key:  *const K,
-    val:  *const V,
-    _marker: marker::PhantomData<(K,V)>,
+    key: *const K,
+    val: *const V,
+    _marker: marker::PhantomData<(K, V)>,
 }
 
-impl<K,V> Copy for RawBucket<K,V> {}
-impl<K,V> Clone for RawBucket<K,V> {
-    fn clone(&self) -> RawBucket<K, V> { *self }
+impl<K, V> Copy for RawBucket<K, V> {}
+impl<K, V> Clone for RawBucket<K, V> {
+    fn clone(&self) -> RawBucket<K, V> {
+        *self
+    }
 }
 
 pub struct Bucket<K, V, M> {
-    raw:   RawBucket<K, V>,
-    idx:   usize,
-    table: M
+    raw: RawBucket<K, V>,
+    idx: usize,
+    table: M,
 }
 
-impl<K,V,M:Copy> Copy for Bucket<K,V,M> {}
-impl<K,V,M:Copy> Clone for Bucket<K,V,M> {
-    fn clone(&self) -> Bucket<K,V,M> { *self }
+impl<K, V, M: Copy> Copy for Bucket<K, V, M> {}
+impl<K, V, M: Copy> Clone for Bucket<K, V, M> {
+    fn clone(&self) -> Bucket<K, V, M> {
+        *self
+    }
 }
 
 pub struct EmptyBucket<K, V, M> {
-    raw:   RawBucket<K, V>,
-    idx:   usize,
-    table: M
+    raw: RawBucket<K, V>,
+    idx: usize,
+    table: M,
 }
 
 pub struct FullBucket<K, V, M> {
-    raw:   RawBucket<K, V>,
-    idx:   usize,
-    table: M
+    raw: RawBucket<K, V>,
+    idx: usize,
+    table: M,
 }
 
 pub type EmptyBucketImm<'table, K, V> = EmptyBucket<K, V, &'table RawTable<K, V>>;
-pub type  FullBucketImm<'table, K, V> =  FullBucket<K, V, &'table RawTable<K, V>>;
+pub type FullBucketImm<'table, K, V> = FullBucket<K, V, &'table RawTable<K, V>>;
 
 pub type EmptyBucketMut<'table, K, V> = EmptyBucket<K, V, &'table mut RawTable<K, V>>;
-pub type  FullBucketMut<'table, K, V> =  FullBucket<K, V, &'table mut RawTable<K, V>>;
+pub type FullBucketMut<'table, K, V> = FullBucket<K, V, &'table mut RawTable<K, V>>;
 
 pub enum BucketState<K, V, M> {
     Empty(EmptyBucket<K, V, M>),
@@ -139,14 +143,17 @@ pub struct SafeHash {
 impl SafeHash {
     /// Peek at the hash value, which is guaranteed to be non-zero.
     #[inline(always)]
-    pub fn inspect(&self) -> u64 { self.hash }
+    pub fn inspect(&self) -> u64 {
+        self.hash
+    }
 }
 
 /// We need to remove hashes of 0. That's reserved for empty buckets.
 /// This function wraps up `hash_keyed` to be the only way outside this
 /// module to generate a SafeHash.
 pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash
-    where T: Hash, S: BuildHasher
+    where T: Hash,
+          S: BuildHasher
 {
     let mut state = hash_state.build_hasher();
     t.hash(&mut state);
@@ -175,8 +182,8 @@ impl<K, V> RawBucket<K, V> {
     unsafe fn offset(self, count: isize) -> RawBucket<K, V> {
         RawBucket {
             hash: self.hash.offset(count),
-            key:  self.key.offset(count),
-            val:  self.val.offset(count),
+            key: self.key.offset(count),
+            val: self.val.offset(count),
             _marker: marker::PhantomData,
         }
     }
@@ -212,7 +219,9 @@ impl<K, V, M> Bucket<K, V, M> {
     }
 }
 
-impl<K, V, M> Deref for FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> {
+impl<K, V, M> Deref for FullBucket<K, V, M>
+    where M: Deref<Target = RawTable<K, V>>
+{
     type Target = RawTable<K, V>;
     fn deref(&self) -> &RawTable<K, V> {
         &self.table
@@ -232,19 +241,23 @@ impl<'t, K, V> Put<K, V> for &'t mut RawTable<K, V> {
     }
 }
 
-impl<K, V, M> Put<K, V> for Bucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> Put<K, V> for Bucket<K, V, M>
+    where M: Put<K, V>
+{
     unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V> {
         self.table.borrow_table_mut()
     }
 }
 
-impl<K, V, M> Put<K, V> for FullBucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> Put<K, V> for FullBucket<K, V, M>
+    where M: Put<K, V>
+{
     unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V> {
         self.table.borrow_table_mut()
     }
 }
 
-impl<K, V, M: Deref<Target=RawTable<K, V>>> Bucket<K, V, M> {
+impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
     pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> {
         Bucket::at_index(table, hash.inspect() as usize)
     }
@@ -252,14 +265,13 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> Bucket<K, V, M> {
     pub fn at_index(table: M, ib_index: usize) -> Bucket<K, V, M> {
         // if capacity is 0, then the RawBucket will be populated with bogus pointers.
         // This is an uncommon case though, so avoid it in release builds.
-        debug_assert!(table.capacity() > 0, "Table should have capacity at this point");
+        debug_assert!(table.capacity() > 0,
+                      "Table should have capacity at this point");
         let ib_index = ib_index & (table.capacity() - 1);
         Bucket {
-            raw: unsafe {
-               table.first_bucket_raw().offset(ib_index as isize)
-            },
+            raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) },
             idx: ib_index,
-            table: table
+            table: table,
         }
     }
 
@@ -267,7 +279,7 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> Bucket<K, V, M> {
         Bucket {
             raw: table.first_bucket_raw(),
             idx: 0,
-            table: table
+            table: table,
         }
     }
 
@@ -277,18 +289,20 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> Bucket<K, V, M> {
     /// this module.
     pub fn peek(self) -> BucketState<K, V, M> {
         match unsafe { *self.raw.hash } {
-            EMPTY_BUCKET =>
+            EMPTY_BUCKET => {
                 Empty(EmptyBucket {
                     raw: self.raw,
                     idx: self.idx,
-                    table: self.table
-                }),
-            _ =>
+                    table: self.table,
+                })
+            }
+            _ => {
                 Full(FullBucket {
                     raw: self.raw,
                     idx: self.idx,
-                    table: self.table
+                    table: self.table,
                 })
+            }
         }
     }
 
@@ -308,7 +322,7 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> Bucket<K, V, M> {
     }
 }
 
-impl<K, V, M: Deref<Target=RawTable<K, V>>> EmptyBucket<K, V, M> {
+impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
     #[inline]
     pub fn next(self) -> Bucket<K, V, M> {
         let mut bucket = self.into_bucket();
@@ -321,7 +335,7 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> EmptyBucket<K, V, M> {
         Bucket {
             raw: self.raw,
             idx: self.idx,
-            table: self.table
+            table: self.table,
         }
     }
 
@@ -329,22 +343,24 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> EmptyBucket<K, V, M> {
         let gap = EmptyBucket {
             raw: self.raw,
             idx: self.idx,
-            table: ()
+            table: (),
         };
 
         match self.next().peek() {
             Full(bucket) => {
                 Some(GapThenFull {
                     gap: gap,
-                    full: bucket
+                    full: bucket,
                 })
             }
-            Empty(..) => None
+            Empty(..) => None,
         }
     }
 }
 
-impl<K, V, M> EmptyBucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> EmptyBucket<K, V, M>
+    where M: Put<K, V>
+{
     /// Puts given key and value pair, along with the key's hash,
     /// into this bucket in the hashtable. Note how `self` is 'moved' into
     /// this function, because this slot will no longer be empty when
@@ -352,8 +368,7 @@ impl<K, V, M> EmptyBucket<K, V, M> where M: Put<K, V> {
     /// the newly-filled slot in the hashtable.
     ///
     /// Use `make_hash` to construct a `SafeHash` to pass to this function.
-    pub fn put(mut self, hash: SafeHash, key: K, value: V)
-               -> FullBucket<K, V, M> {
+    pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
         unsafe {
             *self.raw.hash = hash.inspect();
             ptr::write(self.raw.key as *mut K, key);
@@ -362,11 +377,15 @@ impl<K, V, M> EmptyBucket<K, V, M> where M: Put<K, V> {
             self.table.borrow_table_mut().size += 1;
         }
 
-        FullBucket { raw: self.raw, idx: self.idx, table: self.table }
+        FullBucket {
+            raw: self.raw,
+            idx: self.idx,
+            table: self.table,
+        }
     }
 }
 
-impl<K, V, M: Deref<Target=RawTable<K, V>>> FullBucket<K, V, M> {
+impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
     #[inline]
     pub fn next(self) -> Bucket<K, V, M> {
         let mut bucket = self.into_bucket();
@@ -379,7 +398,7 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> FullBucket<K, V, M> {
         Bucket {
             raw: self.raw,
             idx: self.idx,
-            table: self.table
+            table: self.table,
         }
     }
 
@@ -407,19 +426,12 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> FullBucket<K, V, M> {
 
     #[inline]
     pub fn hash(&self) -> SafeHash {
-        unsafe {
-            SafeHash {
-                hash: *self.raw.hash
-            }
-        }
+        unsafe { SafeHash { hash: *self.raw.hash } }
     }
 
     /// Gets references to the key and value at a given index.
     pub fn read(&self) -> (&K, &V) {
-        unsafe {
-            (&*self.raw.key,
-             &*self.raw.val)
-        }
+        unsafe { (&*self.raw.key, &*self.raw.val) }
     }
 }
 
@@ -436,69 +448,68 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
 
         unsafe {
             *self.raw.hash = EMPTY_BUCKET;
-            (
-                EmptyBucket {
-                    raw: self.raw,
-                    idx: self.idx,
-                    table: self.table
-                },
-                ptr::read(self.raw.key),
-                ptr::read(self.raw.val)
-            )
+            (EmptyBucket {
+                raw: self.raw,
+                idx: self.idx,
+                table: self.table,
+            },
+             ptr::read(self.raw.key),
+             ptr::read(self.raw.val))
         }
     }
 }
 
 // This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases
 // where `M` is a full bucket or table reference type with mutable access to the table.
-impl<K, V, M> FullBucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> FullBucket<K, V, M>
+    where M: Put<K, V>
+{
     pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
         unsafe {
             let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
-            let old_key  = ptr::replace(self.raw.key as *mut K,  k);
-            let old_val  = ptr::replace(self.raw.val as *mut V,  v);
+            let old_key = ptr::replace(self.raw.key as *mut K, k);
+            let old_val = ptr::replace(self.raw.val as *mut V, v);
 
             (old_hash, old_key, old_val)
         }
     }
 }
 
-impl<K, V, M> FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + DerefMut {
+impl<K, V, M> FullBucket<K, V, M>
+    where M: Deref<Target = RawTable<K, V>> + DerefMut
+{
     /// Gets mutable references to the key and value at a given index.
     pub fn read_mut(&mut self) -> (&mut K, &mut V) {
-        unsafe {
-            (&mut *(self.raw.key as *mut K),
-             &mut *(self.raw.val as *mut V))
-        }
+        unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
     }
 }
 
-impl<'t, K, V, M> FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + 't {
+impl<'t, K, V, M> FullBucket<K, V, M>
+    where M: Deref<Target = RawTable<K, V>> + 't
+{
     /// Exchange a bucket state for immutable references into the table.
     /// Because the underlying reference to the table is also consumed,
     /// no further changes to the structure of the table are possible;
     /// in exchange for this, the returned references have a longer lifetime
     /// than the references returned by `read()`.
     pub fn into_refs(self) -> (&'t K, &'t V) {
-        unsafe {
-            (&*self.raw.key,
-             &*self.raw.val)
-        }
+        unsafe { (&*self.raw.key, &*self.raw.val) }
     }
 }
 
-impl<'t, K, V, M> FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + DerefMut + 't {
+impl<'t, K, V, M> FullBucket<K, V, M>
+    where M: Deref<Target = RawTable<K, V>> + DerefMut + 't
+{
     /// This works similarly to `into_refs`, exchanging a bucket state
     /// for mutable references into the table.
     pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
-        unsafe {
-            (&mut *(self.raw.key as *mut K),
-             &mut *(self.raw.val as *mut V))
-        }
+        unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
     }
 }
 
-impl<K, V, M> GapThenFull<K, V, M> where M: Deref<Target=RawTable<K, V>> {
+impl<K, V, M> GapThenFull<K, V, M>
+    where M: Deref<Target = RawTable<K, V>>
+{
     #[inline]
     pub fn full(&self) -> &FullBucket<K, V, M> {
         &self.full
@@ -522,7 +533,7 @@ impl<K, V, M> GapThenFull<K, V, M> where M: Deref<Target=RawTable<K, V>> {
 
                 Some(self)
             }
-            Empty(..) => None
+            Empty(..) => None,
         }
     }
 }
@@ -554,7 +565,8 @@ fn test_rounding() {
 // from the start of a mallocated array.
 #[inline]
 fn calculate_offsets(hashes_size: usize,
-                     keys_size: usize, keys_align: usize,
+                     keys_size: usize,
+                     keys_align: usize,
                      vals_align: usize)
                      -> (usize, usize, bool) {
     let keys_offset = round_up_to_next(hashes_size, keys_align);
@@ -567,14 +579,15 @@ fn calculate_offsets(hashes_size: usize,
 
 // Returns a tuple of (minimum required malloc alignment, hash_offset,
 // array_size), from the start of a mallocated array.
-fn calculate_allocation(hash_size: usize, hash_align: usize,
-                        keys_size: usize, keys_align: usize,
-                        vals_size: usize, vals_align: usize)
+fn calculate_allocation(hash_size: usize,
+                        hash_align: usize,
+                        keys_size: usize,
+                        keys_align: usize,
+                        vals_size: usize,
+                        vals_align: usize)
                         -> (usize, usize, usize, bool) {
     let hash_offset = 0;
-    let (_, vals_offset, oflo) = calculate_offsets(hash_size,
-                                                   keys_size, keys_align,
-                                                              vals_align);
+    let (_, vals_offset, oflo) = calculate_offsets(hash_size, keys_size, keys_align, vals_align);
     let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size);
 
     let align = cmp::max(hash_align, cmp::max(keys_align, vals_align));
@@ -584,12 +597,13 @@ fn calculate_allocation(hash_size: usize, hash_align: usize,
 
 #[test]
 fn test_offset_calculation() {
-    assert_eq!(calculate_allocation(128, 8, 15, 1, 4,  4), (8, 0, 148, false));
-    assert_eq!(calculate_allocation(3,   1, 2,  1, 1,  1), (1, 0, 6, false));
-    assert_eq!(calculate_allocation(6,   2, 12, 4, 24, 8), (8, 0, 48, false));
+    assert_eq!(calculate_allocation(128, 8, 15, 1, 4, 4),
+               (8, 0, 148, false));
+    assert_eq!(calculate_allocation(3, 1, 2, 1, 1, 1), (1, 0, 6, false));
+    assert_eq!(calculate_allocation(6, 2, 12, 4, 24, 8), (8, 0, 48, false));
     assert_eq!(calculate_offsets(128, 15, 1, 4), (128, 144, false));
-    assert_eq!(calculate_offsets(3,   2,  1, 1), (3,   5, false));
-    assert_eq!(calculate_offsets(6,   12, 4, 8), (8,   24, false));
+    assert_eq!(calculate_offsets(3, 2, 1, 1), (3, 5, false));
+    assert_eq!(calculate_offsets(6, 12, 4, 8), (8, 24, false));
 }
 
 impl<K, V> RawTable<K, V> {
@@ -608,8 +622,8 @@ impl<K, V> RawTable<K, V> {
         // No need for `checked_mul` before a more restrictive check performed
         // later in this method.
         let hashes_size = capacity * size_of::<u64>();
-        let keys_size   = capacity * size_of::< K >();
-        let vals_size   = capacity * size_of::< V >();
+        let keys_size = capacity * size_of::<K>();
+        let vals_size = capacity * size_of::<V>();
 
         // Allocating hashmaps is a little tricky. We need to allocate three
         // arrays, but since we know their sizes and alignments up front,
@@ -619,31 +633,38 @@ impl<K, V> RawTable<K, V> {
         // This is great in theory, but in practice getting the alignment
         // right is a little subtle. Therefore, calculating offsets has been
         // factored out into a different function.
-        let (malloc_alignment, hash_offset, size, oflo) =
-            calculate_allocation(
-                hashes_size, align_of::<u64>(),
-                keys_size,   align_of::< K >(),
-                vals_size,   align_of::< V >());
+        let (malloc_alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
+                                                                               align_of::<u64>(),
+                                                                               keys_size,
+                                                                               align_of::<K>(),
+                                                                               vals_size,
+                                                                               align_of::<V>());
 
         assert!(!oflo, "capacity overflow");
 
         // One check for overflow that covers calculation and rounding of size.
-        let size_of_bucket = size_of::<u64>().checked_add(size_of::<K>()).unwrap()
-                                             .checked_add(size_of::<V>()).unwrap();
-        assert!(size >= capacity.checked_mul(size_of_bucket)
-                                .expect("capacity overflow"),
+        let size_of_bucket = size_of::<u64>()
+                                 .checked_add(size_of::<K>())
+                                 .unwrap()
+                                 .checked_add(size_of::<V>())
+                                 .unwrap();
+        assert!(size >=
+                capacity.checked_mul(size_of_bucket)
+                        .expect("capacity overflow"),
                 "capacity overflow");
 
         let buffer = allocate(size, malloc_alignment);
-        if buffer.is_null() { ::alloc::oom() }
+        if buffer.is_null() {
+            ::alloc::oom()
+        }
 
         let hashes = buffer.offset(hash_offset as isize) as *mut u64;
 
         RawTable {
             capacity: capacity,
-            size:     0,
-            hashes:   Unique::new(hashes),
-            marker:   marker::PhantomData,
+            size: 0,
+            hashes: Unique::new(hashes),
+            marker: marker::PhantomData,
         }
     }
 
@@ -652,16 +673,16 @@ impl<K, V> RawTable<K, V> {
         let keys_size = self.capacity * size_of::<K>();
 
         let buffer = *self.hashes as *const u8;
-        let (keys_offset, vals_offset, oflo) =
-            calculate_offsets(hashes_size,
-                              keys_size, align_of::<K>(),
-                              align_of::<V>());
+        let (keys_offset, vals_offset, oflo) = calculate_offsets(hashes_size,
+                                                                 keys_size,
+                                                                 align_of::<K>(),
+                                                                 align_of::<V>());
         debug_assert!(!oflo, "capacity overflow");
         unsafe {
             RawBucket {
                 hash: *self.hashes,
-                key:  buffer.offset(keys_offset as isize) as *const K,
-                val:  buffer.offset(vals_offset as isize) as *const V,
+                key: buffer.offset(keys_offset as isize) as *const K,
+                val: buffer.offset(vals_offset as isize) as *const V,
                 _marker: marker::PhantomData,
             }
         }
@@ -691,9 +712,7 @@ impl<K, V> RawTable<K, V> {
     fn raw_buckets(&self) -> RawBuckets<K, V> {
         RawBuckets {
             raw: self.first_bucket_raw(),
-            hashes_end: unsafe {
-                self.hashes.offset(self.capacity as isize)
-            },
+            hashes_end: unsafe { self.hashes.offset(self.capacity as isize) },
             marker: marker::PhantomData,
         }
     }
@@ -747,7 +766,7 @@ impl<K, V> RawTable<K, V> {
             raw: raw_bucket.offset(self.capacity as isize),
             hashes_end: raw_bucket.hash,
             elems_left: self.size,
-            marker:     marker::PhantomData,
+            marker: marker::PhantomData,
         }
     }
 }
@@ -827,10 +846,7 @@ impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> {
 
                 if *self.raw.hash != EMPTY_BUCKET {
                     self.elems_left -= 1;
-                    return Some((
-                        ptr::read(self.raw.key),
-                        ptr::read(self.raw.val)
-                    ));
+                    return Some((ptr::read(self.raw.key), ptr::read(self.raw.val)));
                 }
             }
         }
@@ -851,7 +867,7 @@ impl<'a, K, V> Clone for Iter<'a, K, V> {
     fn clone(&self) -> Iter<'a, K, V> {
         Iter {
             iter: self.iter.clone(),
-            elems_left: self.elems_left
+            elems_left: self.elems_left,
         }
     }
 }
@@ -873,7 +889,7 @@ unsafe impl<'a, K: Send, V: Send> Send for IterMut<'a, K, V> {}
 /// Iterator over the entries in a table, consuming the table.
 pub struct IntoIter<K, V> {
     table: RawTable<K, V>,
-    iter: RawBuckets<'static, K, V>
+    iter: RawBuckets<'static, K, V>,
 }
 
 unsafe impl<K: Sync, V: Sync> Sync for IntoIter<K, V> {}
@@ -894,10 +910,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> {
     fn next(&mut self) -> Option<(&'a K, &'a V)> {
         self.iter.next().map(|bucket| {
             self.elems_left -= 1;
-            unsafe {
-                (&*bucket.key,
-                 &*bucket.val)
-            }
+            unsafe { (&*bucket.key, &*bucket.val) }
         })
     }
 
@@ -906,7 +919,9 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> {
     }
 }
 impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
-    fn len(&self) -> usize { self.elems_left }
+    fn len(&self) -> usize {
+        self.elems_left
+    }
 }
 
 impl<'a, K, V> Iterator for IterMut<'a, K, V> {
@@ -915,10 +930,7 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
     fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
         self.iter.next().map(|bucket| {
             self.elems_left -= 1;
-            unsafe {
-                (&*bucket.key,
-                 &mut *(bucket.val as *mut V))
-            }
+            unsafe { (&*bucket.key, &mut *(bucket.val as *mut V)) }
         })
     }
 
@@ -927,7 +939,9 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
     }
 }
 impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
-    fn len(&self) -> usize { self.elems_left }
+    fn len(&self) -> usize {
+        self.elems_left
+    }
 }
 
 impl<K, V> Iterator for IntoIter<K, V> {
@@ -937,13 +951,7 @@ impl<K, V> Iterator for IntoIter<K, V> {
         self.iter.next().map(|bucket| {
             self.table.size -= 1;
             unsafe {
-                (
-                    SafeHash {
-                        hash: *bucket.hash,
-                    },
-                    ptr::read(bucket.key),
-                    ptr::read(bucket.val)
-                )
+                (SafeHash { hash: *bucket.hash }, ptr::read(bucket.key), ptr::read(bucket.val))
             }
         })
     }
@@ -954,7 +962,9 @@ impl<K, V> Iterator for IntoIter<K, V> {
     }
 }
 impl<K, V> ExactSizeIterator for IntoIter<K, V> {
-    fn len(&self) -> usize { self.table.size() }
+    fn len(&self) -> usize {
+        self.table.size()
+    }
 }
 
 impl<'a, K, V> Iterator for Drain<'a, K, V> {
@@ -965,13 +975,9 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
         self.iter.next().map(|bucket| {
             self.table.size -= 1;
             unsafe {
-                (
-                    SafeHash {
-                        hash: ptr::replace(bucket.hash, EMPTY_BUCKET),
-                    },
-                    ptr::read(bucket.key),
-                    ptr::read(bucket.val)
-                )
+                (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) },
+                 ptr::read(bucket.key),
+                 ptr::read(bucket.val))
             }
         })
     }
@@ -982,7 +988,9 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
     }
 }
 impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
-    fn len(&self) -> usize { self.table.size() }
+    fn len(&self) -> usize {
+        self.table.size()
+    }
 }
 
 impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
@@ -1040,7 +1048,8 @@ impl<K, V> Drop for RawTable<K, V> {
         // dropping empty tables such as on resize.
         // Also avoid double drop of elements that have been already moved out.
         unsafe {
-            if needs_drop::<(K, V)>() { // avoid linear runtime for types that don't need drop
+            if needs_drop::<(K, V)>() {
+                // avoid linear runtime for types that don't need drop
                 for _ in self.rev_move_buckets() {}
             }
         }
@@ -1048,10 +1057,12 @@ impl<K, V> Drop for RawTable<K, V> {
         let hashes_size = self.capacity * size_of::<u64>();
         let keys_size = self.capacity * size_of::<K>();
         let vals_size = self.capacity * size_of::<V>();
-        let (align, _, size, oflo) =
-            calculate_allocation(hashes_size, align_of::<u64>(),
-                                 keys_size, align_of::<K>(),
-                                 vals_size, align_of::<V>());
+        let (align, _, size, oflo) = calculate_allocation(hashes_size,
+                                                          align_of::<u64>(),
+                                                          keys_size,
+                                                          align_of::<K>(),
+                                                          vals_size,
+                                                          align_of::<V>());
 
         debug_assert!(!oflo, "should be impossible");
 
diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs
index 44613d77671..9b13d542300 100644
--- a/src/libstd/collections/mod.rs
+++ b/src/libstd/collections/mod.rs
@@ -429,14 +429,16 @@ mod hash;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod hash_map {
-    //! A hashmap
+    //! A hash map implementation which uses linear probing with Robin
+    //! Hood bucket stealing.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::hash::map::*;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod hash_set {
-    //! A hashset
+    //! An implementation of a hash set using the underlying representation of a
+    //! HashMap where the value is ().
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::hash::set::*;
 }
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 0180c3118a5..668fa1fb303 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -512,7 +512,7 @@ impl OpenOptions {
     /// No file is allowed to exist at the target location, also no (dangling)
     /// symlink.
     ///
-    /// This option is useful because it as atomic. Otherwise between checking
+    /// This option is useful because it is atomic. Otherwise between checking
     /// whether a file exists and creating a new one, the file may have been
     /// created by another process (a TOCTOU race condition / attack).
     ///
@@ -1771,6 +1771,15 @@ mod tests {
     }
 
     #[test]
+    fn file_create_new_already_exists_error() {
+        let tmpdir = tmpdir();
+        let file = &tmpdir.join("file_create_new_error_exists");
+        check!(fs::File::create(file));
+        let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err();
+        assert_eq!(e.kind(), ErrorKind::AlreadyExists);
+    }
+
+    #[test]
     fn mkdir_path_already_exists_error() {
         let tmpdir = tmpdir();
         let dir = &tmpdir.join("mkdir_error_twice");
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 7114d47e6e8..135ea8a5e7c 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -467,3 +467,15 @@ pub mod __rand {
 // the rustdoc documentation for primitive types. Using `include!`
 // because rustdoc only looks for these modules at the crate level.
 include!("primitive_docs.rs");
+
+// FIXME(stage0): remove this after a snapshot
+// HACK: this is needed because the interpretation of slice
+// patterns changed between stage0 and now.
+#[cfg(stage0)]
+fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] {
+    t
+}
+#[cfg(not(stage0))]
+fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] {
+    *t
+}
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index ba485f819f8..57d75441bff 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -82,14 +82,15 @@ impl Ipv4Addr {
         [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
     }
 
-    /// Returns true for the special 'unspecified' address 0.0.0.0.
+    /// Returns true for the special 'unspecified' address (0.0.0.0).
     pub fn is_unspecified(&self) -> bool {
         self.inner.s_addr == 0
     }
 
     /// Returns true if this is a loopback address (127.0.0.0/8).
     ///
-    /// This property is defined by RFC 6890.
+    /// This property is defined by [RFC 1122].
+    /// [RFC 1122]: https://tools.ietf.org/html/rfc1122
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub fn is_loopback(&self) -> bool {
         self.octets()[0] == 127
@@ -97,7 +98,8 @@ impl Ipv4Addr {
 
     /// Returns true if this is a private address.
     ///
-    /// The private address ranges are defined in RFC 1918 and include:
+    /// The private address ranges are defined in [RFC 1918] and include:
+    /// [RFC 1918]: https://tools.ietf.org/html/rfc1918
     ///
     ///  - 10.0.0.0/8
     ///  - 172.16.0.0/12
@@ -114,7 +116,8 @@ impl Ipv4Addr {
 
     /// Returns true if the address is link-local (169.254.0.0/16).
     ///
-    /// This property is defined by RFC 6890.
+    /// This property is defined by [RFC 3927].
+    /// [RFC 3927]: https://tools.ietf.org/html/rfc3927
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub fn is_link_local(&self) -> bool {
         self.octets()[0] == 169 && self.octets()[1] == 254
@@ -137,18 +140,20 @@ impl Ipv4Addr {
         !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified()
     }
 
-    /// Returns true if this is a multicast address.
+    /// Returns true if this is a multicast address (224.0.0.0/4).
     ///
     /// Multicast addresses have a most significant octet between 224 and 239,
-    /// and is defined by RFC 5771.
+    /// and is defined by [RFC 5771].
+    /// [RFC 5771]: https://tools.ietf.org/html/rfc5771
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub fn is_multicast(&self) -> bool {
         self.octets()[0] >= 224 && self.octets()[0] <= 239
     }
 
-    /// Returns true if this is a broadcast address.
+    /// Returns true if this is a broadcast address (255.255.255.255).
     ///
-    /// A broadcast address has all octets set to 255 as defined in RFC 919.
+    /// A broadcast address has all octets set to 255 as defined in [RFC 919].
+    /// [RFC 919]: https://tools.ietf.org/html/rfc919
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub fn is_broadcast(&self) -> bool {
         self.octets()[0] == 255 && self.octets()[1] == 255 &&
@@ -157,7 +162,8 @@ impl Ipv4Addr {
 
     /// Returns true if this address is in a range designated for documentation.
     ///
-    /// This is defined in RFC 5737:
+    /// This is defined in [RFC 5737]:
+    /// [RFC 5737]: https://tools.ietf.org/html/rfc5737
     ///
     /// - 192.0.2.0/24 (TEST-NET-1)
     /// - 198.51.100.0/24 (TEST-NET-2)
@@ -321,9 +327,10 @@ impl Ipv6Addr {
         ]
     }
 
-    /// Returns true for the special 'unspecified' address ::.
+    /// Returns true for the special 'unspecified' address (::).
     ///
-    /// This property is defined in RFC 6890.
+    /// This property is defined in [RFC 4291].
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub fn is_unspecified(&self) -> bool {
         self.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
@@ -331,7 +338,8 @@ impl Ipv6Addr {
 
     /// Returns true if this is a loopback address (::1).
     ///
-    /// This property is defined in RFC 6890.
+    /// This property is defined in [RFC 4291].
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub fn is_loopback(&self) -> bool {
         self.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
@@ -352,26 +360,33 @@ impl Ipv6Addr {
         }
     }
 
-    /// Returns true if this is a unique local address (IPv6).
+    /// Returns true if this is a unique local address (fc00::/7).
     ///
-    /// Unique local addresses are defined in RFC 4193 and have the form fc00::/7.
+    /// This property is defined in [RFC 4193].
+    /// [RFC 4193]: https://tools.ietf.org/html/rfc4193
     pub fn is_unique_local(&self) -> bool {
         (self.segments()[0] & 0xfe00) == 0xfc00
     }
 
     /// Returns true if the address is unicast and link-local (fe80::/10).
+    ///
+    /// This property is defined in [RFC 4291].
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
     pub fn is_unicast_link_local(&self) -> bool {
         (self.segments()[0] & 0xffc0) == 0xfe80
     }
 
-    /// Returns true if this is a deprecated unicast site-local address (IPv6
-    /// fec0::/10).
+    /// Returns true if this is a deprecated unicast site-local address
+    /// (fec0::/10).
     pub fn is_unicast_site_local(&self) -> bool {
         (self.segments()[0] & 0xffc0) == 0xfec0
     }
 
     /// Returns true if this is an address reserved for documentation
-    /// This is defined to be 2001:db8::/32 in RFC 3849.
+    /// (2001:db8::/32).
+    ///
+    /// This property is defined in [RFC 3849].
+    /// [RFC 3849]: https://tools.ietf.org/html/rfc3849
     pub fn is_documentation(&self) -> bool {
         (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
     }
@@ -411,10 +426,10 @@ impl Ipv6Addr {
         }
     }
 
-    /// Returns true if this is a multicast address.
+    /// Returns true if this is a multicast address (ff00::/8).
     ///
-    /// Multicast addresses have the form ff00::/8, and this property is defined
-    /// by RFC 3956.
+    /// This property is defined by [RFC 4291].
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub fn is_multicast(&self) -> bool {
         (self.segments()[0] & 0xff00) == 0xff00
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 3ce9bcc79f2..2edd1a30638 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -182,8 +182,10 @@ impl FromInner<AnonPipe> for ChildStderr {
     }
 }
 
-/// The `Command` type acts as a process builder, providing fine-grained control
-/// over how a new process should be spawned. A default configuration can be
+/// A process builder, providing fine-grained control
+/// over how a new process should be spawned.
+///
+/// A default configuration can be
 /// generated using `Command::new(program)`, where `program` gives a path to the
 /// program to be executed. Additional builder methods allow the configuration
 /// to be changed (for example, by adding arguments) prior to spawning:
@@ -711,16 +713,17 @@ impl Child {
     /// ```should_panic
     /// use std::process::{Command, Stdio};
     ///
-    /// let mut child = Command::new("/bin/cat")
-    ///                         .arg("file.txt")
-    ///                         .stdout(Stdio::piped())
-    ///                         .spawn()
-    ///                         .expect("failed to execute child");
+    /// let child = Command::new("/bin/cat")
+    ///     .arg("file.txt")
+    ///     .stdout(Stdio::piped())
+    ///     .spawn()
+    ///     .expect("failed to execute child");
     ///
-    /// let ecode = child.wait_with_output()
-    ///                  .expect("failed to wait on child");
+    /// let output = child
+    ///     .wait_with_output()
+    ///     .expect("failed to wait on child");
     ///
-    /// assert!(ecode.status.success());
+    /// assert!(output.status.success());
     /// ```
     ///
     #[stable(feature = "process", since = "1.0.0")]
diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs
index ffd33f8518f..02506e7c2f3 100644
--- a/src/libstd/sync/mpsc/spsc_queue.rs
+++ b/src/libstd/sync/mpsc/spsc_queue.rs
@@ -265,15 +265,18 @@ mod tests {
 
             // Ensure the borrowchecker works
             match queue.peek() {
-                Some(vec) => match &**vec {
-                    // Note that `pop` is not allowed here due to borrow
-                    [1] => {}
-                    _ => return
+                Some(vec) => {
+                    assert_eq!(&*vec, &[1]);
                 },
                 None => unreachable!()
             }
 
-            queue.pop();
+            match queue.pop() {
+                Some(vec) => {
+                    assert_eq!(&*vec, &[1]);
+                },
+                None => unreachable!()
+            }
         }
     }
 
diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs
index 55e485e5811..d705b8986d0 100644
--- a/src/libstd/sys/common/wtf8.rs
+++ b/src/libstd/sys/common/wtf8.rs
@@ -566,8 +566,8 @@ impl Wtf8 {
         if len < 3 {
             return None
         }
-        match &self.bytes[(len - 3)..] {
-            [0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
+        match ::slice_pat(&&self.bytes[(len - 3)..]) {
+            &[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
             _ => None
         }
     }
@@ -578,8 +578,8 @@ impl Wtf8 {
         if len < 3 {
             return None
         }
-        match &self.bytes[..3] {
-            [0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
+        match ::slice_pat(&&self.bytes[..3]) {
+            &[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
             _ => None
         }
     }
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 2acf6485eb3..ce563dc7b16 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -181,6 +181,7 @@ pub const ERROR_ACCESS_DENIED: DWORD = 5;
 pub const ERROR_INVALID_HANDLE: DWORD = 6;
 pub const ERROR_NO_MORE_FILES: DWORD = 18;
 pub const ERROR_HANDLE_EOF: DWORD = 38;
+pub const ERROR_FILE_EXISTS: DWORD = 80;
 pub const ERROR_BROKEN_PIPE: DWORD = 109;
 pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
 pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 3cd45afaf01..c243e890526 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -117,10 +117,10 @@ impl Drop for FindNextFileHandle {
 
 impl DirEntry {
     fn new(root: &Arc<PathBuf>, wfd: &c::WIN32_FIND_DATAW) -> Option<DirEntry> {
-        match &wfd.cFileName[0..3] {
+        match ::slice_pat(&&wfd.cFileName[0..3]) {
             // check for '.' and '..'
-            [46, 0, ..] |
-            [46, 46, 0, ..] => return None,
+            &[46, 0, ..] |
+            &[46, 46, 0, ..] => return None,
             _ => {}
         }
 
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 384940e4dc4..6dd4f4c3e75 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -68,6 +68,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno as c::DWORD {
         c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied,
         c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists,
+        c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists,
         c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe,
         c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index c8783a60c41..c474aa60b3e 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -321,6 +321,35 @@ pub fn yield_now() {
 }
 
 /// Determines whether the current thread is unwinding because of panic.
+///
+/// # Examples
+///
+/// ```rust,should_panic
+/// use std::thread;
+///
+/// struct SomeStruct;
+///
+/// impl Drop for SomeStruct {
+///     fn drop(&mut self) {
+///         if thread::panicking() {
+///             println!("dropped while unwinding");
+///         } else {
+///             println!("dropped while not unwinding");
+///         }
+///     }
+/// }
+///
+/// {
+///     print!("a: ");
+///     let a = SomeStruct;
+/// }
+///
+/// {
+///     print!("b: ");
+///     let b = SomeStruct;
+///     panic!()
+/// }
+/// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn panicking() -> bool {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 40c98206c16..8537fcc221c 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -60,10 +60,6 @@ impl Name {
     pub fn as_str(self) -> token::InternedString {
         token::InternedString::new_from_name(self)
     }
-
-    pub fn unhygienize(self) -> Name {
-        token::intern(&self.as_str())
-    }
 }
 
 impl fmt::Debug for Name {
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index c3c3deea187..e36e15802f0 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -20,12 +20,11 @@ use ast::{Stmt, StmtKind, DeclKind};
 use ast::{Expr, Item, Local, Decl};
 use codemap::{Span, Spanned, spanned, dummy_spanned};
 use codemap::BytePos;
-use config::CfgDiag;
 use errors::Handler;
-use feature_gate::{GatedCfg, GatedCfgAttr};
+use feature_gate::{Features, GatedCfg};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::token::InternedString;
-use parse::token;
+use parse::{ParseSess, token};
 use ptr::P;
 
 use std::cell::{RefCell, Cell};
@@ -365,35 +364,29 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool {
 }
 
 /// Tests if a cfg-pattern matches the cfg set
-pub fn cfg_matches<T: CfgDiag>(cfgs: &[P<MetaItem>],
-                           cfg: &ast::MetaItem,
-                           diag: &mut T) -> bool {
+pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
+                   sess: &ParseSess, features: Option<&Features>)
+                   -> bool {
     match cfg.node {
         ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "any" =>
-            mis.iter().any(|mi| cfg_matches(cfgs, &mi, diag)),
+            mis.iter().any(|mi| cfg_matches(cfgs, &mi, sess, features)),
         ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "all" =>
-            mis.iter().all(|mi| cfg_matches(cfgs, &mi, diag)),
+            mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)),
         ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => {
             if mis.len() != 1 {
-                diag.emit_error(|diagnostic| {
-                    diagnostic.span_err(cfg.span, "expected 1 cfg-pattern");
-                });
+                sess.span_diagnostic.span_err(cfg.span, "expected 1 cfg-pattern");
                 return false;
             }
-            !cfg_matches(cfgs, &mis[0], diag)
+            !cfg_matches(cfgs, &mis[0], sess, features)
         }
         ast::MetaItemKind::List(ref pred, _) => {
-            diag.emit_error(|diagnostic| {
-                diagnostic.span_err(cfg.span,
-                    &format!("invalid predicate `{}`", pred));
-            });
+            sess.span_diagnostic.span_err(cfg.span, &format!("invalid predicate `{}`", pred));
             false
         },
         ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => {
-            diag.flag_gated(|feature_gated_cfgs| {
-                feature_gated_cfgs.extend(
-                    GatedCfg::gate(cfg).map(GatedCfgAttr::GatedCfg));
-            });
+            if let (Some(features), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
+                gated_cfg.check_and_emit(sess, features);
+            }
             contains(cfgs, cfg)
         }
     }
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index d391cd0be7b..5e1335b45aa 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -21,10 +21,11 @@ pub use self::ExpnFormat::*;
 
 use std::cell::{Cell, RefCell};
 use std::ops::{Add, Sub};
-use std::path::Path;
+use std::path::{Path,PathBuf};
 use std::rc::Rc;
 use std::cmp;
 
+use std::env;
 use std::{fmt, fs};
 use std::io::{self, Read};
 
@@ -508,6 +509,8 @@ pub struct FileMap {
     /// originate from files has names between angle brackets by convention,
     /// e.g. `<anon>`
     pub name: FileName,
+    /// The absolute path of the file that the source came from.
+    pub abs_path: Option<FileName>,
     /// The complete source code
     pub src: Option<Rc<String>>,
     /// The start position of this source in the CodeMap
@@ -522,11 +525,12 @@ pub struct FileMap {
 
 impl Encodable for FileMap {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_struct("FileMap", 5, |s| {
+        s.emit_struct("FileMap", 6, |s| {
             s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
-            s.emit_struct_field("start_pos", 1, |s| self.start_pos.encode(s))?;
-            s.emit_struct_field("end_pos", 2, |s| self.end_pos.encode(s))?;
-            s.emit_struct_field("lines", 3, |s| {
+            s.emit_struct_field("abs_path", 1, |s| self.abs_path.encode(s))?;
+            s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?;
+            s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?;
+            s.emit_struct_field("lines", 4, |s| {
                 let lines = self.lines.borrow();
                 // store the length
                 s.emit_u32(lines.len() as u32)?;
@@ -572,7 +576,7 @@ impl Encodable for FileMap {
 
                 Ok(())
             })?;
-            s.emit_struct_field("multibyte_chars", 4, |s| {
+            s.emit_struct_field("multibyte_chars", 5, |s| {
                 (*self.multibyte_chars.borrow()).encode(s)
             })
         })
@@ -582,11 +586,13 @@ impl Encodable for FileMap {
 impl Decodable for FileMap {
     fn decode<D: Decoder>(d: &mut D) -> Result<FileMap, D::Error> {
 
-        d.read_struct("FileMap", 5, |d| {
+        d.read_struct("FileMap", 6, |d| {
             let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
-            let start_pos: BytePos = d.read_struct_field("start_pos", 1, |d| Decodable::decode(d))?;
-            let end_pos: BytePos = d.read_struct_field("end_pos", 2, |d| Decodable::decode(d))?;
-            let lines: Vec<BytePos> = d.read_struct_field("lines", 3, |d| {
+            let abs_path: Option<String> =
+                d.read_struct_field("abs_path", 1, |d| Decodable::decode(d))?;
+            let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
+            let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?;
+            let lines: Vec<BytePos> = d.read_struct_field("lines", 4, |d| {
                 let num_lines: u32 = Decodable::decode(d)?;
                 let mut lines = Vec::with_capacity(num_lines as usize);
 
@@ -615,9 +621,10 @@ impl Decodable for FileMap {
                 Ok(lines)
             })?;
             let multibyte_chars: Vec<MultiByteChar> =
-                d.read_struct_field("multibyte_chars", 4, |d| Decodable::decode(d))?;
+                d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
             Ok(FileMap {
                 name: name,
+                abs_path: abs_path,
                 start_pos: start_pos,
                 end_pos: end_pos,
                 src: None,
@@ -703,6 +710,9 @@ pub trait FileLoader {
     /// Query the existence of a file.
     fn file_exists(&self, path: &Path) -> bool;
 
+    /// Return an absolute path to a file, if possible.
+    fn abs_path(&self, path: &Path) -> Option<PathBuf>;
+
     /// Read the contents of an UTF-8 file into memory.
     fn read_file(&self, path: &Path) -> io::Result<String>;
 }
@@ -715,6 +725,16 @@ impl FileLoader for RealFileLoader {
         fs::metadata(path).is_ok()
     }
 
+    fn abs_path(&self, path: &Path) -> Option<PathBuf> {
+        if path.is_absolute() {
+            Some(path.to_path_buf())
+        } else {
+            env::current_dir()
+                .ok()
+                .map(|cwd| cwd.join(path))
+        }
+    }
+
     fn read_file(&self, path: &Path) -> io::Result<String> {
         let mut src = String::new();
         fs::File::open(path)?.read_to_string(&mut src)?;
@@ -755,7 +775,8 @@ impl CodeMap {
 
     pub fn load_file(&self, path: &Path) -> io::Result<Rc<FileMap>> {
         let src = self.file_loader.read_file(path)?;
-        Ok(self.new_filemap(path.to_str().unwrap().to_string(), src))
+        let abs_path = self.file_loader.abs_path(path).map(|p| p.to_str().unwrap().to_string());
+        Ok(self.new_filemap(path.to_str().unwrap().to_string(), abs_path, src))
     }
 
     fn next_start_pos(&self) -> usize {
@@ -770,7 +791,8 @@ impl CodeMap {
 
     /// Creates a new filemap without setting its line information. If you don't
     /// intend to set the line information yourself, you should use new_filemap_and_lines.
-    pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc<FileMap> {
+    pub fn new_filemap(&self, filename: FileName, abs_path: Option<FileName>,
+                       mut src: String) -> Rc<FileMap> {
         let start_pos = self.next_start_pos();
         let mut files = self.files.borrow_mut();
 
@@ -783,6 +805,7 @@ impl CodeMap {
 
         let filemap = Rc::new(FileMap {
             name: filename,
+            abs_path: abs_path,
             src: Some(Rc::new(src)),
             start_pos: Pos::from_usize(start_pos),
             end_pos: Pos::from_usize(end_pos),
@@ -796,8 +819,11 @@ impl CodeMap {
     }
 
     /// Creates a new filemap and sets its line information.
-    pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc<FileMap> {
-        let fm = self.new_filemap(filename.to_string(), src.to_owned());
+    pub fn new_filemap_and_lines(&self, filename: &str, abs_path: Option<&str>,
+                                 src: &str) -> Rc<FileMap> {
+        let fm = self.new_filemap(filename.to_string(),
+                                  abs_path.map(|s| s.to_owned()),
+                                  src.to_owned());
         let mut byte_pos: u32 = fm.start_pos.0;
         for line in src.lines() {
             // register the start of this line
@@ -816,6 +842,7 @@ impl CodeMap {
     /// information for things inlined from other crates.
     pub fn new_imported_filemap(&self,
                                 filename: FileName,
+                                abs_path: Option<FileName>,
                                 source_len: usize,
                                 mut file_local_lines: Vec<BytePos>,
                                 mut file_local_multibyte_chars: Vec<MultiByteChar>)
@@ -836,6 +863,7 @@ impl CodeMap {
 
         let filemap = Rc::new(FileMap {
             name: filename,
+            abs_path: abs_path,
             src: None,
             start_pos: start_pos,
             end_pos: end_pos,
@@ -1422,6 +1450,7 @@ mod tests {
     fn t1 () {
         let cm = CodeMap::new();
         let fm = cm.new_filemap("blork.rs".to_string(),
+                                None,
                                 "first line.\nsecond line".to_string());
         fm.next_line(BytePos(0));
         // Test we can get lines with partial line info.
@@ -1438,6 +1467,7 @@ mod tests {
     fn t2 () {
         let cm = CodeMap::new();
         let fm = cm.new_filemap("blork.rs".to_string(),
+                                None,
                                 "first line.\nsecond line".to_string());
         // TESTING *REALLY* BROKEN BEHAVIOR:
         fm.next_line(BytePos(0));
@@ -1448,10 +1478,13 @@ mod tests {
     fn init_code_map() -> CodeMap {
         let cm = CodeMap::new();
         let fm1 = cm.new_filemap("blork.rs".to_string(),
+                                 None,
                                  "first line.\nsecond line".to_string());
         let fm2 = cm.new_filemap("empty.rs".to_string(),
+                                 None,
                                  "".to_string());
         let fm3 = cm.new_filemap("blork2.rs".to_string(),
+                                 None,
                                  "first line.\nsecond line".to_string());
 
         fm1.next_line(BytePos(0));
@@ -1514,8 +1547,10 @@ mod tests {
         // € is a three byte utf8 char.
         let fm1 =
             cm.new_filemap("blork.rs".to_string(),
+                           None,
                            "fir€st €€€€ line.\nsecond line".to_string());
         let fm2 = cm.new_filemap("blork2.rs".to_string(),
+                                 None,
                                  "first line€€.\n€ second line".to_string());
 
         fm1.next_line(BytePos(0));
@@ -1583,7 +1618,7 @@ mod tests {
         let cm = CodeMap::new();
         let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
         let selection = "     \n    ~~\n~~~\n~~~~~     \n   \n";
-        cm.new_filemap_and_lines("blork.rs", inputtext);
+        cm.new_filemap_and_lines("blork.rs", None, inputtext);
         let span = span_from_selection(inputtext, selection);
 
         // check that we are extracting the text we thought we were extracting
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index c164e89c52f..0e5d6841c82 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -9,50 +9,33 @@
 // except according to those terms.
 
 use attr::{AttrMetaMethods, HasAttrs};
-use errors::Handler;
-use feature_gate::GatedCfgAttr;
+use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
 use fold::Folder;
 use {ast, fold, attr};
 use codemap::{Spanned, respan};
+use parse::{ParseSess, token};
 use ptr::P;
 
 use util::small_vector::SmallVector;
 
-pub trait CfgFolder: fold::Folder {
-    // Check if a node with the given attributes is in this configuration.
-    fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool;
-
-    // Update a node before checking if it is in this configuration (used to implement `cfg_attr`).
-    fn process_attrs<T: HasAttrs>(&mut self, node: T) -> T { node }
-
-    // Visit attributes on expression and statements (but not attributes on items in blocks).
-    fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {}
-
-    // Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`.
-    fn visit_unremovable_expr(&mut self, _expr: &ast::Expr) {}
+/// A folder that strips out items that do not belong in the current configuration.
+pub struct StripUnconfigured<'a> {
+    pub config: &'a ast::CrateConfig,
+    pub should_test: bool,
+    pub sess: &'a ParseSess,
+    pub features: Option<&'a Features>,
+}
 
+impl<'a> StripUnconfigured<'a> {
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
-        let node = self.process_attrs(node);
+        let node = self.process_cfg_attrs(node);
         if self.in_cfg(node.attrs()) { Some(node) } else { None }
     }
-}
-
-/// A folder that strips out items that do not belong in the current
-/// configuration.
-pub struct StripUnconfigured<'a> {
-    diag: CfgDiagReal<'a, 'a>,
-    config: &'a ast::CrateConfig,
-}
 
-impl<'a> StripUnconfigured<'a> {
-    pub fn new(config: &'a ast::CrateConfig,
-               diagnostic: &'a Handler,
-               feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>)
-               -> Self {
-        StripUnconfigured {
-            config: config,
-            diag: CfgDiagReal { diag: diagnostic, feature_gated_cfgs: feature_gated_cfgs },
-        }
+    fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T {
+        node.map_attrs(|attrs| {
+            attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
+        })
     }
 
     fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
@@ -64,7 +47,7 @@ impl<'a> StripUnconfigured<'a> {
             Some(attr_list) => attr_list,
             None => {
                 let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
-                self.diag.diag.span_err(attr.span, msg);
+                self.sess.span_diagnostic.span_err(attr.span, msg);
                 return None;
             }
         };
@@ -72,13 +55,13 @@ impl<'a> StripUnconfigured<'a> {
             (2, Some(cfg), Some(mi)) => (cfg, mi),
             _ => {
                 let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
-                self.diag.diag.span_err(attr.span, msg);
+                self.sess.span_diagnostic.span_err(attr.span, msg);
                 return None;
             }
         };
 
-        if attr::cfg_matches(self.config, &cfg, &mut self.diag) {
-            Some(respan(mi.span, ast::Attribute_ {
+        if attr::cfg_matches(self.config, &cfg, self.sess, self.features) {
+            self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
                 id: attr::mk_attr_id(),
                 style: attr.node.style,
                 value: mi.clone(),
@@ -88,61 +71,73 @@ impl<'a> StripUnconfigured<'a> {
             None
         }
     }
-}
 
-impl<'a> CfgFolder for StripUnconfigured<'a> {
-    // Determine if an item should be translated in the current crate
-    // configuration based on the item's attributes
+    // Determine if a node with the given attributes should be included in this configuation.
     fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
         attrs.iter().all(|attr| {
+            // When not compiling with --test we should not compile the #[test] functions
+            if !self.should_test && is_test_or_bench(attr) {
+                return false;
+            }
+
             let mis = match attr.node.value.node {
                 ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis,
                 _ => return true
             };
 
             if mis.len() != 1 {
-                self.diag.emit_error(|diagnostic| {
-                    diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
-                });
+                self.sess.span_diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
                 return true;
             }
 
-            attr::cfg_matches(self.config, &mis[0], &mut self.diag)
-        })
-    }
-
-    fn process_attrs<T: HasAttrs>(&mut self, node: T) -> T {
-        node.map_attrs(|attrs| {
-            attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
+            attr::cfg_matches(self.config, &mis[0], self.sess, self.features)
         })
     }
 
+    // Visit attributes on expression and statements (but not attributes on items in blocks).
     fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
         // flag the offending attributes
         for attr in attrs.iter() {
-            self.diag.feature_gated_cfgs.push(GatedCfgAttr::GatedAttr(attr.span));
-        }
-    }
-
-    fn visit_unremovable_expr(&mut self, expr: &ast::Expr) {
-        if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
-            let msg = "removing an expression is not supported in this position";
-            self.diag.diag.span_err(attr.span, msg);
+            if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
+                emit_feature_err(&self.sess.span_diagnostic,
+                                 "stmt_expr_attributes",
+                                 attr.span,
+                                 GateIssue::Language,
+                                 EXPLAIN_STMT_ATTR_SYNTAX);
+            }
         }
     }
 }
 
 // Support conditional compilation by transforming the AST, stripping out
 // any items that do not belong in the current configuration
-pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate,
-                                feature_gated_cfgs: &mut Vec<GatedCfgAttr>)
-                                -> ast::Crate
-{
-    let config = &krate.config.clone();
-    StripUnconfigured::new(config, diagnostic, feature_gated_cfgs).fold_crate(krate)
+pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
+                                -> (ast::Crate, Features) {
+    let features;
+    {
+        let mut strip_unconfigured = StripUnconfigured {
+            config: &krate.config.clone(),
+            should_test: should_test,
+            sess: sess,
+            features: None,
+        };
+
+        let err_count = sess.span_diagnostic.err_count();
+        let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone());
+        features = get_features(&sess.span_diagnostic, &krate_attrs);
+        if err_count < sess.span_diagnostic.err_count() {
+            krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
+        }
+
+        strip_unconfigured.features = Some(&features);
+        krate = strip_unconfigured.fold_crate(krate);
+        krate.attrs = krate_attrs;
+    }
+
+    (krate, features)
 }
 
-impl<T: CfgFolder> fold::Folder for T {
+impl<'a> fold::Folder for StripUnconfigured<'a> {
     fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
         ast::ForeignMod {
             abi: foreign_mod.abi,
@@ -195,6 +190,7 @@ impl<T: CfgFolder> fold::Folder for T {
 
     fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
         self.visit_stmt_or_expr_attrs(expr.attrs());
+
         // If an expr is valid to cfg away it will have been removed by the
         // outer stmt or expression folder before descending in here.
         // Anything else is always required, and thus has to error out
@@ -202,8 +198,12 @@ impl<T: CfgFolder> fold::Folder for T {
         //
         // NB: This is intentionally not part of the fold_expr() function
         //     in order for fold_opt_expr() to be able to avoid this check
-        self.visit_unremovable_expr(&expr);
-        let expr = self.process_attrs(expr);
+        if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a) || is_test_or_bench(a)) {
+            let msg = "removing an expression is not supported in this position";
+            self.sess.span_diagnostic.span_err(attr.span, msg);
+        }
+
+        let expr = self.process_cfg_attrs(expr);
         fold_expr(self, expr)
     }
 
@@ -247,9 +247,15 @@ impl<T: CfgFolder> fold::Folder for T {
         self.configure(item).map(|item| fold::noop_fold_trait_item(item, self))
                             .unwrap_or(SmallVector::zero())
     }
+
+    fn fold_interpolated(&mut self, nt: token::Nonterminal) -> token::Nonterminal {
+        // Don't configure interpolated AST (c.f. #34171).
+        // Interpolated AST will get configured once the surrounding tokens are parsed.
+        nt
+    }
 }
 
-fn fold_expr<F: CfgFolder>(folder: &mut F, expr: P<ast::Expr>) -> P<ast::Expr> {
+fn fold_expr(folder: &mut StripUnconfigured, expr: P<ast::Expr>) -> P<ast::Expr> {
     expr.map(|ast::Expr {id, span, node, attrs}| {
         fold::noop_fold_expr(ast::Expr {
             id: id,
@@ -271,21 +277,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
     attr.check_name("cfg")
 }
 
-pub trait CfgDiag {
-    fn emit_error<F>(&mut self, f: F) where F: FnMut(&Handler);
-    fn flag_gated<F>(&mut self, f: F) where F: FnMut(&mut Vec<GatedCfgAttr>);
-}
-
-pub struct CfgDiagReal<'a, 'b> {
-    pub diag: &'a Handler,
-    pub feature_gated_cfgs: &'b mut Vec<GatedCfgAttr>,
-}
-
-impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> {
-    fn emit_error<F>(&mut self, mut f: F) where F: FnMut(&Handler) {
-        f(self.diag)
-    }
-    fn flag_gated<F>(&mut self, mut f: F) where F: FnMut(&mut Vec<GatedCfgAttr>) {
-        f(self.feature_gated_cfgs)
-    }
+fn is_test_or_bench(attr: &ast::Attribute) -> bool {
+    attr.check_name("test") || attr.check_name("bench")
 }
diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs
index 6b15aa4f92c..71a03e846a2 100644
--- a/src/libsyntax/errors/emitter.rs
+++ b/src/libsyntax/errors/emitter.rs
@@ -668,7 +668,7 @@ mod test {
         tolv
         dreizehn
         ";
-        let file = cm.new_filemap_and_lines("dummy.txt", content);
+        let file = cm.new_filemap_and_lines("dummy.txt", None, content);
         let start = file.lines.borrow()[10];
         let end = file.lines.borrow()[11];
         let sp = mk_sp(start, end);
@@ -694,7 +694,7 @@ mod test {
         let cm = CodeMap::new();
         let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
         let selection = "     \n    ~~\n~~~\n~~~~~     \n   \n";
-        cm.new_filemap_and_lines("blork.rs", inputtext);
+        cm.new_filemap_and_lines("blork.rs", None, inputtext);
         let sp = span_from_selection(inputtext, selection);
         let msp: MultiSpan = sp.into();
 
@@ -717,7 +717,7 @@ mod test {
         let inputtext  = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
         let selection1 = "     \n      \n   \n          \n ~ \n"; // intentionally out of order
         let selection2 = "     \n    ~~\n~~~\n~~~~~     \n   \n";
-        cm.new_filemap_and_lines("blork.rs", inputtext);
+        cm.new_filemap_and_lines("blork.rs", None, inputtext);
         let sp1 = span_from_selection(inputtext, selection1);
         let sp2 = span_from_selection(inputtext, selection2);
         let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]);
@@ -757,7 +757,7 @@ mod test {
             assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
             sp
         };
-        cm.new_filemap_and_lines("dummy.txt", inp);
+        cm.new_filemap_and_lines("dummy.txt", None, inp);
         let sp1 = span(sp1, "aaaaaa");
         let sp2 = span(sp2, "bbbbbb");
         let sp3 = span(sp3, "ccccc");
@@ -802,7 +802,7 @@ mod test {
                    ddd__eee_\n\
                    elided\n\
                    __f_gg";
-        let file = cm.new_filemap_and_lines("dummy.txt", inp);
+        let file = cm.new_filemap_and_lines("dummy.txt", None, inp);
 
         let span = |lo, hi, (off_lo, off_hi)| {
             let lines = file.lines.borrow();
diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs
index 51fe4572dbc..79e40a09165 100644
--- a/src/libsyntax/errors/snippet/test.rs
+++ b/src/libsyntax/errors/snippet/test.rs
@@ -88,7 +88,7 @@ fn foo() {
 ";
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
     let span_bar = cm.span_substr(&foo, file_text, "bar", 0);
 
     let mut snippet = SnippetData::new(cm, Some(span_bar));
@@ -113,7 +113,7 @@ fn foo() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
     let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
     let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
     let span_semi = cm.span_substr(&foo, file_text, ";", 0);
@@ -173,12 +173,12 @@ fn bar() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo_map = cm.new_filemap_and_lines("foo.rs", file_text_foo);
+    let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo);
     let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0);
     let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1);
     let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0);
 
-    let bar_map = cm.new_filemap_and_lines("bar.rs", file_text_bar);
+    let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar);
     let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0);
     let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1);
     let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0);
@@ -235,7 +235,7 @@ fn foo() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
     let span_data0 = cm.span_substr(&foo, file_text, "data", 0);
     let span_data1 = cm.span_substr(&foo, file_text, "data", 1);
     let span_rbrace = cm.span_substr(&foo, file_text, "}", 3);
@@ -274,7 +274,7 @@ fn foo() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
     let span0 = cm.span_substr(&foo, file_text, "vec.push", 0);
     let span1 = cm.span_substr(&foo, file_text, "vec", 0);
     let span2 = cm.span_substr(&foo, file_text, "ec.push", 0);
@@ -312,7 +312,7 @@ fn foo() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
     let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
     let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
     let span_semi = cm.span_substr(&foo, file_text, ";", 0);
@@ -354,7 +354,7 @@ fn foo() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
     let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3);
     let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8);
 
@@ -393,7 +393,7 @@ fn foo() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
 
     let mut snippet = SnippetData::new(cm.clone(), None);
     for i in 0..4 {
@@ -427,7 +427,7 @@ impl SomeTrait for () {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
 
     let mut snippet = SnippetData::new(cm.clone(), None);
     let fn_span = cm.span_substr(&foo, file_text, "fn", 0);
@@ -456,7 +456,7 @@ fn span_overlap_label() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
 
     let mut snippet = SnippetData::new(cm.clone(), None);
     let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0);
@@ -491,7 +491,7 @@ fn span_overlap_label2() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
 
     let mut snippet = SnippetData::new(cm.clone(), None);
     let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0);
@@ -529,7 +529,7 @@ fn span_overlap_label3() {
 "#;
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
 
     let mut snippet = SnippetData::new(cm.clone(), None);
 
@@ -578,7 +578,7 @@ fn main() {
 
 
     let cm = Rc::new(CodeMap::new());
-    let foo = cm.new_filemap_and_lines("foo.rs", file_text);
+    let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
 
     let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1);
     rbrace_span.lo = rbrace_span.hi;
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 303187aeba8..5da81a269ab 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -18,7 +18,6 @@ use errors::DiagnosticBuilder;
 use ext;
 use ext::expand;
 use ext::tt::macro_rules;
-use feature_gate::GatedCfgAttr;
 use parse;
 use parse::parser;
 use parse::token;
@@ -95,6 +94,16 @@ impl Annotatable {
             _ => panic!("expected Item")
         }
     }
+
+    pub fn fold_with<F: Folder>(self, folder: &mut F) -> SmallVector<Self> {
+        match self {
+            Annotatable::Item(item) => folder.fold_item(item).map(Annotatable::Item),
+            Annotatable::ImplItem(item) =>
+                folder.fold_impl_item(item.unwrap()).map(|item| Annotatable::ImplItem(P(item))),
+            Annotatable::TraitItem(item) =>
+                folder.fold_trait_item(item.unwrap()).map(|item| Annotatable::TraitItem(P(item))),
+        }
+    }
 }
 
 // A more flexible ItemDecorator.
@@ -536,6 +545,17 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
     syntax_expanders
 }
 
+pub trait MacroLoader {
+    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef>;
+}
+
+pub struct DummyMacroLoader;
+impl MacroLoader for DummyMacroLoader {
+    fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<ast::MacroDef> {
+        Vec::new()
+    }
+}
+
 /// One of these is made during expansion and incrementally updated as we go;
 /// when a macro expansion occurs, the resulting nodes have the backtrace()
 /// -> expn_info of their expansion context stored into their span.
@@ -545,7 +565,7 @@ pub struct ExtCtxt<'a> {
     pub backtrace: ExpnId,
     pub ecfg: expand::ExpansionConfig<'a>,
     pub crate_root: Option<&'static str>,
-    pub feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>,
+    pub loader: &'a mut MacroLoader,
 
     pub mod_path: Vec<ast::Ident> ,
     pub exported_macros: Vec<ast::MacroDef>,
@@ -561,7 +581,8 @@ pub struct ExtCtxt<'a> {
 impl<'a> ExtCtxt<'a> {
     pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
                ecfg: expand::ExpansionConfig<'a>,
-               feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>) -> ExtCtxt<'a> {
+               loader: &'a mut MacroLoader)
+               -> ExtCtxt<'a> {
         let env = initial_syntax_expander_table(&ecfg);
         ExtCtxt {
             parse_sess: parse_sess,
@@ -570,8 +591,8 @@ impl<'a> ExtCtxt<'a> {
             mod_path: Vec::new(),
             ecfg: ecfg,
             crate_root: None,
-            feature_gated_cfgs: feature_gated_cfgs,
             exported_macros: Vec::new(),
+            loader: loader,
             syntax_env: env,
             recursion_count: 0,
 
@@ -602,22 +623,6 @@ impl<'a> ExtCtxt<'a> {
     }
     pub fn backtrace(&self) -> ExpnId { self.backtrace }
 
-    /// Original span that caused the current exapnsion to happen.
-    pub fn original_span(&self) -> Span {
-        let mut expn_id = self.backtrace;
-        let mut call_site = None;
-        loop {
-            match self.codemap().with_expn_info(expn_id, |ei| ei.map(|ei| ei.call_site)) {
-                None => break,
-                Some(cs) => {
-                    call_site = Some(cs);
-                    expn_id = cs.expn_id;
-                }
-            }
-        }
-        call_site.expect("missing expansion backtrace")
-    }
-
     /// Returns span for the macro which originally caused the current expansion to happen.
     ///
     /// Stops backtracing at include! boundary.
@@ -925,4 +930,10 @@ impl SyntaxEnv {
         let last_chain_index = self.chain.len() - 1;
         &mut self.chain[last_chain_index].info
     }
+
+    pub fn is_crate_root(&mut self) -> bool {
+        // The first frame is pushed in `SyntaxEnv::new()` and the second frame is
+        // pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
+        self.chain.len() <= 2
+    }
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d3f5a573218..d63411568dc 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -41,6 +41,7 @@ trait MacroGenerable: Sized {
 
     // Fold this node or list of nodes using the given folder.
     fn fold_with<F: Folder>(self, folder: &mut F) -> Self;
+    fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V);
 
     // Return a placeholder expansion to allow compilation to continue after an erroring expansion.
     fn dummy(span: Span) -> Self;
@@ -50,7 +51,9 @@ trait MacroGenerable: Sized {
 }
 
 macro_rules! impl_macro_generable {
-    ($($ty:ty: $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*,
+    ($($ty:ty: $kind_name:expr, .$make:ident,
+               $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
+               $(.$visit:ident)* $(lift .$visit_elt:ident)*,
                |$span:ident| $dummy:expr;)*) => { $(
         impl MacroGenerable for $ty {
             fn kind_name() -> &'static str { $kind_name }
@@ -59,21 +62,27 @@ macro_rules! impl_macro_generable {
                 $( folder.$fold(self) )*
                 $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )*
             }
+            fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V) {
+                $( visitor.$visit(self) )*
+                $( for item in self.as_slice() { visitor. $visit_elt (item) } )*
+            }
             fn dummy($span: Span) -> Self { $dummy }
         }
     )* }
 }
 
 impl_macro_generable! {
-    P<ast::Expr>: "expression", .make_expr, .fold_expr, |span| DummyResult::raw_expr(span);
-    P<ast::Pat>:  "pattern",    .make_pat,  .fold_pat,  |span| P(DummyResult::raw_pat(span));
-    P<ast::Ty>:   "type",       .make_ty,   .fold_ty,   |span| DummyResult::raw_ty(span);
-    SmallVector<ast::ImplItem>:
-        "impl item", .make_impl_items, lift .fold_impl_item, |_span| SmallVector::zero();
-    SmallVector<P<ast::Item>>:
-        "item",      .make_items,      lift .fold_item,      |_span| SmallVector::zero();
+    P<ast::Pat>: "pattern", .make_pat, .fold_pat, .visit_pat, |span| P(DummyResult::raw_pat(span));
+    P<ast::Ty>:  "type",    .make_ty,  .fold_ty,  .visit_ty,  |span| DummyResult::raw_ty(span);
+    P<ast::Expr>:
+        "expression", .make_expr, .fold_expr, .visit_expr, |span| DummyResult::raw_expr(span);
     SmallVector<ast::Stmt>:
-        "statement", .make_stmts,      lift .fold_stmt,      |_span| SmallVector::zero();
+        "statement",  .make_stmts, lift .fold_stmt, lift .visit_stmt, |_span| SmallVector::zero();
+    SmallVector<P<ast::Item>>:
+        "item",       .make_items, lift .fold_item, lift .visit_item, |_span| SmallVector::zero();
+    SmallVector<ast::ImplItem>:
+        "impl item",  .make_impl_items, lift .fold_impl_item, lift .visit_impl_item,
+        |_span| SmallVector::zero();
 }
 
 impl MacroGenerable for Option<P<ast::Expr>> {
@@ -85,6 +94,9 @@ impl MacroGenerable for Option<P<ast::Expr>> {
     fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
         self.and_then(|expr| folder.fold_opt_expr(expr))
     }
+    fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V) {
+        self.as_ref().map(|expr| visitor.visit_expr(expr));
+    }
 }
 
 pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
@@ -236,14 +248,8 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
                     },
                 });
 
-                // The span that we pass to the expanders we want to
-                // be the root of the call stack. That's the most
-                // relevant span and it's the actual invocation of
-                // the macro.
-                let mac_span = fld.cx.original_span();
-
                 let marked_tts = mark_tts(&tts[..], mark);
-                Some(expandfun.expand(fld.cx, mac_span, &marked_tts))
+                Some(expandfun.expand(fld.cx, call_site, &marked_tts))
             }
 
             IdentTT(ref expander, tt_span, allow_internal_unstable) => {
@@ -326,6 +332,7 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
 
     let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
     let configured = marked.fold_with(&mut fld.strip_unconfigured());
+    fld.load_macros(&configured);
     let fully_expanded = configured.fold_with(fld);
     fld.cx.bt_pop();
     fully_expanded
@@ -723,20 +730,14 @@ fn expand_annotatable(a: Annotatable,
                       -> SmallVector<Annotatable> {
     let a = expand_item_multi_modifier(a, fld);
 
-    let mut decorator_items = SmallVector::zero();
-    let mut new_attrs = Vec::new();
-    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
-
-    let mut new_items: SmallVector<Annotatable> = match a {
+    let new_items: SmallVector<Annotatable> = match a {
         Annotatable::Item(it) => match it.node {
             ast::ItemKind::Mac(..) => {
-                let new_items: SmallVector<P<ast::Item>> = it.and_then(|it| match it.node {
+                it.and_then(|it| match it.node {
                     ItemKind::Mac(mac) =>
                         expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld),
                     _ => unreachable!(),
-                });
-
-                new_items.into_iter().map(|i| Annotatable::Item(i)).collect()
+                })
             }
             ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
                 let valid_ident =
@@ -745,23 +746,17 @@ fn expand_annotatable(a: Annotatable,
                 if valid_ident {
                     fld.cx.mod_push(it.ident);
                 }
-                let macro_use = contains_macro_use(fld, &new_attrs[..]);
+                let macro_use = contains_macro_use(fld, &it.attrs);
                 let result = with_exts_frame!(fld.cx.syntax_env,
                                               macro_use,
                                               noop_fold_item(it, fld));
                 if valid_ident {
                     fld.cx.mod_pop();
                 }
-                result.into_iter().map(|i| Annotatable::Item(i)).collect()
+                result
             },
-            _ => {
-                let it = P(ast::Item {
-                    attrs: new_attrs,
-                    ..(*it).clone()
-                });
-                noop_fold_item(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
-            }
-        },
+            _ => noop_fold_item(it, fld),
+        }.into_iter().map(|i| Annotatable::Item(i)).collect(),
 
         Annotatable::TraitItem(it) => match it.node {
             ast::TraitItemKind::Method(_, Some(_)) => {
@@ -789,6 +784,15 @@ fn expand_annotatable(a: Annotatable,
         }
     };
 
+    new_items.into_iter().flat_map(|a| decorate(a, fld)).collect()
+}
+
+fn decorate(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
+    let mut decorator_items = SmallVector::zero();
+    let mut new_attrs = Vec::new();
+    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
+
+    let mut new_items = SmallVector::one(a.fold_attrs(new_attrs));
     new_items.push_all(decorator_items);
     new_items
 }
@@ -839,16 +843,18 @@ fn expand_decorators(a: Annotatable,
                         }
                     });
 
-                    // we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
-                    // but that double-mut-borrows fld
                     let mut items: SmallVector<Annotatable> = SmallVector::zero();
                     dec.expand(fld.cx,
                                attr.span,
                                &attr.node.value,
                                &a,
                                &mut |ann| items.push(ann));
-                    decorator_items.extend(items.into_iter()
-                        .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
+
+                    for item in items {
+                        for configured_item in item.fold_with(&mut fld.strip_unconfigured()) {
+                            decorator_items.extend(expand_annotatable(configured_item, fld));
+                        }
+                    }
 
                     fld.cx.bt_pop();
                 }
@@ -992,9 +998,46 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     }
 
     fn strip_unconfigured(&mut self) -> StripUnconfigured {
-        StripUnconfigured::new(&self.cx.cfg,
-                               &self.cx.parse_sess.span_diagnostic,
-                               self.cx.feature_gated_cfgs)
+        StripUnconfigured {
+            config: &self.cx.cfg,
+            should_test: self.cx.ecfg.should_test,
+            sess: self.cx.parse_sess,
+            features: self.cx.ecfg.features,
+        }
+    }
+
+    fn load_macros<T: MacroGenerable>(&mut self, node: &T) {
+        struct MacroLoadingVisitor<'a, 'b: 'a>{
+            cx: &'a mut ExtCtxt<'b>,
+            at_crate_root: bool,
+        }
+
+        impl<'a, 'b, 'v> Visitor<'v> for MacroLoadingVisitor<'a, 'b> {
+            fn visit_mac(&mut self, _: &'v ast::Mac) {}
+            fn visit_item(&mut self, item: &'v ast::Item) {
+                if let ast::ItemKind::ExternCrate(..) = item.node {
+                    // We need to error on `#[macro_use] extern crate` when it isn't at the
+                    // crate root, because `$crate` won't work properly.
+                    for def in self.cx.loader.load_crate(item, self.at_crate_root) {
+                        self.cx.insert_macro(def);
+                    }
+                } else {
+                    let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false);
+                    visit::walk_item(self, item);
+                    self.at_crate_root = at_crate_root;
+                }
+            }
+            fn visit_block(&mut self, block: &'v ast::Block) {
+                let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false);
+                visit::walk_block(self, block);
+                self.at_crate_root = at_crate_root;
+            }
+        }
+
+        node.visit_with(&mut MacroLoadingVisitor {
+            at_crate_root: self.cx.syntax_env.is_crate_root(),
+            cx: self.cx,
+        });
     }
 }
 
@@ -1098,6 +1141,7 @@ pub struct ExpansionConfig<'feat> {
     pub features: Option<&'feat Features>,
     pub recursion_limit: usize,
     pub trace_mac: bool,
+    pub should_test: bool, // If false, strip `#[test]` nodes
 }
 
 macro_rules! feature_tests {
@@ -1120,6 +1164,7 @@ impl<'feat> ExpansionConfig<'feat> {
             features: None,
             recursion_limit: 64,
             trace_mac: false,
+            should_test: false,
         }
     }
 
@@ -1136,10 +1181,8 @@ impl<'feat> ExpansionConfig<'feat> {
 }
 
 pub fn expand_crate(mut cx: ExtCtxt,
-                    // these are the macros being imported to this crate:
-                    imported_macros: Vec<ast::MacroDef>,
                     user_exts: Vec<NamedSyntaxExtension>,
-                    c: Crate) -> (Crate, HashSet<Name>) {
+                    mut c: Crate) -> (Crate, HashSet<Name>) {
     if std_inject::no_core(&c) {
         cx.crate_root = None;
     } else if std_inject::no_std(&c) {
@@ -1150,14 +1193,14 @@ pub fn expand_crate(mut cx: ExtCtxt,
     let ret = {
         let mut expander = MacroExpander::new(&mut cx);
 
-        for def in imported_macros {
-            expander.cx.insert_macro(def);
-        }
-
         for (name, extension) in user_exts {
             expander.cx.syntax_env.insert(name, extension);
         }
 
+        let items = SmallVector::many(c.module.items);
+        expander.load_macros(&items);
+        c.module.items = items.into();
+
         let err_count = cx.parse_sess.span_diagnostic.err_count();
         let mut ret = expander.fold_crate(c);
         ret.exported_macros = expander.cx.exported_macros.clone();
@@ -1219,7 +1262,7 @@ mod tests {
     use ast;
     use ast::Name;
     use codemap;
-    use ext::base::ExtCtxt;
+    use ext::base::{ExtCtxt, DummyMacroLoader};
     use ext::mtwt;
     use fold::Folder;
     use parse;
@@ -1290,9 +1333,9 @@ mod tests {
             src,
             Vec::new(), &sess).unwrap();
         // should fail:
-        let mut gated_cfgs = vec![];
-        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
-        expand_crate(ecx, vec![], vec![], crate_ast);
+        let mut loader = DummyMacroLoader;
+        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
+        expand_crate(ecx, vec![], crate_ast);
     }
 
     // make sure that macros can't escape modules
@@ -1305,9 +1348,9 @@ mod tests {
             "<test>".to_string(),
             src,
             Vec::new(), &sess).unwrap();
-        let mut gated_cfgs = vec![];
-        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
-        expand_crate(ecx, vec![], vec![], crate_ast);
+        let mut loader = DummyMacroLoader;
+        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
+        expand_crate(ecx, vec![], crate_ast);
     }
 
     // macro_use modules should allow macros to escape
@@ -1319,18 +1362,18 @@ mod tests {
             "<test>".to_string(),
             src,
             Vec::new(), &sess).unwrap();
-        let mut gated_cfgs = vec![];
-        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
-        expand_crate(ecx, vec![], vec![], crate_ast);
+        let mut loader = DummyMacroLoader;
+        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader);
+        expand_crate(ecx, vec![], crate_ast);
     }
 
     fn expand_crate_str(crate_str: String) -> ast::Crate {
         let ps = parse::ParseSess::new();
         let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
         // the cfg argument actually does matter, here...
-        let mut gated_cfgs = vec![];
-        let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs);
-        expand_crate(ecx, vec![], vec![], crate_ast).0
+        let mut loader = DummyMacroLoader;
+        let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader);
+        expand_crate(ecx, vec![], crate_ast).0
     }
 
     // find the pat_ident paths in a crate
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 3e375e1798d..fd229d77966 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -154,7 +154,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
             // dependency information
             let filename = format!("{}", file.display());
             let interned = token::intern_and_get_ident(&src[..]);
-            cx.codemap().new_filemap_and_lines(&filename, &src);
+            cx.codemap().new_filemap_and_lines(&filename, None, &src);
 
             base::MacEager::expr(cx.expr_str(sp, interned))
         }
@@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
             // Add this input file to the code map to make it available as
             // dependency information, but don't enter it's contents
             let filename = format!("{}", file.display());
-            cx.codemap().new_filemap_and_lines(&filename, "");
+            cx.codemap().new_filemap_and_lines(&filename, None, "");
 
             base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Rc::new(bytes))))
         }
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 69e24cf0719..bbe989b0f40 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -349,203 +349,12 @@ fn check_rhs(cx: &mut ExtCtxt, rhs: &TokenTree) -> bool {
     false
 }
 
-// Issue 30450: when we are through a warning cycle, we can just error
-// on all failure conditions and remove this struct and enum.
-
-#[derive(Debug)]
-struct OnFail {
-    saw_failure: bool,
-    action: OnFailAction,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum OnFailAction { Warn, Error, DoNothing }
-
-impl OnFail {
-    fn warn() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::Warn } }
-    fn error() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::Error } }
-    fn do_nothing() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::DoNothing } }
-    fn react(&mut self, cx: &mut ExtCtxt, sp: Span, msg: &str, help: Option<&str>) {
-        match self.action {
-            OnFailAction::DoNothing => {}
-            OnFailAction::Error => {
-                let mut err = cx.struct_span_err(sp, msg);
-                if let Some(msg) = help { err.span_help(sp, msg); }
-                err.emit();
-            }
-            OnFailAction::Warn => {
-                let mut warn = cx.struct_span_warn(sp, msg);
-                if let Some(msg) = help { warn.span_help(sp, msg); }
-                warn.span_note(sp, "The above warning will be a hard error in the next release.")
-                    .emit();
-            }
-        };
-        self.saw_failure = true;
-    }
-}
-
 fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) -> bool {
-    // Issue 30450: when we are through a warning cycle, we can just
-    // error on all failure conditions (and remove check_matcher_old).
-
-    // First run the old-pass, but *only* to find out if it would have failed.
-    let mut on_fail = OnFail::do_nothing();
-    check_matcher_old(cx, matcher.iter(), &Eof, &mut on_fail);
-    // Then run the new pass, but merely warn if the old pass accepts and new pass rejects.
-    // (Note this silently accepts code if new pass accepts.)
-    let mut on_fail = if on_fail.saw_failure {
-        OnFail::error()
-    } else {
-        OnFail::warn()
-    };
-    check_matcher_new(cx, matcher, &mut on_fail);
-    // matcher is valid if the new pass didn't see any error,
-    // or if errors were considered warnings
-    on_fail.action != OnFailAction::Error || !on_fail.saw_failure
-}
-
-// returns the last token that was checked, for TokenTree::Sequence.
-// return value is used by recursive calls.
-fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fail: &mut OnFail)
--> Option<(Span, Token)> where I: Iterator<Item=&'a TokenTree> {
-    use print::pprust::token_to_string;
-    use std::iter::once;
-
-    let mut last = None;
-
-    // 2. For each token T in M:
-    let mut tokens = matcher.peekable();
-    while let Some(token) = tokens.next() {
-        last = match *token {
-            TokenTree::Token(sp, MatchNt(ref name, ref frag_spec)) => {
-                // ii. If T is a simple NT, look ahead to the next token T' in
-                // M. If T' is in the set FOLLOW(NT), continue. Else; reject.
-                if can_be_followed_by_any(&frag_spec.name.as_str()) {
-                    continue
-                } else {
-                    let next_token = match tokens.peek() {
-                        // If T' closes a complex NT, replace T' with F
-                        Some(&&TokenTree::Token(_, CloseDelim(_))) => follow.clone(),
-                        Some(&&TokenTree::Token(_, ref tok)) => tok.clone(),
-                        Some(&&TokenTree::Sequence(sp, _)) => {
-                            // Be conservative around sequences: to be
-                            // more specific, we would need to
-                            // consider FIRST sets, but also the
-                            // possibility that the sequence occurred
-                            // zero times (in which case we need to
-                            // look at the token that follows the
-                            // sequence, which may itself be a sequence,
-                            // and so on).
-                            on_fail.react(cx, sp,
-                                          &format!("`${0}:{1}` is followed by a \
-                                                    sequence repetition, which is not \
-                                                    allowed for `{1}` fragments",
-                                                   name, frag_spec),
-                                          None);
-                            Eof
-                        },
-                        // die next iteration
-                        Some(&&TokenTree::Delimited(_, ref delim)) => delim.close_token(),
-                        // else, we're at the end of the macro or sequence
-                        None => follow.clone()
-                    };
-
-                    let tok = if let TokenTree::Token(_, ref tok) = *token {
-                        tok
-                    } else {
-                        unreachable!()
-                    };
-
-                    // If T' is in the set FOLLOW(NT), continue. Else, reject.
-                    match (&next_token, is_in_follow(cx, &next_token, &frag_spec.name.as_str())) {
-                        (_, Err((msg, _))) => {
-                            // no need for help message, those messages
-                            // are never emitted anyway...
-                            on_fail.react(cx, sp, &msg, None);
-                            continue
-                        }
-                        (&Eof, _) => return Some((sp, tok.clone())),
-                        (_, Ok(true)) => continue,
-                        (next, Ok(false)) => {
-                            on_fail.react(cx, sp, &format!("`${0}:{1}` is followed by `{2}`, which \
-                                                      is not allowed for `{1}` fragments",
-                                                     name, frag_spec,
-                                                     token_to_string(next)), None);
-                            continue
-                        },
-                    }
-                }
-            },
-            TokenTree::Sequence(sp, ref seq) => {
-                // iii. Else, T is a complex NT.
-                match seq.separator {
-                    // If T has the form $(...)U+ or $(...)U* for some token U,
-                    // run the algorithm on the contents with F set to U. If it
-                    // accepts, continue, else, reject.
-                    Some(ref u) => {
-                        let last = check_matcher_old(cx, seq.tts.iter(), u, on_fail);
-                        match last {
-                            // Since the delimiter isn't required after the last
-                            // repetition, make sure that the *next* token is
-                            // sane. This doesn't actually compute the FIRST of
-                            // the rest of the matcher yet, it only considers
-                            // single tokens and simple NTs. This is imprecise,
-                            // but conservatively correct.
-                            Some((span, tok)) => {
-                                let fol = match tokens.peek() {
-                                    Some(&&TokenTree::Token(_, ref tok)) => tok.clone(),
-                                    Some(&&TokenTree::Delimited(_, ref delim)) =>
-                                        delim.close_token(),
-                                    Some(_) => {
-                                        on_fail.react(cx, sp, "sequence repetition followed by \
-                                                another sequence repetition, which is not allowed",
-                                                      None);
-                                        Eof
-                                    },
-                                    None => Eof
-                                };
-                                check_matcher_old(cx, once(&TokenTree::Token(span, tok.clone())),
-                                                  &fol, on_fail)
-                            },
-                            None => last,
-                        }
-                    },
-                    // If T has the form $(...)+ or $(...)*, run the algorithm
-                    // on the contents with F set to the token following the
-                    // sequence. If it accepts, continue, else, reject.
-                    None => {
-                        let fol = match tokens.peek() {
-                            Some(&&TokenTree::Token(_, ref tok)) => tok.clone(),
-                            Some(&&TokenTree::Delimited(_, ref delim)) => delim.close_token(),
-                            Some(_) => {
-                                on_fail.react(cx, sp, "sequence repetition followed by another \
-                                             sequence repetition, which is not allowed", None);
-                                Eof
-                            },
-                            None => Eof
-                        };
-                        check_matcher_old(cx, seq.tts.iter(), &fol, on_fail)
-                    }
-                }
-            },
-            TokenTree::Token(..) => {
-                // i. If T is not an NT, continue.
-                continue
-            },
-            TokenTree::Delimited(_, ref tts) => {
-                // if we don't pass in that close delimiter, we'll incorrectly consider the matcher
-                // `{ $foo:ty }` as having a follow that isn't `RBrace`
-                check_matcher_old(cx, tts.tts.iter(), &tts.close_token(), on_fail)
-            }
-        }
-    }
-    last
-}
-
-fn check_matcher_new(cx: &mut ExtCtxt, matcher: &[TokenTree], on_fail: &mut OnFail) {
     let first_sets = FirstSets::new(matcher);
     let empty_suffix = TokenSet::empty();
-    check_matcher_core(cx, &first_sets, matcher, &empty_suffix, on_fail);
+    let err = cx.parse_sess.span_diagnostic.err_count();
+    check_matcher_core(cx, &first_sets, matcher, &empty_suffix);
+    err == cx.parse_sess.span_diagnostic.err_count()
 }
 
 // The FirstSets for a matcher is a mapping from subsequences in the
@@ -785,8 +594,7 @@ impl TokenSet {
 fn check_matcher_core(cx: &mut ExtCtxt,
                       first_sets: &FirstSets,
                       matcher: &[TokenTree],
-                      follow: &TokenSet,
-                      on_fail: &mut OnFail) -> TokenSet {
+                      follow: &TokenSet) -> TokenSet {
     use print::pprust::token_to_string;
 
     let mut last = TokenSet::empty();
@@ -815,11 +623,11 @@ fn check_matcher_core(cx: &mut ExtCtxt,
             TokenTree::Token(sp, ref tok) => {
                 let can_be_followed_by_any;
                 if let Err(bad_frag) = has_legal_fragment_specifier(tok) {
-                    on_fail.react(cx, sp,
-                                  &format!("invalid fragment specifier `{}`", bad_frag),
-                                  Some("valid fragment specifiers are `ident`, `block`, \
-                                        `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
-                                        and `item`"));
+                    cx.struct_span_err(sp, &format!("invalid fragment specifier `{}`", bad_frag))
+                        .help("valid fragment specifiers are `ident`, `block`, \
+                               `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
+                               and `item`")
+                        .emit();
                     // (This eliminates false positives and duplicates
                     // from error messages.)
                     can_be_followed_by_any = true;
@@ -840,7 +648,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
             }
             TokenTree::Delimited(_, ref d) => {
                 let my_suffix = TokenSet::singleton((d.close_span, Token::CloseDelim(d.delim)));
-                check_matcher_core(cx, first_sets, &d.tts, &my_suffix, on_fail);
+                check_matcher_core(cx, first_sets, &d.tts, &my_suffix);
                 // don't track non NT tokens
                 last.replace_with_irrelevant();
 
@@ -872,7 +680,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
                 // At this point, `suffix_first` is built, and
                 // `my_suffix` is some TokenSet that we can use
                 // for checking the interior of `seq_rep`.
-                let next = check_matcher_core(cx, first_sets, &seq_rep.tts, my_suffix, on_fail);
+                let next = check_matcher_core(cx, first_sets, &seq_rep.tts, my_suffix);
                 if next.maybe_empty {
                     last.add_all(&next);
                 } else {
@@ -894,7 +702,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
                 for &(sp, ref next_token) in &suffix_first.tokens {
                     match is_in_follow(cx, next_token, &frag_spec.name.as_str()) {
                         Err((msg, help)) => {
-                            on_fail.react(cx, sp, &msg, Some(help));
+                            cx.struct_span_err(sp, &msg).help(help).emit();
                             // don't bother reporting every source of
                             // conflict for a particular element of `last`.
                             continue 'each_last;
@@ -909,15 +717,14 @@ fn check_matcher_core(cx: &mut ExtCtxt,
                                 "may be"
                             };
 
-                            on_fail.react(
-                                cx, sp,
+                            cx.span_err(
+                                sp,
                                 &format!("`${name}:{frag}` {may_be} followed by `{next}`, which \
                                           is not allowed for `{frag}` fragments",
                                          name=name,
                                          frag=frag_spec,
                                          next=token_to_string(next_token),
-                                         may_be=may_be),
-                                None
+                                         may_be=may_be)
                             );
                         }
                     }
@@ -947,33 +754,11 @@ fn token_can_be_followed_by_any(tok: &Token) -> bool {
 /// ANYTHING without fear of future compatibility hazards).
 fn frag_can_be_followed_by_any(frag: &str) -> bool {
     match frag {
-        "item" |  // always terminated by `}` or `;`
-        "block" | // exactly one token tree
-        "ident" | // exactly one token tree
-        "meta" |  // exactly one token tree
-        "tt" =>    // exactly one token tree
-            true,
-
-        _ =>
-            false,
-    }
-}
-
-/// True if a fragment of type `frag` can be followed by any sort of
-/// token.  We use this (among other things) as a useful approximation
-/// for when `frag` can be followed by a repetition like `$(...)*` or
-/// `$(...)+`. In general, these can be a bit tricky to reason about,
-/// so we adopt a conservative position that says that any fragment
-/// specifier which consumes at most one token tree can be followed by
-/// a fragment specifier (indeed, these fragments can be followed by
-/// ANYTHING without fear of future compatibility hazards).
-fn can_be_followed_by_any(frag: &str) -> bool {
-    match frag {
-        "item" |  // always terminated by `}` or `;`
+        "item"  | // always terminated by `}` or `;`
         "block" | // exactly one token tree
         "ident" | // exactly one token tree
-        "meta" |  // exactly one token tree
-        "tt" =>    // exactly one token tree
+        "meta"  | // exactly one token tree
+        "tt" =>   // exactly one token tree
             true,
 
         _ =>
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 86c4a33896d..550eb0a56d9 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -34,10 +34,10 @@ use codemap::{CodeMap, Span};
 use errors::Handler;
 use visit;
 use visit::{FnKind, Visitor};
+use parse::ParseSess;
 use parse::token::InternedString;
 
 use std::ascii::AsciiExt;
-use std::cmp;
 
 macro_rules! setter {
     ($field: ident) => {{
@@ -604,59 +604,11 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)]
 ];
 
 #[derive(Debug, Eq, PartialEq)]
-pub enum GatedCfgAttr {
-    GatedCfg(GatedCfg),
-    GatedAttr(Span),
-}
-
-#[derive(Debug, Eq, PartialEq)]
 pub struct GatedCfg {
     span: Span,
     index: usize,
 }
 
-impl Ord for GatedCfgAttr {
-    fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering {
-        let to_tup = |s: &GatedCfgAttr| match *s {
-            GatedCfgAttr::GatedCfg(ref gated_cfg) => {
-                (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index)
-            }
-            GatedCfgAttr::GatedAttr(ref span) => {
-                (span.lo.0, span.hi.0, GATED_CFGS.len())
-            }
-        };
-        to_tup(self).cmp(&to_tup(other))
-    }
-}
-
-impl PartialOrd for GatedCfgAttr {
-    fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl GatedCfgAttr {
-    pub fn check_and_emit(&self,
-                          diagnostic: &Handler,
-                          features: &Features,
-                          codemap: &CodeMap) {
-        match *self {
-            GatedCfgAttr::GatedCfg(ref cfg) => {
-                cfg.check_and_emit(diagnostic, features, codemap);
-            }
-            GatedCfgAttr::GatedAttr(span) => {
-                if !features.stmt_expr_attributes {
-                    emit_feature_err(diagnostic,
-                                     "stmt_expr_attributes",
-                                     span,
-                                     GateIssue::Language,
-                                     EXPLAIN_STMT_ATTR_SYNTAX);
-                }
-            }
-        }
-    }
-}
-
 impl GatedCfg {
     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
         let name = cfg.name();
@@ -669,12 +621,11 @@ impl GatedCfg {
                       }
                   })
     }
-    fn check_and_emit(&self,
-                      diagnostic: &Handler,
-                      features: &Features,
-                      codemap: &CodeMap) {
+
+    pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
-        if !has_feature(features) && !codemap.span_allows_unstable(self.span) {
+        if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
+            let diagnostic = &sess.span_diagnostic;
             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
             emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
         }
@@ -810,7 +761,7 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs
 const EXPLAIN_BOX_SYNTAX: &'static str =
     "box expression syntax is experimental; you can call `Box::new` instead.";
 
-const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
+pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
     "attributes on non-item statements and expressions are experimental.";
 
 pub const EXPLAIN_ASM: &'static str =
@@ -1142,10 +1093,10 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
     }
 }
 
-pub fn get_features(span_handler: &Handler, krate: &ast::Crate) -> Features {
+pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
     let mut features = Features::new();
 
-    for attr in &krate.attrs {
+    for attr in krate_attrs {
         if !attr.check_name("feature") {
             continue
         }
@@ -1188,21 +1139,19 @@ pub fn get_features(span_handler: &Handler, krate: &ast::Crate) -> Features {
     features
 }
 
-pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
+pub fn check_crate(krate: &ast::Crate,
+                   sess: &ParseSess,
+                   features: &Features,
                    plugin_attributes: &[(String, AttributeType)],
-                   unstable: UnstableFeatures) -> Features {
-    maybe_stage_features(span_handler, krate, unstable);
-    let features = get_features(span_handler, krate);
-    {
-        let ctx = Context {
-            features: &features,
-            span_handler: span_handler,
-            cm: cm,
-            plugin_attributes: plugin_attributes,
-        };
-        visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
-    }
-    features
+                   unstable: UnstableFeatures) {
+    maybe_stage_features(&sess.span_diagnostic, krate, unstable);
+    let ctx = Context {
+        features: features,
+        span_handler: &sess.span_diagnostic,
+        cm: sess.codemap(),
+        plugin_attributes: plugin_attributes,
+    };
+    visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
 }
 
 #[derive(Clone, Copy)]
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index 629edced804..06d255d5c0f 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -346,7 +346,7 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
     srdr.read_to_end(&mut src).unwrap();
     let src = String::from_utf8(src).unwrap();
     let cm = CodeMap::new();
-    let filemap = cm.new_filemap(path, src);
+    let filemap = cm.new_filemap(path, None, src);
     let mut rdr = lexer::StringReader::new_raw(span_diagnostic, filemap);
 
     let mut comments: Vec<Comment> = Vec::new();
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index da62e5286d4..d78a81dec83 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -1695,7 +1695,7 @@ mod tests {
                  span_handler: &'a errors::Handler,
                  teststr: String)
                  -> StringReader<'a> {
-        let fm = cm.new_filemap("zebra.rs".to_string(), teststr);
+        let fm = cm.new_filemap("zebra.rs".to_string(), None, teststr);
         StringReader::new(span_handler, fm)
     }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 2a9bcfd658c..2e4d46bc983 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -178,7 +178,7 @@ pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
                                       name: String,
                                       source: String)
                                       -> Parser<'a> {
-    filemap_to_parser(sess, sess.codemap().new_filemap(name, source), cfg)
+    filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source), cfg)
 }
 
 /// Create a new parser, handling errors as appropriate
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 22cc20b8f8c..341b076e7cf 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5430,18 +5430,15 @@ impl<'a> Parser<'a> {
                               name: String,
                               id_sp: Span) -> PResult<'a, (ast::ItemKind, Vec<ast::Attribute> )> {
         let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
-        match included_mod_stack.iter().position(|p| *p == path) {
-            Some(i) => {
-                let mut err = String::from("circular modules: ");
-                let len = included_mod_stack.len();
-                for p in &included_mod_stack[i.. len] {
-                    err.push_str(&p.to_string_lossy());
-                    err.push_str(" -> ");
-                }
-                err.push_str(&path.to_string_lossy());
-                return Err(self.span_fatal(id_sp, &err[..]));
-            }
-            None => ()
+        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
+            let mut err = String::from("circular modules: ");
+            let len = included_mod_stack.len();
+            for p in &included_mod_stack[i.. len] {
+                err.push_str(&p.to_string_lossy());
+                err.push_str(" -> ");
+            }
+            err.push_str(&path.to_string_lossy());
+            return Err(self.span_fatal(id_sp, &err[..]));
         }
         included_mod_stack.push(path.clone());
         drop(included_mod_stack);
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 5b9ec924de9..a2ee5bf6090 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -123,16 +123,16 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
         let list = attr::mk_list_item(InternedString::new("feature"),
                                       vec![prelude_import_meta]);
         let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), list);
-        s.print_attribute(&fake_attr)?;
+        try!(s.print_attribute(&fake_attr));
 
         // #![no_std]
         let no_std_meta = attr::mk_word_item(InternedString::new("no_std"));
         let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), no_std_meta);
-        s.print_attribute(&fake_attr)?;
+        try!(s.print_attribute(&fake_attr));
     }
 
-    s.print_mod(&krate.module, &krate.attrs)?;
-    s.print_remaining_comments()?;
+    try!(s.print_mod(&krate.module, &krate.attrs));
+    try!(s.print_remaining_comments());
     eof(&mut s.s)
 }
 
@@ -385,10 +385,10 @@ pub fn fun_to_string(decl: &ast::FnDecl,
                      generics: &ast::Generics)
                      -> String {
     to_string(|s| {
-        s.head("")?;
-        s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name),
-                   generics, &ast::Visibility::Inherited)?;
-        s.end()?; // Close the head box
+        try!(s.head(""));
+        try!(s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name),
+                   generics, &ast::Visibility::Inherited));
+        try!(s.end()); // Close the head box
         s.end() // Close the outer box
     })
 }
@@ -396,9 +396,9 @@ pub fn fun_to_string(decl: &ast::FnDecl,
 pub fn block_to_string(blk: &ast::Block) -> String {
     to_string(|s| {
         // containing cbox, will be closed by print-block at }
-        s.cbox(INDENT_UNIT)?;
+        try!(s.cbox(INDENT_UNIT));
         // head-ibox, will be closed by print-block after {
-        s.ibox(0)?;
+        try!(s.ibox(0));
         s.print_block(blk)
     })
 }
@@ -454,7 +454,7 @@ pub trait PrintState<'a> {
     fn literals(&self) -> &Option<Vec<comments::Literal>>;
 
     fn word_space(&mut self, w: &str) -> io::Result<()> {
-        word(self.writer(), w)?;
+        try!(word(self.writer(), w));
         space(self.writer())
     }
 
@@ -483,7 +483,7 @@ pub trait PrintState<'a> {
 
     fn hardbreak_if_not_bol(&mut self) -> io::Result<()> {
         if !self.is_bol() {
-            hardbreak(self.writer())?
+            try!(hardbreak(self.writer()))
         }
         Ok(())
     }
@@ -507,11 +507,11 @@ pub trait PrintState<'a> {
     fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()>
         where F: FnMut(&mut Self, &T) -> io::Result<()>,
     {
-        self.rbox(0, b)?;
+        try!(self.rbox(0, b));
         let mut first = true;
         for elt in elts {
-            if first { first = false; } else { self.word_space(",")?; }
-            op(self, elt)?;
+            if first { first = false; } else { try!(self.word_space(",")); }
+            try!(op(self, elt));
         }
         self.end()
     }
@@ -543,7 +543,7 @@ pub trait PrintState<'a> {
             match self.next_comment() {
                 Some(ref cmnt) => {
                     if (*cmnt).pos < pos {
-                        self.print_comment(cmnt)?;
+                        try!(self.print_comment(cmnt));
                         self.cur_cmnt_and_lit().cur_cmnt += 1;
                     } else { break; }
                 }
@@ -558,34 +558,34 @@ pub trait PrintState<'a> {
         match cmnt.style {
             comments::Mixed => {
                 assert_eq!(cmnt.lines.len(), 1);
-                zerobreak(self.writer())?;
-                word(self.writer(), &cmnt.lines[0])?;
+                try!(zerobreak(self.writer()));
+                try!(word(self.writer(), &cmnt.lines[0]));
                 zerobreak(self.writer())
             }
             comments::Isolated => {
-                self.hardbreak_if_not_bol()?;
+                try!(self.hardbreak_if_not_bol());
                 for line in &cmnt.lines {
                     // Don't print empty lines because they will end up as trailing
                     // whitespace
                     if !line.is_empty() {
-                        word(self.writer(), &line[..])?;
+                        try!(word(self.writer(), &line[..]));
                     }
-                    hardbreak(self.writer())?;
+                    try!(hardbreak(self.writer()));
                 }
                 Ok(())
             }
             comments::Trailing => {
-                word(self.writer(), " ")?;
+                try!(word(self.writer(), " "));
                 if cmnt.lines.len() == 1 {
-                    word(self.writer(), &cmnt.lines[0])?;
+                    try!(word(self.writer(), &cmnt.lines[0]));
                     hardbreak(self.writer())
                 } else {
-                    self.ibox(0)?;
+                    try!(self.ibox(0));
                     for line in &cmnt.lines {
                         if !line.is_empty() {
-                            word(self.writer(), &line[..])?;
+                            try!(word(self.writer(), &line[..]));
                         }
-                        hardbreak(self.writer())?;
+                        try!(hardbreak(self.writer()));
                     }
                     self.end()
                 }
@@ -597,7 +597,7 @@ pub trait PrintState<'a> {
                     _ => false
                 };
                 if is_semi || self.is_begin() || self.is_end() {
-                    hardbreak(self.writer())?;
+                    try!(hardbreak(self.writer()));
                 }
                 hardbreak(self.writer())
             }
@@ -619,7 +619,7 @@ pub trait PrintState<'a> {
     }
 
     fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
-        self.maybe_print_comment(lit.span.lo)?;
+        try!(self.maybe_print_comment(lit.span.lo));
         match self.next_lit(lit.span.lo) {
             Some(ref ltrl) => {
                 return word(self.writer(), &(*ltrl).lit);
@@ -725,15 +725,15 @@ pub trait PrintState<'a> {
         let mut count = 0;
         for attr in attrs {
             if attr.node.style == kind {
-                    self.print_attribute_inline(attr, is_inline)?;
-                    if is_inline {
-                        self.nbsp()?;
-                    }
-                    count += 1;
+                try!(self.print_attribute_inline(attr, is_inline));
+                if is_inline {
+                    try!(self.nbsp());
+                }
+                count += 1;
             }
         }
         if count > 0 && trailing_hardbreak && !is_inline {
-            self.hardbreak_if_not_bol()?;
+            try!(self.hardbreak_if_not_bol());
         }
         Ok(())
     }
@@ -745,47 +745,47 @@ pub trait PrintState<'a> {
     fn print_attribute_inline(&mut self, attr: &ast::Attribute,
                               is_inline: bool) -> io::Result<()> {
         if !is_inline {
-            self.hardbreak_if_not_bol()?;
+            try!(self.hardbreak_if_not_bol());
         }
-        self.maybe_print_comment(attr.span.lo)?;
+        try!(self.maybe_print_comment(attr.span.lo));
         if attr.node.is_sugared_doc {
-            word(self.writer(), &attr.value_str().unwrap())?;
+            try!(word(self.writer(), &attr.value_str().unwrap()));
             hardbreak(self.writer())
         } else {
             match attr.node.style {
-                ast::AttrStyle::Inner => word(self.writer(), "#![")?,
-                ast::AttrStyle::Outer => word(self.writer(), "#[")?,
+                ast::AttrStyle::Inner => try!(word(self.writer(), "#![")),
+                ast::AttrStyle::Outer => try!(word(self.writer(), "#[")),
             }
-            self.print_meta_item(&attr.meta())?;
+            try!(self.print_meta_item(&attr.meta()));
             word(self.writer(), "]")
         }
     }
 
     fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
-        self.ibox(INDENT_UNIT)?;
+        try!(self.ibox(INDENT_UNIT));
         match item.node {
             ast::MetaItemKind::Word(ref name) => {
-                word(self.writer(), &name)?;
+                try!(word(self.writer(), &name));
             }
             ast::MetaItemKind::NameValue(ref name, ref value) => {
-                self.word_space(&name[..])?;
-                self.word_space("=")?;
-                self.print_literal(value)?;
+                try!(self.word_space(&name[..]));
+                try!(self.word_space("="));
+                try!(self.print_literal(value));
             }
             ast::MetaItemKind::List(ref name, ref items) => {
-                word(self.writer(), &name)?;
-                self.popen()?;
-                self.commasep(Consistent,
+                try!(word(self.writer(), &name));
+                try!(self.popen());
+                try!(self.commasep(Consistent,
                               &items[..],
-                              |s, i| s.print_meta_item(&i))?;
-                self.pclose()?;
+                              |s, i| s.print_meta_item(&i)));
+                try!(self.pclose());
             }
         }
         self.end()
     }
 
     fn space_if_not_bol(&mut self) -> io::Result<()> {
-        if !self.is_bol() { space(self.writer())?; }
+        if !self.is_bol() { try!(space(self.writer())); }
         Ok(())
     }
 
@@ -821,24 +821,24 @@ impl<'a> State<'a> {
     }
 
     pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
-        word(&mut self.s, w)?;
+        try!(word(&mut self.s, w));
         self.nbsp()
     }
 
     pub fn head(&mut self, w: &str) -> io::Result<()> {
         // outer-box is consistent
-        self.cbox(INDENT_UNIT)?;
+        try!(self.cbox(INDENT_UNIT));
         // head-box is inconsistent
-        self.ibox(w.len() + 1)?;
+        try!(self.ibox(w.len() + 1));
         // keyword that starts the head
         if !w.is_empty() {
-            self.word_nbsp(w)?;
+            try!(self.word_nbsp(w));
         }
         Ok(())
     }
 
     pub fn bopen(&mut self) -> io::Result<()> {
-        word(&mut self.s, "{")?;
+        try!(word(&mut self.s, "{"));
         self.end() // close the head-box
     }
 
@@ -848,11 +848,11 @@ impl<'a> State<'a> {
     }
     pub fn bclose_maybe_open(&mut self, span: codemap::Span,
                              indented: usize, close_box: bool) -> io::Result<()> {
-        self.maybe_print_comment(span.hi)?;
-        self.break_offset_if_not_bol(1, -(indented as isize))?;
-        word(&mut self.s, "}")?;
+        try!(self.maybe_print_comment(span.hi));
+        try!(self.break_offset_if_not_bol(1, -(indented as isize)));
+        try!(word(&mut self.s, "}"));
         if close_box {
-            self.end()?; // close the outer-box
+            try!(self.end()); // close the outer-box
         }
         Ok(())
     }
@@ -885,10 +885,10 @@ impl<'a> State<'a> {
     // Synthesizes a comment that was not textually present in the original source
     // file.
     pub fn synth_comment(&mut self, text: String) -> io::Result<()> {
-        word(&mut self.s, "/*")?;
-        space(&mut self.s)?;
-        word(&mut self.s, &text[..])?;
-        space(&mut self.s)?;
+        try!(word(&mut self.s, "/*"));
+        try!(space(&mut self.s));
+        try!(word(&mut self.s, &text[..]));
+        try!(space(&mut self.s));
         word(&mut self.s, "*/")
     }
 
@@ -902,18 +902,18 @@ impl<'a> State<'a> {
         F: FnMut(&mut State, &T) -> io::Result<()>,
         G: FnMut(&T) -> codemap::Span,
     {
-        self.rbox(0, b)?;
+        try!(self.rbox(0, b));
         let len = elts.len();
         let mut i = 0;
         for elt in elts {
-            self.maybe_print_comment(get_span(elt).hi)?;
-            op(self, elt)?;
+            try!(self.maybe_print_comment(get_span(elt).hi));
+            try!(op(self, elt));
             i += 1;
             if i < len {
-                word(&mut self.s, ",")?;
-                self.maybe_print_trailing_comment(get_span(elt),
-                                                  Some(get_span(&elts[i]).hi))?;
-                self.space_if_not_bol()?;
+                try!(word(&mut self.s, ","));
+                try!(self.maybe_print_trailing_comment(get_span(elt),
+                                                  Some(get_span(&elts[i]).hi)));
+                try!(self.space_if_not_bol());
             }
         }
         self.end()
@@ -926,18 +926,18 @@ impl<'a> State<'a> {
 
     pub fn print_mod(&mut self, _mod: &ast::Mod,
                      attrs: &[ast::Attribute]) -> io::Result<()> {
-        self.print_inner_attributes(attrs)?;
+        try!(self.print_inner_attributes(attrs));
         for item in &_mod.items {
-            self.print_item(&item)?;
+            try!(self.print_item(&item));
         }
         Ok(())
     }
 
     pub fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod,
                              attrs: &[ast::Attribute]) -> io::Result<()> {
-        self.print_inner_attributes(attrs)?;
+        try!(self.print_inner_attributes(attrs));
         for item in &nmod.items {
-            self.print_foreign_item(item)?;
+            try!(self.print_foreign_item(item));
         }
         Ok(())
     }
@@ -945,47 +945,47 @@ impl<'a> State<'a> {
     pub fn print_opt_lifetime(&mut self,
                               lifetime: &Option<ast::Lifetime>) -> io::Result<()> {
         if let Some(l) = *lifetime {
-            self.print_lifetime(&l)?;
-            self.nbsp()?;
+            try!(self.print_lifetime(&l));
+            try!(self.nbsp());
         }
         Ok(())
     }
 
     pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
-        self.maybe_print_comment(ty.span.lo)?;
-        self.ibox(0)?;
+        try!(self.maybe_print_comment(ty.span.lo));
+        try!(self.ibox(0));
         match ty.node {
             ast::TyKind::Vec(ref ty) => {
-                word(&mut self.s, "[")?;
-                self.print_type(&ty)?;
-                word(&mut self.s, "]")?;
+                try!(word(&mut self.s, "["));
+                try!(self.print_type(&ty));
+                try!(word(&mut self.s, "]"));
             }
             ast::TyKind::Ptr(ref mt) => {
-                word(&mut self.s, "*")?;
+                try!(word(&mut self.s, "*"));
                 match mt.mutbl {
-                    ast::Mutability::Mutable => self.word_nbsp("mut")?,
-                    ast::Mutability::Immutable => self.word_nbsp("const")?,
+                    ast::Mutability::Mutable => try!(self.word_nbsp("mut")),
+                    ast::Mutability::Immutable => try!(self.word_nbsp("const")),
                 }
-                self.print_type(&mt.ty)?;
+                try!(self.print_type(&mt.ty));
             }
             ast::TyKind::Rptr(ref lifetime, ref mt) => {
-                word(&mut self.s, "&")?;
-                self.print_opt_lifetime(lifetime)?;
-                self.print_mt(mt)?;
+                try!(word(&mut self.s, "&"));
+                try!(self.print_opt_lifetime(lifetime));
+                try!(self.print_mt(mt));
             }
             ast::TyKind::Tup(ref elts) => {
-                self.popen()?;
-                self.commasep(Inconsistent, &elts[..],
-                              |s, ty| s.print_type(&ty))?;
+                try!(self.popen());
+                try!(self.commasep(Inconsistent, &elts[..],
+                              |s, ty| s.print_type(&ty)));
                 if elts.len() == 1 {
-                    word(&mut self.s, ",")?;
+                    try!(word(&mut self.s, ","));
                 }
-                self.pclose()?;
+                try!(self.pclose());
             }
             ast::TyKind::Paren(ref typ) => {
-                self.popen()?;
-                self.print_type(&typ)?;
-                self.pclose()?;
+                try!(self.popen());
+                try!(self.print_type(&typ));
+                try!(self.pclose());
             }
             ast::TyKind::BareFn(ref f) => {
                 let generics = ast::Generics {
@@ -996,45 +996,45 @@ impl<'a> State<'a> {
                         predicates: Vec::new(),
                     },
                 };
-                self.print_ty_fn(f.abi,
+                try!(self.print_ty_fn(f.abi,
                                  f.unsafety,
                                  &f.decl,
                                  None,
-                                 &generics)?;
+                                 &generics));
             }
             ast::TyKind::Path(None, ref path) => {
-                self.print_path(path, false, 0)?;
+                try!(self.print_path(path, false, 0));
             }
             ast::TyKind::Path(Some(ref qself), ref path) => {
-                self.print_qpath(path, qself, false)?
+                try!(self.print_qpath(path, qself, false))
             }
             ast::TyKind::ObjectSum(ref ty, ref bounds) => {
-                self.print_type(&ty)?;
-                self.print_bounds("+", &bounds[..])?;
+                try!(self.print_type(&ty));
+                try!(self.print_bounds("+", &bounds[..]));
             }
             ast::TyKind::PolyTraitRef(ref bounds) => {
-                self.print_bounds("", &bounds[..])?;
+                try!(self.print_bounds("", &bounds[..]));
             }
             ast::TyKind::FixedLengthVec(ref ty, ref v) => {
-                word(&mut self.s, "[")?;
-                self.print_type(&ty)?;
-                word(&mut self.s, "; ")?;
-                self.print_expr(&v)?;
-                word(&mut self.s, "]")?;
+                try!(word(&mut self.s, "["));
+                try!(self.print_type(&ty));
+                try!(word(&mut self.s, "; "));
+                try!(self.print_expr(&v));
+                try!(word(&mut self.s, "]"));
             }
             ast::TyKind::Typeof(ref e) => {
-                word(&mut self.s, "typeof(")?;
-                self.print_expr(&e)?;
-                word(&mut self.s, ")")?;
+                try!(word(&mut self.s, "typeof("));
+                try!(self.print_expr(&e));
+                try!(word(&mut self.s, ")"));
             }
             ast::TyKind::Infer => {
-                word(&mut self.s, "_")?;
+                try!(word(&mut self.s, "_"));
             }
             ast::TyKind::ImplicitSelf => {
-                unreachable!();
+                try!(word(&mut self.s, "Self"));
             }
             ast::TyKind::Mac(ref m) => {
-                self.print_mac(m, token::Paren)?;
+                try!(self.print_mac(m, token::Paren));
             }
         }
         self.end()
@@ -1042,30 +1042,30 @@ impl<'a> State<'a> {
 
     pub fn print_foreign_item(&mut self,
                               item: &ast::ForeignItem) -> io::Result<()> {
-        self.hardbreak_if_not_bol()?;
-        self.maybe_print_comment(item.span.lo)?;
-        self.print_outer_attributes(&item.attrs)?;
+        try!(self.hardbreak_if_not_bol());
+        try!(self.maybe_print_comment(item.span.lo));
+        try!(self.print_outer_attributes(&item.attrs));
         match item.node {
             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
-                self.head("")?;
-                self.print_fn(decl, ast::Unsafety::Normal,
+                try!(self.head(""));
+                try!(self.print_fn(decl, ast::Unsafety::Normal,
                               ast::Constness::NotConst,
                               Abi::Rust, Some(item.ident),
-                              generics, &item.vis)?;
-                self.end()?; // end head-ibox
-                word(&mut self.s, ";")?;
+                              generics, &item.vis));
+                try!(self.end()); // end head-ibox
+                try!(word(&mut self.s, ";"));
                 self.end() // end the outer fn box
             }
             ast::ForeignItemKind::Static(ref t, m) => {
-                self.head(&visibility_qualified(&item.vis, "static"))?;
+                try!(self.head(&visibility_qualified(&item.vis, "static")));
                 if m {
-                    self.word_space("mut")?;
+                    try!(self.word_space("mut"));
                 }
-                self.print_ident(item.ident)?;
-                self.word_space(":")?;
-                self.print_type(&t)?;
-                word(&mut self.s, ";")?;
-                self.end()?; // end the head-ibox
+                try!(self.print_ident(item.ident));
+                try!(self.word_space(":"));
+                try!(self.print_type(&t));
+                try!(word(&mut self.s, ";"));
+                try!(self.end()); // end the head-ibox
                 self.end() // end the outer cbox
             }
         }
@@ -1078,15 +1078,15 @@ impl<'a> State<'a> {
                               vis: &ast::Visibility)
                               -> io::Result<()>
     {
-        word(&mut self.s, &visibility_qualified(vis, ""))?;
-        self.word_space("const")?;
-        self.print_ident(ident)?;
-        self.word_space(":")?;
-        self.print_type(ty)?;
+        try!(word(&mut self.s, &visibility_qualified(vis, "")));
+        try!(self.word_space("const"));
+        try!(self.print_ident(ident));
+        try!(self.word_space(":"));
+        try!(self.print_type(ty));
         if let Some(expr) = default {
-            space(&mut self.s)?;
-            self.word_space("=")?;
-            self.print_expr(expr)?;
+            try!(space(&mut self.s));
+            try!(self.word_space("="));
+            try!(self.print_expr(expr));
         }
         word(&mut self.s, ";")
     }
@@ -1096,83 +1096,83 @@ impl<'a> State<'a> {
                              bounds: Option<&ast::TyParamBounds>,
                              ty: Option<&ast::Ty>)
                              -> io::Result<()> {
-        self.word_space("type")?;
-        self.print_ident(ident)?;
+        try!(self.word_space("type"));
+        try!(self.print_ident(ident));
         if let Some(bounds) = bounds {
-            self.print_bounds(":", bounds)?;
+            try!(self.print_bounds(":", bounds));
         }
         if let Some(ty) = ty {
-            space(&mut self.s)?;
-            self.word_space("=")?;
-            self.print_type(ty)?;
+            try!(space(&mut self.s));
+            try!(self.word_space("="));
+            try!(self.print_type(ty));
         }
         word(&mut self.s, ";")
     }
 
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
-        self.hardbreak_if_not_bol()?;
-        self.maybe_print_comment(item.span.lo)?;
-        self.print_outer_attributes(&item.attrs)?;
-        self.ann.pre(self, NodeItem(item))?;
+        try!(self.hardbreak_if_not_bol());
+        try!(self.maybe_print_comment(item.span.lo));
+        try!(self.print_outer_attributes(&item.attrs));
+        try!(self.ann.pre(self, NodeItem(item)));
         match item.node {
             ast::ItemKind::ExternCrate(ref optional_path) => {
-                self.head(&visibility_qualified(&item.vis, "extern crate"))?;
+                try!(self.head(&visibility_qualified(&item.vis, "extern crate")));
                 if let Some(p) = *optional_path {
                     let val = p.as_str();
                     if val.contains("-") {
-                        self.print_string(&val, ast::StrStyle::Cooked)?;
+                        try!(self.print_string(&val, ast::StrStyle::Cooked));
                     } else {
-                        self.print_name(p)?;
+                        try!(self.print_name(p));
                     }
-                    space(&mut self.s)?;
-                    word(&mut self.s, "as")?;
-                    space(&mut self.s)?;
+                    try!(space(&mut self.s));
+                    try!(word(&mut self.s, "as"));
+                    try!(space(&mut self.s));
                 }
-                self.print_ident(item.ident)?;
-                word(&mut self.s, ";")?;
-                self.end()?; // end inner head-block
-                self.end()?; // end outer head-block
+                try!(self.print_ident(item.ident));
+                try!(word(&mut self.s, ";"));
+                try!(self.end()); // end inner head-block
+                try!(self.end()); // end outer head-block
             }
             ast::ItemKind::Use(ref vp) => {
-                self.head(&visibility_qualified(&item.vis, "use"))?;
-                self.print_view_path(&vp)?;
-                word(&mut self.s, ";")?;
-                self.end()?; // end inner head-block
-                self.end()?; // end outer head-block
+                try!(self.head(&visibility_qualified(&item.vis, "use")));
+                try!(self.print_view_path(&vp));
+                try!(word(&mut self.s, ";"));
+                try!(self.end()); // end inner head-block
+                try!(self.end()); // end outer head-block
             }
             ast::ItemKind::Static(ref ty, m, ref expr) => {
-                self.head(&visibility_qualified(&item.vis, "static"))?;
+                try!(self.head(&visibility_qualified(&item.vis, "static")));
                 if m == ast::Mutability::Mutable {
-                    self.word_space("mut")?;
+                    try!(self.word_space("mut"));
                 }
-                self.print_ident(item.ident)?;
-                self.word_space(":")?;
-                self.print_type(&ty)?;
-                space(&mut self.s)?;
-                self.end()?; // end the head-ibox
+                try!(self.print_ident(item.ident));
+                try!(self.word_space(":"));
+                try!(self.print_type(&ty));
+                try!(space(&mut self.s));
+                try!(self.end()); // end the head-ibox
 
-                self.word_space("=")?;
-                self.print_expr(&expr)?;
-                word(&mut self.s, ";")?;
-                self.end()?; // end the outer cbox
+                try!(self.word_space("="));
+                try!(self.print_expr(&expr));
+                try!(word(&mut self.s, ";"));
+                try!(self.end()); // end the outer cbox
             }
             ast::ItemKind::Const(ref ty, ref expr) => {
-                self.head(&visibility_qualified(&item.vis, "const"))?;
-                self.print_ident(item.ident)?;
-                self.word_space(":")?;
-                self.print_type(&ty)?;
-                space(&mut self.s)?;
-                self.end()?; // end the head-ibox
-
-                self.word_space("=")?;
-                self.print_expr(&expr)?;
-                word(&mut self.s, ";")?;
-                self.end()?; // end the outer cbox
+                try!(self.head(&visibility_qualified(&item.vis, "const")));
+                try!(self.print_ident(item.ident));
+                try!(self.word_space(":"));
+                try!(self.print_type(&ty));
+                try!(space(&mut self.s));
+                try!(self.end()); // end the head-ibox
+
+                try!(self.word_space("="));
+                try!(self.print_expr(&expr));
+                try!(word(&mut self.s, ";"));
+                try!(self.end()); // end the outer cbox
             }
             ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
-                self.head("")?;
-                self.print_fn(
+                try!(self.head(""));
+                try!(self.print_fn(
                     decl,
                     unsafety,
                     constness,
@@ -1180,65 +1180,65 @@ impl<'a> State<'a> {
                     Some(item.ident),
                     typarams,
                     &item.vis
-                )?;
-                word(&mut self.s, " ")?;
-                self.print_block_with_attrs(&body, &item.attrs)?;
+                ));
+                try!(word(&mut self.s, " "));
+                try!(self.print_block_with_attrs(&body, &item.attrs));
             }
             ast::ItemKind::Mod(ref _mod) => {
-                self.head(&visibility_qualified(&item.vis, "mod"))?;
-                self.print_ident(item.ident)?;
-                self.nbsp()?;
-                self.bopen()?;
-                self.print_mod(_mod, &item.attrs)?;
-                self.bclose(item.span)?;
+                try!(self.head(&visibility_qualified(&item.vis, "mod")));
+                try!(self.print_ident(item.ident));
+                try!(self.nbsp());
+                try!(self.bopen());
+                try!(self.print_mod(_mod, &item.attrs));
+                try!(self.bclose(item.span));
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head("extern")?;
-                self.word_nbsp(&nmod.abi.to_string())?;
-                self.bopen()?;
-                self.print_foreign_mod(nmod, &item.attrs)?;
-                self.bclose(item.span)?;
+                try!(self.head("extern"));
+                try!(self.word_nbsp(&nmod.abi.to_string()));
+                try!(self.bopen());
+                try!(self.print_foreign_mod(nmod, &item.attrs));
+                try!(self.bclose(item.span));
             }
             ast::ItemKind::Ty(ref ty, ref params) => {
-                self.ibox(INDENT_UNIT)?;
-                self.ibox(0)?;
-                self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
-                self.print_ident(item.ident)?;
-                self.print_generics(params)?;
-                self.end()?; // end the inner ibox
-
-                self.print_where_clause(&params.where_clause)?;
-                space(&mut self.s)?;
-                self.word_space("=")?;
-                self.print_type(&ty)?;
-                word(&mut self.s, ";")?;
-                self.end()?; // end the outer ibox
+                try!(self.ibox(INDENT_UNIT));
+                try!(self.ibox(0));
+                try!(self.word_nbsp(&visibility_qualified(&item.vis, "type")));
+                try!(self.print_ident(item.ident));
+                try!(self.print_generics(params));
+                try!(self.end()); // end the inner ibox
+
+                try!(self.print_where_clause(&params.where_clause));
+                try!(space(&mut self.s));
+                try!(self.word_space("="));
+                try!(self.print_type(&ty));
+                try!(word(&mut self.s, ";"));
+                try!(self.end()); // end the outer ibox
             }
             ast::ItemKind::Enum(ref enum_definition, ref params) => {
-                self.print_enum_def(
+                try!(self.print_enum_def(
                     enum_definition,
                     params,
                     item.ident,
                     item.span,
                     &item.vis
-                )?;
+                ));
             }
             ast::ItemKind::Struct(ref struct_def, ref generics) => {
-                self.head(&visibility_qualified(&item.vis, "struct"))?;
-                self.print_struct(&struct_def, generics, item.ident, item.span, true)?;
+                try!(self.head(&visibility_qualified(&item.vis, "struct")));
+                try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
             }
 
             ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
-                self.head("")?;
-                self.print_visibility(&item.vis)?;
-                self.print_unsafety(unsafety)?;
-                self.word_nbsp("impl")?;
-                self.print_trait_ref(trait_ref)?;
-                space(&mut self.s)?;
-                self.word_space("for")?;
-                self.word_space("..")?;
-                self.bopen()?;
-                self.bclose(item.span)?;
+                try!(self.head(""));
+                try!(self.print_visibility(&item.vis));
+                try!(self.print_unsafety(unsafety));
+                try!(self.word_nbsp("impl"));
+                try!(self.print_trait_ref(trait_ref));
+                try!(space(&mut self.s));
+                try!(self.word_space("for"));
+                try!(self.word_space(".."));
+                try!(self.bopen());
+                try!(self.bclose(item.span));
             }
             ast::ItemKind::Impl(unsafety,
                           polarity,
@@ -1246,80 +1246,80 @@ impl<'a> State<'a> {
                           ref opt_trait,
                           ref ty,
                           ref impl_items) => {
-                self.head("")?;
-                self.print_visibility(&item.vis)?;
-                self.print_unsafety(unsafety)?;
-                self.word_nbsp("impl")?;
+                try!(self.head(""));
+                try!(self.print_visibility(&item.vis));
+                try!(self.print_unsafety(unsafety));
+                try!(self.word_nbsp("impl"));
 
                 if generics.is_parameterized() {
-                    self.print_generics(generics)?;
-                    space(&mut self.s)?;
+                    try!(self.print_generics(generics));
+                    try!(space(&mut self.s));
                 }
 
                 match polarity {
                     ast::ImplPolarity::Negative => {
-                        word(&mut self.s, "!")?;
+                        try!(word(&mut self.s, "!"));
                     },
                     _ => {}
                 }
 
                 match *opt_trait {
                     Some(ref t) => {
-                        self.print_trait_ref(t)?;
-                        space(&mut self.s)?;
-                        self.word_space("for")?;
+                        try!(self.print_trait_ref(t));
+                        try!(space(&mut self.s));
+                        try!(self.word_space("for"));
                     }
                     None => {}
                 }
 
-                self.print_type(&ty)?;
-                self.print_where_clause(&generics.where_clause)?;
+                try!(self.print_type(&ty));
+                try!(self.print_where_clause(&generics.where_clause));
 
-                space(&mut self.s)?;
-                self.bopen()?;
-                self.print_inner_attributes(&item.attrs)?;
+                try!(space(&mut self.s));
+                try!(self.bopen());
+                try!(self.print_inner_attributes(&item.attrs));
                 for impl_item in impl_items {
-                    self.print_impl_item(impl_item)?;
+                    try!(self.print_impl_item(impl_item));
                 }
-                self.bclose(item.span)?;
+                try!(self.bclose(item.span));
             }
             ast::ItemKind::Trait(unsafety, ref generics, ref bounds, ref trait_items) => {
-                self.head("")?;
-                self.print_visibility(&item.vis)?;
-                self.print_unsafety(unsafety)?;
-                self.word_nbsp("trait")?;
-                self.print_ident(item.ident)?;
-                self.print_generics(generics)?;
+                try!(self.head(""));
+                try!(self.print_visibility(&item.vis));
+                try!(self.print_unsafety(unsafety));
+                try!(self.word_nbsp("trait"));
+                try!(self.print_ident(item.ident));
+                try!(self.print_generics(generics));
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 for b in bounds.iter() {
                     if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        space(&mut self.s)?;
-                        self.word_space("for ?")?;
-                        self.print_trait_ref(&ptr.trait_ref)?;
+                        try!(space(&mut self.s));
+                        try!(self.word_space("for ?"));
+                        try!(self.print_trait_ref(&ptr.trait_ref));
                     } else {
                         real_bounds.push(b.clone());
                     }
                 }
-                self.print_bounds(":", &real_bounds[..])?;
-                self.print_where_clause(&generics.where_clause)?;
-                word(&mut self.s, " ")?;
-                self.bopen()?;
+                try!(self.print_bounds(":", &real_bounds[..]));
+                try!(self.print_where_clause(&generics.where_clause));
+                try!(word(&mut self.s, " "));
+                try!(self.bopen());
                 for trait_item in trait_items {
-                    self.print_trait_item(trait_item)?;
+                    try!(self.print_trait_item(trait_item));
                 }
-                self.bclose(item.span)?;
+                try!(self.bclose(item.span));
             }
             ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
-                self.print_visibility(&item.vis)?;
-                self.print_path(&node.path, false, 0)?;
-                word(&mut self.s, "! ")?;
-                self.print_ident(item.ident)?;
-                self.cbox(INDENT_UNIT)?;
-                self.popen()?;
-                self.print_tts(&node.tts[..])?;
-                self.pclose()?;
-                word(&mut self.s, ";")?;
-                self.end()?;
+                try!(self.print_visibility(&item.vis));
+                try!(self.print_path(&node.path, false, 0));
+                try!(word(&mut self.s, "! "));
+                try!(self.print_ident(item.ident));
+                try!(self.cbox(INDENT_UNIT));
+                try!(self.popen());
+                try!(self.print_tts(&node.tts[..]));
+                try!(self.pclose());
+                try!(word(&mut self.s, ";"));
+                try!(self.end());
             }
         }
         self.ann.post(self, NodeItem(item))
@@ -1331,22 +1331,22 @@ impl<'a> State<'a> {
 
     fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> {
         if !lifetimes.is_empty() {
-            word(&mut self.s, "for<")?;
+            try!(word(&mut self.s, "for<"));
             let mut comma = false;
             for lifetime_def in lifetimes {
                 if comma {
-                    self.word_space(",")?
+                    try!(self.word_space(","))
                 }
-                self.print_lifetime_def(lifetime_def)?;
+                try!(self.print_lifetime_def(lifetime_def));
                 comma = true;
             }
-            word(&mut self.s, ">")?;
+            try!(word(&mut self.s, ">"));
         }
         Ok(())
     }
 
     fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> io::Result<()> {
-        self.print_formal_lifetime_list(&t.bound_lifetimes)?;
+        try!(self.print_formal_lifetime_list(&t.bound_lifetimes));
         self.print_trait_ref(&t.trait_ref)
     }
 
@@ -1354,27 +1354,27 @@ impl<'a> State<'a> {
                           generics: &ast::Generics, ident: ast::Ident,
                           span: codemap::Span,
                           visibility: &ast::Visibility) -> io::Result<()> {
-        self.head(&visibility_qualified(visibility, "enum"))?;
-        self.print_ident(ident)?;
-        self.print_generics(generics)?;
-        self.print_where_clause(&generics.where_clause)?;
-        space(&mut self.s)?;
+        try!(self.head(&visibility_qualified(visibility, "enum")));
+        try!(self.print_ident(ident));
+        try!(self.print_generics(generics));
+        try!(self.print_where_clause(&generics.where_clause));
+        try!(space(&mut self.s));
         self.print_variants(&enum_definition.variants, span)
     }
 
     pub fn print_variants(&mut self,
                           variants: &[ast::Variant],
                           span: codemap::Span) -> io::Result<()> {
-        self.bopen()?;
+        try!(self.bopen());
         for v in variants {
-            self.space_if_not_bol()?;
-            self.maybe_print_comment(v.span.lo)?;
-            self.print_outer_attributes(&v.node.attrs)?;
-            self.ibox(INDENT_UNIT)?;
-            self.print_variant(v)?;
-            word(&mut self.s, ",")?;
-            self.end()?;
-            self.maybe_print_trailing_comment(v.span, None)?;
+            try!(self.space_if_not_bol());
+            try!(self.maybe_print_comment(v.span.lo));
+            try!(self.print_outer_attributes(&v.node.attrs));
+            try!(self.ibox(INDENT_UNIT));
+            try!(self.print_variant(v));
+            try!(word(&mut self.s, ","));
+            try!(self.end());
+            try!(self.maybe_print_trailing_comment(v.span, None));
         }
         self.bclose(span)
     }
@@ -1395,42 +1395,43 @@ impl<'a> State<'a> {
                         ident: ast::Ident,
                         span: codemap::Span,
                         print_finalizer: bool) -> io::Result<()> {
-        self.print_ident(ident)?;
-        self.print_generics(generics)?;
+        try!(self.print_ident(ident));
+        try!(self.print_generics(generics));
         if !struct_def.is_struct() {
             if struct_def.is_tuple() {
-                self.popen()?;
-                self.commasep(
+                try!(self.popen());
+                try!(self.commasep(
                     Inconsistent, struct_def.fields(),
                     |s, field| {
-                        s.print_visibility(&field.vis)?;
-                        s.maybe_print_comment(field.span.lo)?;
+                        try!(s.maybe_print_comment(field.span.lo));
+                        try!(s.print_outer_attributes(&field.attrs));
+                        try!(s.print_visibility(&field.vis));
                         s.print_type(&field.ty)
                     }
-                )?;
-                self.pclose()?;
+                ));
+                try!(self.pclose());
             }
-            self.print_where_clause(&generics.where_clause)?;
+            try!(self.print_where_clause(&generics.where_clause));
             if print_finalizer {
-                word(&mut self.s, ";")?;
+                try!(word(&mut self.s, ";"));
             }
-            self.end()?;
+            try!(self.end());
             self.end() // close the outer-box
         } else {
-            self.print_where_clause(&generics.where_clause)?;
-            self.nbsp()?;
-            self.bopen()?;
-            self.hardbreak_if_not_bol()?;
+            try!(self.print_where_clause(&generics.where_clause));
+            try!(self.nbsp());
+            try!(self.bopen());
+            try!(self.hardbreak_if_not_bol());
 
             for field in struct_def.fields() {
-                self.hardbreak_if_not_bol()?;
-                self.maybe_print_comment(field.span.lo)?;
-                self.print_outer_attributes(&field.attrs)?;
-                self.print_visibility(&field.vis)?;
-                self.print_ident(field.ident.unwrap())?;
-                self.word_nbsp(":")?;
-                self.print_type(&field.ty)?;
-                word(&mut self.s, ",")?;
+                try!(self.hardbreak_if_not_bol());
+                try!(self.maybe_print_comment(field.span.lo));
+                try!(self.print_outer_attributes(&field.attrs));
+                try!(self.print_visibility(&field.vis));
+                try!(self.print_ident(field.ident.unwrap()));
+                try!(self.word_nbsp(":"));
+                try!(self.print_type(&field.ty));
+                try!(word(&mut self.s, ","));
             }
 
             self.bclose(span)
@@ -1447,7 +1448,7 @@ impl<'a> State<'a> {
     pub fn print_tt(&mut self, tt: &ast::TokenTree) -> io::Result<()> {
         match *tt {
             TokenTree::Token(_, ref tk) => {
-                word(&mut self.s, &token_to_string(tk))?;
+                try!(word(&mut self.s, &token_to_string(tk)));
                 match *tk {
                     parse::token::DocComment(..) => {
                         hardbreak(&mut self.s)
@@ -1456,21 +1457,21 @@ impl<'a> State<'a> {
                 }
             }
             TokenTree::Delimited(_, ref delimed) => {
-                word(&mut self.s, &token_to_string(&delimed.open_token()))?;
-                space(&mut self.s)?;
-                self.print_tts(&delimed.tts)?;
-                space(&mut self.s)?;
+                try!(word(&mut self.s, &token_to_string(&delimed.open_token())));
+                try!(space(&mut self.s));
+                try!(self.print_tts(&delimed.tts));
+                try!(space(&mut self.s));
                 word(&mut self.s, &token_to_string(&delimed.close_token()))
             },
             TokenTree::Sequence(_, ref seq) => {
-                word(&mut self.s, "$(")?;
+                try!(word(&mut self.s, "$("));
                 for tt_elt in &seq.tts {
-                    self.print_tt(tt_elt)?;
+                    try!(self.print_tt(tt_elt));
                 }
-                word(&mut self.s, ")")?;
+                try!(word(&mut self.s, ")"));
                 match seq.separator {
                     Some(ref tk) => {
-                        word(&mut self.s, &token_to_string(tk))?;
+                        try!(word(&mut self.s, &token_to_string(tk)));
                     }
                     None => {},
                 }
@@ -1483,24 +1484,24 @@ impl<'a> State<'a> {
     }
 
     pub fn print_tts(&mut self, tts: &[ast::TokenTree]) -> io::Result<()> {
-        self.ibox(0)?;
+        try!(self.ibox(0));
         for (i, tt) in tts.iter().enumerate() {
             if i != 0 {
-                space(&mut self.s)?;
+                try!(space(&mut self.s));
             }
-            self.print_tt(tt)?;
+            try!(self.print_tt(tt));
         }
         self.end()
     }
 
     pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> {
-        self.head("")?;
+        try!(self.head(""));
         let generics = ast::Generics::default();
-        self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
+        try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false));
         match v.node.disr_expr {
             Some(ref d) => {
-                space(&mut self.s)?;
-                self.word_space("=")?;
+                try!(space(&mut self.s));
+                try!(self.word_space("="));
                 self.print_expr(&d)
             }
             _ => Ok(())
@@ -1523,103 +1524,103 @@ impl<'a> State<'a> {
 
     pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
                             -> io::Result<()> {
-        self.ann.pre(self, NodeSubItem(ti.id))?;
-        self.hardbreak_if_not_bol()?;
-        self.maybe_print_comment(ti.span.lo)?;
-        self.print_outer_attributes(&ti.attrs)?;
+        try!(self.ann.pre(self, NodeSubItem(ti.id)));
+        try!(self.hardbreak_if_not_bol());
+        try!(self.maybe_print_comment(ti.span.lo));
+        try!(self.print_outer_attributes(&ti.attrs));
         match ti.node {
             ast::TraitItemKind::Const(ref ty, ref default) => {
-                self.print_associated_const(ti.ident, &ty,
+                try!(self.print_associated_const(ti.ident, &ty,
                                             default.as_ref().map(|expr| &**expr),
-                                            &ast::Visibility::Inherited)?;
+                                            &ast::Visibility::Inherited));
             }
             ast::TraitItemKind::Method(ref sig, ref body) => {
                 if body.is_some() {
-                    self.head("")?;
+                    try!(self.head(""));
                 }
-                self.print_method_sig(ti.ident, sig, &ast::Visibility::Inherited)?;
+                try!(self.print_method_sig(ti.ident, sig, &ast::Visibility::Inherited));
                 if let Some(ref body) = *body {
-                    self.nbsp()?;
-                    self.print_block_with_attrs(body, &ti.attrs)?;
+                    try!(self.nbsp());
+                    try!(self.print_block_with_attrs(body, &ti.attrs));
                 } else {
-                    word(&mut self.s, ";")?;
+                    try!(word(&mut self.s, ";"));
                 }
             }
             ast::TraitItemKind::Type(ref bounds, ref default) => {
-                self.print_associated_type(ti.ident, Some(bounds),
-                                           default.as_ref().map(|ty| &**ty))?;
+                try!(self.print_associated_type(ti.ident, Some(bounds),
+                                           default.as_ref().map(|ty| &**ty)));
             }
         }
         self.ann.post(self, NodeSubItem(ti.id))
     }
 
     pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
-        self.ann.pre(self, NodeSubItem(ii.id))?;
-        self.hardbreak_if_not_bol()?;
-        self.maybe_print_comment(ii.span.lo)?;
-        self.print_outer_attributes(&ii.attrs)?;
+        try!(self.ann.pre(self, NodeSubItem(ii.id)));
+        try!(self.hardbreak_if_not_bol());
+        try!(self.maybe_print_comment(ii.span.lo));
+        try!(self.print_outer_attributes(&ii.attrs));
         if let ast::Defaultness::Default = ii.defaultness {
-            self.word_nbsp("default")?;
+            try!(self.word_nbsp("default"));
         }
         match ii.node {
             ast::ImplItemKind::Const(ref ty, ref expr) => {
-                self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?;
+                try!(self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis));
             }
             ast::ImplItemKind::Method(ref sig, ref body) => {
-                self.head("")?;
-                self.print_method_sig(ii.ident, sig, &ii.vis)?;
-                self.nbsp()?;
-                self.print_block_with_attrs(body, &ii.attrs)?;
+                try!(self.head(""));
+                try!(self.print_method_sig(ii.ident, sig, &ii.vis));
+                try!(self.nbsp());
+                try!(self.print_block_with_attrs(body, &ii.attrs));
             }
             ast::ImplItemKind::Type(ref ty) => {
-                self.print_associated_type(ii.ident, None, Some(ty))?;
+                try!(self.print_associated_type(ii.ident, None, Some(ty)));
             }
             ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => {
                 // code copied from ItemKind::Mac:
-                self.print_path(&node.path, false, 0)?;
-                word(&mut self.s, "! ")?;
-                self.cbox(INDENT_UNIT)?;
-                self.popen()?;
-                self.print_tts(&node.tts[..])?;
-                self.pclose()?;
-                word(&mut self.s, ";")?;
-                self.end()?
+                try!(self.print_path(&node.path, false, 0));
+                try!(word(&mut self.s, "! "));
+                try!(self.cbox(INDENT_UNIT));
+                try!(self.popen());
+                try!(self.print_tts(&node.tts[..]));
+                try!(self.pclose());
+                try!(word(&mut self.s, ";"));
+                try!(self.end())
             }
         }
         self.ann.post(self, NodeSubItem(ii.id))
     }
 
     pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> {
-        self.maybe_print_comment(st.span.lo)?;
+        try!(self.maybe_print_comment(st.span.lo));
         match st.node {
             ast::StmtKind::Decl(ref decl, _) => {
-                self.print_decl(&decl)?;
+                try!(self.print_decl(&decl));
             }
             ast::StmtKind::Expr(ref expr, _) => {
-                self.space_if_not_bol()?;
-                self.print_expr_outer_attr_style(&expr, false)?;
+                try!(self.space_if_not_bol());
+                try!(self.print_expr_outer_attr_style(&expr, false));
             }
             ast::StmtKind::Semi(ref expr, _) => {
-                self.space_if_not_bol()?;
-                self.print_expr_outer_attr_style(&expr, false)?;
-                word(&mut self.s, ";")?;
+                try!(self.space_if_not_bol());
+                try!(self.print_expr_outer_attr_style(&expr, false));
+                try!(word(&mut self.s, ";"));
             }
             ast::StmtKind::Mac(ref mac, style, ref attrs) => {
-                self.space_if_not_bol()?;
-                self.print_outer_attributes(attrs.as_attr_slice())?;
+                try!(self.space_if_not_bol());
+                try!(self.print_outer_attributes(attrs.as_attr_slice()));
                 let delim = match style {
                     ast::MacStmtStyle::Braces => token::Brace,
                     _ => token::Paren
                 };
-                self.print_mac(&mac, delim)?;
+                try!(self.print_mac(&mac, delim));
                 match style {
                     ast::MacStmtStyle::Braces => {}
-                    _ => word(&mut self.s, ";")?,
+                    _ => try!(word(&mut self.s, ";")),
                 }
             }
         }
         if parse::classify::stmt_ends_with_semi(&st.node) {
-            word(&mut self.s, ";")?;
+            try!(word(&mut self.s, ";"));
         }
         self.maybe_print_trailing_comment(st.span, None)
     }
@@ -1655,27 +1656,27 @@ impl<'a> State<'a> {
                                       attrs: &[ast::Attribute],
                                       close_box: bool) -> io::Result<()> {
         match blk.rules {
-            BlockCheckMode::Unsafe(..) => self.word_space("unsafe")?,
+            BlockCheckMode::Unsafe(..) => try!(self.word_space("unsafe")),
             BlockCheckMode::Default => ()
         }
-        self.maybe_print_comment(blk.span.lo)?;
-        self.ann.pre(self, NodeBlock(blk))?;
-        self.bopen()?;
+        try!(self.maybe_print_comment(blk.span.lo));
+        try!(self.ann.pre(self, NodeBlock(blk)));
+        try!(self.bopen());
 
-        self.print_inner_attributes(attrs)?;
+        try!(self.print_inner_attributes(attrs));
 
         for st in &blk.stmts {
-            self.print_stmt(st)?;
+            try!(self.print_stmt(st));
         }
         match blk.expr {
             Some(ref expr) => {
-                self.space_if_not_bol()?;
-                self.print_expr_outer_attr_style(&expr, false)?;
-                self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))?;
+                try!(self.space_if_not_bol());
+                try!(self.print_expr_outer_attr_style(&expr, false));
+                try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
             }
             _ => ()
         }
-        self.bclose_maybe_open(blk.span, indented, close_box)?;
+        try!(self.bclose_maybe_open(blk.span, indented, close_box));
         self.ann.post(self, NodeBlock(blk))
     }
 
@@ -1685,32 +1686,32 @@ impl<'a> State<'a> {
                 match _else.node {
                     // "another else-if"
                     ast::ExprKind::If(ref i, ref then, ref e) => {
-                        self.cbox(INDENT_UNIT - 1)?;
-                        self.ibox(0)?;
-                        word(&mut self.s, " else if ")?;
-                        self.print_expr(&i)?;
-                        space(&mut self.s)?;
-                        self.print_block(&then)?;
+                        try!(self.cbox(INDENT_UNIT - 1));
+                        try!(self.ibox(0));
+                        try!(word(&mut self.s, " else if "));
+                        try!(self.print_expr(&i));
+                        try!(space(&mut self.s));
+                        try!(self.print_block(&then));
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "another else-if-let"
                     ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => {
-                        self.cbox(INDENT_UNIT - 1)?;
-                        self.ibox(0)?;
-                        word(&mut self.s, " else if let ")?;
-                        self.print_pat(&pat)?;
-                        space(&mut self.s)?;
-                        self.word_space("=")?;
-                        self.print_expr(&expr)?;
-                        space(&mut self.s)?;
-                        self.print_block(&then)?;
+                        try!(self.cbox(INDENT_UNIT - 1));
+                        try!(self.ibox(0));
+                        try!(word(&mut self.s, " else if let "));
+                        try!(self.print_pat(&pat));
+                        try!(space(&mut self.s));
+                        try!(self.word_space("="));
+                        try!(self.print_expr(&expr));
+                        try!(space(&mut self.s));
+                        try!(self.print_block(&then));
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "final else"
                     ast::ExprKind::Block(ref b) => {
-                        self.cbox(INDENT_UNIT - 1)?;
-                        self.ibox(0)?;
-                        word(&mut self.s, " else ")?;
+                        try!(self.cbox(INDENT_UNIT - 1));
+                        try!(self.ibox(0));
+                        try!(word(&mut self.s, " else "));
                         self.print_block(&b)
                     }
                     // BLEAH, constraints would be great here
@@ -1725,38 +1726,38 @@ impl<'a> State<'a> {
 
     pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
                     elseopt: Option<&ast::Expr>) -> io::Result<()> {
-        self.head("if")?;
-        self.print_expr(test)?;
-        space(&mut self.s)?;
-        self.print_block(blk)?;
+        try!(self.head("if"));
+        try!(self.print_expr(test));
+        try!(space(&mut self.s));
+        try!(self.print_block(blk));
         self.print_else(elseopt)
     }
 
     pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
                         elseopt: Option<&ast::Expr>) -> io::Result<()> {
-        self.head("if let")?;
-        self.print_pat(pat)?;
-        space(&mut self.s)?;
-        self.word_space("=")?;
-        self.print_expr(expr)?;
-        space(&mut self.s)?;
-        self.print_block(blk)?;
+        try!(self.head("if let"));
+        try!(self.print_pat(pat));
+        try!(space(&mut self.s));
+        try!(self.word_space("="));
+        try!(self.print_expr(expr));
+        try!(space(&mut self.s));
+        try!(self.print_block(blk));
         self.print_else(elseopt)
     }
 
     pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
                      -> io::Result<()> {
-        self.print_path(&m.node.path, false, 0)?;
-        word(&mut self.s, "!")?;
+        try!(self.print_path(&m.node.path, false, 0));
+        try!(word(&mut self.s, "!"));
         match delim {
-            token::Paren => self.popen()?,
-            token::Bracket => word(&mut self.s, "[")?,
+            token::Paren => try!(self.popen()),
+            token::Bracket => try!(word(&mut self.s, "[")),
             token::Brace => {
-                self.head("")?;
-                self.bopen()?;
+                try!(self.head(""));
+                try!(self.bopen());
             }
         }
-        self.print_tts(&m.node.tts)?;
+        try!(self.print_tts(&m.node.tts));
         match delim {
             token::Paren => self.pclose(),
             token::Bracket => word(&mut self.s, "]"),
@@ -1766,8 +1767,8 @@ impl<'a> State<'a> {
 
 
     fn print_call_post(&mut self, args: &[P<ast::Expr>]) -> io::Result<()> {
-        self.popen()?;
-        self.commasep_exprs(Inconsistent, args)?;
+        try!(self.popen());
+        try!(self.commasep_exprs(Inconsistent, args));
         self.pclose()
     }
 
@@ -1789,11 +1790,11 @@ impl<'a> State<'a> {
     pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> io::Result<()> {
         let needs_par = needs_parentheses(expr);
         if needs_par {
-            self.popen()?;
+            try!(self.popen());
         }
-        self.print_expr(expr)?;
+        try!(self.print_expr(expr));
         if needs_par {
-            self.pclose()?;
+            try!(self.pclose());
         }
         Ok(())
     }
@@ -1801,19 +1802,19 @@ impl<'a> State<'a> {
     fn print_expr_in_place(&mut self,
                            place: &ast::Expr,
                            expr: &ast::Expr) -> io::Result<()> {
-        self.print_expr_maybe_paren(place)?;
-        space(&mut self.s)?;
-        self.word_space("<-")?;
+        try!(self.print_expr_maybe_paren(place));
+        try!(space(&mut self.s));
+        try!(self.word_space("<-"));
         self.print_expr_maybe_paren(expr)
     }
 
     fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>],
                       attrs: &[Attribute]) -> io::Result<()> {
-        self.ibox(INDENT_UNIT)?;
-        word(&mut self.s, "[")?;
-        self.print_inner_attributes_inline(attrs)?;
-        self.commasep_exprs(Inconsistent, &exprs[..])?;
-        word(&mut self.s, "]")?;
+        try!(self.ibox(INDENT_UNIT));
+        try!(word(&mut self.s, "["));
+        try!(self.print_inner_attributes_inline(attrs));
+        try!(self.commasep_exprs(Inconsistent, &exprs[..]));
+        try!(word(&mut self.s, "]"));
         self.end()
     }
 
@@ -1821,13 +1822,13 @@ impl<'a> State<'a> {
                          element: &ast::Expr,
                          count: &ast::Expr,
                          attrs: &[Attribute]) -> io::Result<()> {
-        self.ibox(INDENT_UNIT)?;
-        word(&mut self.s, "[")?;
-        self.print_inner_attributes_inline(attrs)?;
-        self.print_expr(element)?;
-        self.word_space(";")?;
-        self.print_expr(count)?;
-        word(&mut self.s, "]")?;
+        try!(self.ibox(INDENT_UNIT));
+        try!(word(&mut self.s, "["));
+        try!(self.print_inner_attributes_inline(attrs));
+        try!(self.print_expr(element));
+        try!(self.word_space(";"));
+        try!(self.print_expr(count));
+        try!(word(&mut self.s, "]"));
         self.end()
     }
 
@@ -1836,46 +1837,46 @@ impl<'a> State<'a> {
                          fields: &[ast::Field],
                          wth: &Option<P<ast::Expr>>,
                          attrs: &[Attribute]) -> io::Result<()> {
-        self.print_path(path, true, 0)?;
-        word(&mut self.s, "{")?;
-        self.print_inner_attributes_inline(attrs)?;
-        self.commasep_cmnt(
+        try!(self.print_path(path, true, 0));
+        try!(word(&mut self.s, "{"));
+        try!(self.print_inner_attributes_inline(attrs));
+        try!(self.commasep_cmnt(
             Consistent,
             &fields[..],
             |s, field| {
-                s.ibox(INDENT_UNIT)?;
-                s.print_ident(field.ident.node)?;
-                s.word_space(":")?;
-                s.print_expr(&field.expr)?;
+                try!(s.ibox(INDENT_UNIT));
+                try!(s.print_ident(field.ident.node));
+                try!(s.word_space(":"));
+                try!(s.print_expr(&field.expr));
                 s.end()
             },
-            |f| f.span)?;
+            |f| f.span));
         match *wth {
             Some(ref expr) => {
-                self.ibox(INDENT_UNIT)?;
+                try!(self.ibox(INDENT_UNIT));
                 if !fields.is_empty() {
-                    word(&mut self.s, ",")?;
-                    space(&mut self.s)?;
+                    try!(word(&mut self.s, ","));
+                    try!(space(&mut self.s));
                 }
-                word(&mut self.s, "..")?;
-                self.print_expr(&expr)?;
-                self.end()?;
+                try!(word(&mut self.s, ".."));
+                try!(self.print_expr(&expr));
+                try!(self.end());
             }
             _ => if !fields.is_empty() {
-                word(&mut self.s, ",")?
+                try!(word(&mut self.s, ","))
             }
         }
-        word(&mut self.s, "}")?;
+        try!(word(&mut self.s, "}"));
         Ok(())
     }
 
     fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>],
                       attrs: &[Attribute]) -> io::Result<()> {
-        self.popen()?;
-        self.print_inner_attributes_inline(attrs)?;
-        self.commasep_exprs(Inconsistent, &exprs[..])?;
+        try!(self.popen());
+        try!(self.print_inner_attributes_inline(attrs));
+        try!(self.commasep_exprs(Inconsistent, &exprs[..]));
         if exprs.len() == 1 {
-            word(&mut self.s, ",")?;
+            try!(word(&mut self.s, ","));
         }
         self.pclose()
     }
@@ -1883,7 +1884,7 @@ impl<'a> State<'a> {
     fn print_expr_call(&mut self,
                        func: &ast::Expr,
                        args: &[P<ast::Expr>]) -> io::Result<()> {
-        self.print_expr_maybe_paren(func)?;
+        try!(self.print_expr_maybe_paren(func));
         self.print_call_post(args)
     }
 
@@ -1892,14 +1893,14 @@ impl<'a> State<'a> {
                               tys: &[P<ast::Ty>],
                               args: &[P<ast::Expr>]) -> io::Result<()> {
         let base_args = &args[1..];
-        self.print_expr(&args[0])?;
-        word(&mut self.s, ".")?;
-        self.print_ident(ident.node)?;
+        try!(self.print_expr(&args[0]));
+        try!(word(&mut self.s, "."));
+        try!(self.print_ident(ident.node));
         if !tys.is_empty() {
-            word(&mut self.s, "::<")?;
-            self.commasep(Inconsistent, tys,
-                          |s, ty| s.print_type(&ty))?;
-            word(&mut self.s, ">")?;
+            try!(word(&mut self.s, "::<"));
+            try!(self.commasep(Inconsistent, tys,
+                          |s, ty| s.print_type(&ty)));
+            try!(word(&mut self.s, ">"));
         }
         self.print_call_post(base_args)
     }
@@ -1909,12 +1910,12 @@ impl<'a> State<'a> {
                          lhs: &ast::Expr,
                          rhs: &ast::Expr) -> io::Result<()> {
         if self.check_expr_bin_needs_paren(lhs, op) {
-            self.print_expr_maybe_paren(lhs)?;
+            try!(self.print_expr_maybe_paren(lhs));
         } else {
-            self.print_expr(lhs)?;
+            try!(self.print_expr(lhs));
         }
-        space(&mut self.s)?;
-        self.word_space(op.node.to_string())?;
+        try!(space(&mut self.s));
+        try!(self.word_space(op.node.to_string()));
         if self.check_expr_bin_needs_paren(rhs, op) {
             self.print_expr_maybe_paren(rhs)
         } else {
@@ -1925,15 +1926,15 @@ impl<'a> State<'a> {
     fn print_expr_unary(&mut self,
                         op: ast::UnOp,
                         expr: &ast::Expr) -> io::Result<()> {
-        word(&mut self.s, ast::UnOp::to_string(op))?;
+        try!(word(&mut self.s, ast::UnOp::to_string(op)));
         self.print_expr_maybe_paren(expr)
     }
 
     fn print_expr_addr_of(&mut self,
                           mutability: ast::Mutability,
                           expr: &ast::Expr) -> io::Result<()> {
-        word(&mut self.s, "&")?;
-        self.print_mutability(mutability)?;
+        try!(word(&mut self.s, "&"));
+        try!(self.print_mutability(mutability));
         self.print_expr_maybe_paren(expr)
     }
 
@@ -1944,139 +1945,139 @@ impl<'a> State<'a> {
     fn print_expr_outer_attr_style(&mut self,
                                   expr: &ast::Expr,
                                   is_inline: bool) -> io::Result<()> {
-        self.maybe_print_comment(expr.span.lo)?;
+        try!(self.maybe_print_comment(expr.span.lo));
 
         let attrs = expr.attrs.as_attr_slice();
         if is_inline {
-            self.print_outer_attributes_inline(attrs)?;
+            try!(self.print_outer_attributes_inline(attrs));
         } else {
-            self.print_outer_attributes(attrs)?;
+            try!(self.print_outer_attributes(attrs));
         }
 
-        self.ibox(INDENT_UNIT)?;
-        self.ann.pre(self, NodeExpr(expr))?;
+        try!(self.ibox(INDENT_UNIT));
+        try!(self.ann.pre(self, NodeExpr(expr)));
         match expr.node {
             ast::ExprKind::Box(ref expr) => {
-                self.word_space("box")?;
-                self.print_expr(expr)?;
+                try!(self.word_space("box"));
+                try!(self.print_expr(expr));
             }
             ast::ExprKind::InPlace(ref place, ref expr) => {
-                self.print_expr_in_place(place, expr)?;
+                try!(self.print_expr_in_place(place, expr));
             }
             ast::ExprKind::Vec(ref exprs) => {
-                self.print_expr_vec(&exprs[..], attrs)?;
+                try!(self.print_expr_vec(&exprs[..], attrs));
             }
             ast::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(&element, &count, attrs)?;
+                try!(self.print_expr_repeat(&element, &count, attrs));
             }
             ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
-                self.print_expr_struct(path, &fields[..], wth, attrs)?;
+                try!(self.print_expr_struct(path, &fields[..], wth, attrs));
             }
             ast::ExprKind::Tup(ref exprs) => {
-                self.print_expr_tup(&exprs[..], attrs)?;
+                try!(self.print_expr_tup(&exprs[..], attrs));
             }
             ast::ExprKind::Call(ref func, ref args) => {
-                self.print_expr_call(&func, &args[..])?;
+                try!(self.print_expr_call(&func, &args[..]));
             }
             ast::ExprKind::MethodCall(ident, ref tys, ref args) => {
-                self.print_expr_method_call(ident, &tys[..], &args[..])?;
+                try!(self.print_expr_method_call(ident, &tys[..], &args[..]));
             }
             ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
-                self.print_expr_binary(op, &lhs, &rhs)?;
+                try!(self.print_expr_binary(op, &lhs, &rhs));
             }
             ast::ExprKind::Unary(op, ref expr) => {
-                self.print_expr_unary(op, &expr)?;
+                try!(self.print_expr_unary(op, &expr));
             }
             ast::ExprKind::AddrOf(m, ref expr) => {
-                self.print_expr_addr_of(m, &expr)?;
+                try!(self.print_expr_addr_of(m, &expr));
             }
             ast::ExprKind::Lit(ref lit) => {
-                self.print_literal(&lit)?;
+                try!(self.print_literal(&lit));
             }
             ast::ExprKind::Cast(ref expr, ref ty) => {
                 if let ast::ExprKind::Cast(..) = expr.node {
-                    self.print_expr(&expr)?;
+                    try!(self.print_expr(&expr));
                 } else {
-                    self.print_expr_maybe_paren(&expr)?;
+                    try!(self.print_expr_maybe_paren(&expr));
                 }
-                space(&mut self.s)?;
-                self.word_space("as")?;
-                self.print_type(&ty)?;
+                try!(space(&mut self.s));
+                try!(self.word_space("as"));
+                try!(self.print_type(&ty));
             }
             ast::ExprKind::Type(ref expr, ref ty) => {
-                self.print_expr(&expr)?;
-                self.word_space(":")?;
-                self.print_type(&ty)?;
+                try!(self.print_expr(&expr));
+                try!(self.word_space(":"));
+                try!(self.print_type(&ty));
             }
             ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
+                try!(self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e)));
             }
             ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
-                self.print_if_let(&pat, &expr, &blk, elseopt.as_ref().map(|e| &**e))?;
+                try!(self.print_if_let(&pat, &expr, &blk, elseopt.as_ref().map(|e| &**e)));
             }
             ast::ExprKind::While(ref test, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
-                    self.word_space(":")?;
+                    try!(self.print_ident(ident.node));
+                    try!(self.word_space(":"));
                 }
-                self.head("while")?;
-                self.print_expr(&test)?;
-                space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                try!(self.head("while"));
+                try!(self.print_expr(&test));
+                try!(space(&mut self.s));
+                try!(self.print_block_with_attrs(&blk, attrs));
             }
             ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
-                    self.word_space(":")?;
+                    try!(self.print_ident(ident.node));
+                    try!(self.word_space(":"));
                 }
-                self.head("while let")?;
-                self.print_pat(&pat)?;
-                space(&mut self.s)?;
-                self.word_space("=")?;
-                self.print_expr(&expr)?;
-                space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                try!(self.head("while let"));
+                try!(self.print_pat(&pat));
+                try!(space(&mut self.s));
+                try!(self.word_space("="));
+                try!(self.print_expr(&expr));
+                try!(space(&mut self.s));
+                try!(self.print_block_with_attrs(&blk, attrs));
             }
             ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
-                    self.word_space(":")?;
+                    try!(self.print_ident(ident.node));
+                    try!(self.word_space(":"));
                 }
-                self.head("for")?;
-                self.print_pat(&pat)?;
-                space(&mut self.s)?;
-                self.word_space("in")?;
-                self.print_expr(&iter)?;
-                space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                try!(self.head("for"));
+                try!(self.print_pat(&pat));
+                try!(space(&mut self.s));
+                try!(self.word_space("in"));
+                try!(self.print_expr(&iter));
+                try!(space(&mut self.s));
+                try!(self.print_block_with_attrs(&blk, attrs));
             }
             ast::ExprKind::Loop(ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
-                    self.word_space(":")?;
+                    try!(self.print_ident(ident.node));
+                    try!(self.word_space(":"));
                 }
-                self.head("loop")?;
-                space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                try!(self.head("loop"));
+                try!(space(&mut self.s));
+                try!(self.print_block_with_attrs(&blk, attrs));
             }
             ast::ExprKind::Match(ref expr, ref arms) => {
-                self.cbox(INDENT_UNIT)?;
-                self.ibox(4)?;
-                self.word_nbsp("match")?;
-                self.print_expr(&expr)?;
-                space(&mut self.s)?;
-                self.bopen()?;
-                self.print_inner_attributes_no_trailing_hardbreak(attrs)?;
+                try!(self.cbox(INDENT_UNIT));
+                try!(self.ibox(4));
+                try!(self.word_nbsp("match"));
+                try!(self.print_expr(&expr));
+                try!(space(&mut self.s));
+                try!(self.bopen());
+                try!(self.print_inner_attributes_no_trailing_hardbreak(attrs));
                 for arm in arms {
-                    self.print_arm(arm)?;
+                    try!(self.print_arm(arm));
                 }
-                self.bclose_(expr.span, INDENT_UNIT)?;
+                try!(self.bclose_(expr.span, INDENT_UNIT));
             }
             ast::ExprKind::Closure(capture_clause, ref decl, ref body, _) => {
-                self.print_capture_clause(capture_clause)?;
+                try!(self.print_capture_clause(capture_clause));
 
-                self.print_fn_block_args(&decl)?;
-                space(&mut self.s)?;
+                try!(self.print_fn_block_args(&decl));
+                try!(space(&mut self.s));
 
                 let default_return = match decl.output {
                     ast::FunctionRetTy::Default(..) => true,
@@ -2084,150 +2085,150 @@ impl<'a> State<'a> {
                 };
 
                 if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
-                    self.print_block_unclosed(&body)?;
+                    try!(self.print_block_unclosed(&body));
                 } else {
                     // we extract the block, so as not to create another set of boxes
                     let i_expr = body.expr.as_ref().unwrap();
                     match i_expr.node {
                         ast::ExprKind::Block(ref blk) => {
-                            self.print_block_unclosed_with_attrs(
+                            try!(self.print_block_unclosed_with_attrs(
                                 &blk,
-                                i_expr.attrs.as_attr_slice())?;
+                                i_expr.attrs.as_attr_slice()));
                         }
                         _ => {
                             // this is a bare expression
-                            self.print_expr(&i_expr)?;
-                            self.end()?; // need to close a box
+                            try!(self.print_expr(&i_expr));
+                            try!(self.end()); // need to close a box
                         }
                     }
                 }
                 // a box will be closed by print_expr, but we didn't want an overall
                 // wrapper so we closed the corresponding opening. so create an
                 // empty box to satisfy the close.
-                self.ibox(0)?;
+                try!(self.ibox(0));
             }
             ast::ExprKind::Block(ref blk) => {
                 // containing cbox, will be closed by print-block at }
-                self.cbox(INDENT_UNIT)?;
+                try!(self.cbox(INDENT_UNIT));
                 // head-box, will be closed by print-block after {
-                self.ibox(0)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                try!(self.ibox(0));
+                try!(self.print_block_with_attrs(&blk, attrs));
             }
             ast::ExprKind::Assign(ref lhs, ref rhs) => {
-                self.print_expr(&lhs)?;
-                space(&mut self.s)?;
-                self.word_space("=")?;
-                self.print_expr(&rhs)?;
+                try!(self.print_expr(&lhs));
+                try!(space(&mut self.s));
+                try!(self.word_space("="));
+                try!(self.print_expr(&rhs));
             }
             ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                self.print_expr(&lhs)?;
-                space(&mut self.s)?;
-                word(&mut self.s, op.node.to_string())?;
-                self.word_space("=")?;
-                self.print_expr(&rhs)?;
+                try!(self.print_expr(&lhs));
+                try!(space(&mut self.s));
+                try!(word(&mut self.s, op.node.to_string()));
+                try!(self.word_space("="));
+                try!(self.print_expr(&rhs));
             }
             ast::ExprKind::Field(ref expr, id) => {
-                self.print_expr(&expr)?;
-                word(&mut self.s, ".")?;
-                self.print_ident(id.node)?;
+                try!(self.print_expr(&expr));
+                try!(word(&mut self.s, "."));
+                try!(self.print_ident(id.node));
             }
             ast::ExprKind::TupField(ref expr, id) => {
-                self.print_expr(&expr)?;
-                word(&mut self.s, ".")?;
-                self.print_usize(id.node)?;
+                try!(self.print_expr(&expr));
+                try!(word(&mut self.s, "."));
+                try!(self.print_usize(id.node));
             }
             ast::ExprKind::Index(ref expr, ref index) => {
-                self.print_expr(&expr)?;
-                word(&mut self.s, "[")?;
-                self.print_expr(&index)?;
-                word(&mut self.s, "]")?;
+                try!(self.print_expr(&expr));
+                try!(word(&mut self.s, "["));
+                try!(self.print_expr(&index));
+                try!(word(&mut self.s, "]"));
             }
             ast::ExprKind::Range(ref start, ref end, limits) => {
                 if let &Some(ref e) = start {
-                    self.print_expr(&e)?;
+                    try!(self.print_expr(&e));
                 }
                 if limits == ast::RangeLimits::HalfOpen {
-                    word(&mut self.s, "..")?;
+                    try!(word(&mut self.s, ".."));
                 } else {
-                    word(&mut self.s, "...")?;
+                    try!(word(&mut self.s, "..."));
                 }
                 if let &Some(ref e) = end {
-                    self.print_expr(&e)?;
+                    try!(self.print_expr(&e));
                 }
             }
             ast::ExprKind::Path(None, ref path) => {
-                self.print_path(path, true, 0)?
+                try!(self.print_path(path, true, 0))
             }
             ast::ExprKind::Path(Some(ref qself), ref path) => {
-                self.print_qpath(path, qself, true)?
+                try!(self.print_qpath(path, qself, true))
             }
             ast::ExprKind::Break(opt_ident) => {
-                word(&mut self.s, "break")?;
-                space(&mut self.s)?;
+                try!(word(&mut self.s, "break"));
+                try!(space(&mut self.s));
                 if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
-                    space(&mut self.s)?;
+                    try!(self.print_ident(ident.node));
+                    try!(space(&mut self.s));
                 }
             }
             ast::ExprKind::Again(opt_ident) => {
-                word(&mut self.s, "continue")?;
-                space(&mut self.s)?;
+                try!(word(&mut self.s, "continue"));
+                try!(space(&mut self.s));
                 if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
-                    space(&mut self.s)?
+                    try!(self.print_ident(ident.node));
+                    try!(space(&mut self.s))
                 }
             }
             ast::ExprKind::Ret(ref result) => {
-                word(&mut self.s, "return")?;
+                try!(word(&mut self.s, "return"));
                 match *result {
                     Some(ref expr) => {
-                        word(&mut self.s, " ")?;
-                        self.print_expr(&expr)?;
+                        try!(word(&mut self.s, " "));
+                        try!(self.print_expr(&expr));
                     }
                     _ => ()
                 }
             }
             ast::ExprKind::InlineAsm(ref a) => {
-                word(&mut self.s, "asm!")?;
-                self.popen()?;
-                self.print_string(&a.asm, a.asm_str_style)?;
-                self.word_space(":")?;
+                try!(word(&mut self.s, "asm!"));
+                try!(self.popen());
+                try!(self.print_string(&a.asm, a.asm_str_style));
+                try!(self.word_space(":"));
 
-                self.commasep(Inconsistent, &a.outputs,
+                try!(self.commasep(Inconsistent, &a.outputs,
                                    |s, out| {
                     let mut ch = out.constraint.chars();
                     match ch.next() {
                         Some('=') if out.is_rw => {
-                            s.print_string(&format!("+{}", ch.as_str()),
-                                           ast::StrStyle::Cooked)?
+                            try!(s.print_string(&format!("+{}", ch.as_str()),
+                                           ast::StrStyle::Cooked))
                         }
-                        _ => s.print_string(&out.constraint,
-                                            ast::StrStyle::Cooked)?
+                        _ => try!(s.print_string(&out.constraint,
+                                            ast::StrStyle::Cooked))
                     }
-                    s.popen()?;
-                    s.print_expr(&out.expr)?;
-                    s.pclose()?;
+                    try!(s.popen());
+                    try!(s.print_expr(&out.expr));
+                    try!(s.pclose());
                     Ok(())
-                })?;
-                space(&mut self.s)?;
-                self.word_space(":")?;
+                }));
+                try!(space(&mut self.s));
+                try!(self.word_space(":"));
 
-                self.commasep(Inconsistent, &a.inputs,
+                try!(self.commasep(Inconsistent, &a.inputs,
                                    |s, &(ref co, ref o)| {
-                    s.print_string(&co, ast::StrStyle::Cooked)?;
-                    s.popen()?;
-                    s.print_expr(&o)?;
-                    s.pclose()?;
+                    try!(s.print_string(&co, ast::StrStyle::Cooked));
+                    try!(s.popen());
+                    try!(s.print_expr(&o));
+                    try!(s.pclose());
                     Ok(())
-                })?;
-                space(&mut self.s)?;
-                self.word_space(":")?;
+                }));
+                try!(space(&mut self.s));
+                try!(self.word_space(":"));
 
-                self.commasep(Inconsistent, &a.clobbers,
+                try!(self.commasep(Inconsistent, &a.clobbers,
                                    |s, co| {
-                    s.print_string(&co, ast::StrStyle::Cooked)?;
+                    try!(s.print_string(&co, ast::StrStyle::Cooked));
                     Ok(())
-                })?;
+                }));
 
                 let mut options = vec!();
                 if a.volatile {
@@ -2241,58 +2242,58 @@ impl<'a> State<'a> {
                 }
 
                 if !options.is_empty() {
-                    space(&mut self.s)?;
-                    self.word_space(":")?;
-                    self.commasep(Inconsistent, &options,
+                    try!(space(&mut self.s));
+                    try!(self.word_space(":"));
+                    try!(self.commasep(Inconsistent, &options,
                                   |s, &co| {
-                                      s.print_string(co, ast::StrStyle::Cooked)?;
+                                      try!(s.print_string(co, ast::StrStyle::Cooked));
                                       Ok(())
-                                  })?;
+                                  }));
                 }
 
-                self.pclose()?;
+                try!(self.pclose());
             }
-            ast::ExprKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
+            ast::ExprKind::Mac(ref m) => try!(self.print_mac(m, token::Paren)),
             ast::ExprKind::Paren(ref e) => {
-                self.popen()?;
-                self.print_inner_attributes_inline(attrs)?;
-                self.print_expr(&e)?;
-                self.pclose()?;
+                try!(self.popen());
+                try!(self.print_inner_attributes_inline(attrs));
+                try!(self.print_expr(&e));
+                try!(self.pclose());
             },
             ast::ExprKind::Try(ref e) => {
-                self.print_expr(e)?;
-                word(&mut self.s, "?")?
+                try!(self.print_expr(e));
+                try!(word(&mut self.s, "?"))
             }
         }
-        self.ann.post(self, NodeExpr(expr))?;
+        try!(self.ann.post(self, NodeExpr(expr)));
         self.end()
     }
 
     pub fn print_local_decl(&mut self, loc: &ast::Local) -> io::Result<()> {
-        self.print_pat(&loc.pat)?;
+        try!(self.print_pat(&loc.pat));
         if let Some(ref ty) = loc.ty {
-            self.word_space(":")?;
-            self.print_type(&ty)?;
+            try!(self.word_space(":"));
+            try!(self.print_type(&ty));
         }
         Ok(())
     }
 
     pub fn print_decl(&mut self, decl: &ast::Decl) -> io::Result<()> {
-        self.maybe_print_comment(decl.span.lo)?;
+        try!(self.maybe_print_comment(decl.span.lo));
         match decl.node {
             ast::DeclKind::Local(ref loc) => {
-                self.print_outer_attributes(loc.attrs.as_attr_slice())?;
-                self.space_if_not_bol()?;
-                self.ibox(INDENT_UNIT)?;
-                self.word_nbsp("let")?;
-
-                self.ibox(INDENT_UNIT)?;
-                self.print_local_decl(&loc)?;
-                self.end()?;
+                try!(self.print_outer_attributes(loc.attrs.as_attr_slice()));
+                try!(self.space_if_not_bol());
+                try!(self.ibox(INDENT_UNIT));
+                try!(self.word_nbsp("let"));
+
+                try!(self.ibox(INDENT_UNIT));
+                try!(self.print_local_decl(&loc));
+                try!(self.end());
                 if let Some(ref init) = loc.init {
-                    self.nbsp()?;
-                    self.word_space("=")?;
-                    self.print_expr(&init)?;
+                    try!(self.nbsp());
+                    try!(self.word_space("="));
+                    try!(self.print_expr(&init));
                 }
                 self.end()
             }
@@ -2301,7 +2302,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        word(&mut self.s, &ident.name.as_str())?;
+        try!(word(&mut self.s, &ident.name.as_str()));
         self.ann.post(self, NodeIdent(&ident))
     }
 
@@ -2310,15 +2311,15 @@ impl<'a> State<'a> {
     }
 
     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
-        word(&mut self.s, &name.as_str())?;
+        try!(word(&mut self.s, &name.as_str()));
         self.ann.post(self, NodeName(&name))
     }
 
     pub fn print_for_decl(&mut self, loc: &ast::Local,
                           coll: &ast::Expr) -> io::Result<()> {
-        self.print_local_decl(loc)?;
-        space(&mut self.s)?;
-        self.word_space("in")?;
+        try!(self.print_local_decl(loc));
+        try!(space(&mut self.s));
+        try!(self.word_space("in"));
         self.print_expr(coll)
     }
 
@@ -2328,19 +2329,19 @@ impl<'a> State<'a> {
                   depth: usize)
                   -> io::Result<()>
     {
-        self.maybe_print_comment(path.span.lo)?;
+        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 {
-                word(&mut self.s, "::")?
+                try!(word(&mut self.s, "::"))
             }
 
-            self.print_ident(segment.identifier)?;
+            try!(self.print_ident(segment.identifier));
 
-            self.print_path_parameters(&segment.parameters, colons_before_params)?;
+            try!(self.print_path_parameters(&segment.parameters, colons_before_params));
         }
 
         Ok(())
@@ -2352,18 +2353,18 @@ impl<'a> State<'a> {
                    colons_before_params: bool)
                    -> io::Result<()>
     {
-        word(&mut self.s, "<")?;
-        self.print_type(&qself.ty)?;
+        try!(word(&mut self.s, "<"));
+        try!(self.print_type(&qself.ty));
         if qself.position > 0 {
-            space(&mut self.s)?;
-            self.word_space("as")?;
+            try!(space(&mut self.s));
+            try!(self.word_space("as"));
             let depth = path.segments.len() - qself.position;
-            self.print_path(&path, false, depth)?;
+            try!(self.print_path(&path, false, depth));
         }
-        word(&mut self.s, ">")?;
-        word(&mut self.s, "::")?;
+        try!(word(&mut self.s, ">"));
+        try!(word(&mut self.s, "::"));
         let item_segment = path.segments.last().unwrap();
-        self.print_ident(item_segment.identifier)?;
+        try!(self.print_ident(item_segment.identifier));
         self.print_path_parameters(&item_segment.parameters, colons_before_params)
     }
 
@@ -2377,61 +2378,61 @@ impl<'a> State<'a> {
         }
 
         if colons_before_params {
-            word(&mut self.s, "::")?
+            try!(word(&mut self.s, "::"))
         }
 
         match *parameters {
             ast::PathParameters::AngleBracketed(ref data) => {
-                word(&mut self.s, "<")?;
+                try!(word(&mut self.s, "<"));
 
                 let mut comma = false;
                 for lifetime in &data.lifetimes {
                     if comma {
-                        self.word_space(",")?
+                        try!(self.word_space(","))
                     }
-                    self.print_lifetime(lifetime)?;
+                    try!(self.print_lifetime(lifetime));
                     comma = true;
                 }
 
                 if !data.types.is_empty() {
                     if comma {
-                        self.word_space(",")?
+                        try!(self.word_space(","))
                     }
-                    self.commasep(
+                    try!(self.commasep(
                         Inconsistent,
                         &data.types,
-                        |s, ty| s.print_type(&ty))?;
+                        |s, ty| s.print_type(&ty)));
                         comma = true;
                 }
 
                 for binding in data.bindings.iter() {
                     if comma {
-                        self.word_space(",")?
+                        try!(self.word_space(","))
                     }
-                    self.print_ident(binding.ident)?;
-                    space(&mut self.s)?;
-                    self.word_space("=")?;
-                    self.print_type(&binding.ty)?;
+                    try!(self.print_ident(binding.ident));
+                    try!(space(&mut self.s));
+                    try!(self.word_space("="));
+                    try!(self.print_type(&binding.ty));
                     comma = true;
                 }
 
-                word(&mut self.s, ">")?
+                try!(word(&mut self.s, ">"))
             }
 
             ast::PathParameters::Parenthesized(ref data) => {
-                word(&mut self.s, "(")?;
-                self.commasep(
+                try!(word(&mut self.s, "("));
+                try!(self.commasep(
                     Inconsistent,
                     &data.inputs,
-                    |s, ty| s.print_type(&ty))?;
-                word(&mut self.s, ")")?;
+                    |s, ty| s.print_type(&ty)));
+                try!(word(&mut self.s, ")"));
 
                 match data.output {
                     None => { }
                     Some(ref ty) => {
-                        self.space_if_not_bol()?;
-                        self.word_space("->")?;
-                        self.print_type(&ty)?;
+                        try!(self.space_if_not_bol());
+                        try!(self.word_space("->"));
+                        try!(self.print_type(&ty));
                     }
                 }
             }
@@ -2441,136 +2442,133 @@ impl<'a> State<'a> {
     }
 
     pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
-        self.maybe_print_comment(pat.span.lo)?;
-        self.ann.pre(self, NodePat(pat))?;
+        try!(self.maybe_print_comment(pat.span.lo));
+        try!(self.ann.pre(self, NodePat(pat)));
         /* Pat isn't normalized, but the beauty of it
          is that it doesn't matter */
         match pat.node {
-            PatKind::Wild => word(&mut self.s, "_")?,
+            PatKind::Wild => try!(word(&mut self.s, "_")),
             PatKind::Ident(binding_mode, ref path1, ref sub) => {
                 match binding_mode {
                     ast::BindingMode::ByRef(mutbl) => {
-                        self.word_nbsp("ref")?;
-                        self.print_mutability(mutbl)?;
+                        try!(self.word_nbsp("ref"));
+                        try!(self.print_mutability(mutbl));
                     }
                     ast::BindingMode::ByValue(ast::Mutability::Immutable) => {}
                     ast::BindingMode::ByValue(ast::Mutability::Mutable) => {
-                        self.word_nbsp("mut")?;
+                        try!(self.word_nbsp("mut"));
                     }
                 }
-                self.print_ident(path1.node)?;
-                match *sub {
-                    Some(ref p) => {
-                        word(&mut self.s, "@")?;
-                        self.print_pat(&p)?;
-                    }
-                    None => ()
+                try!(self.print_ident(path1.node));
+                if let Some(ref p) = *sub {
+                    try!(word(&mut self.s, "@"));
+                    try!(self.print_pat(&p));
                 }
             }
             PatKind::TupleStruct(ref path, ref elts, ddpos) => {
-                self.print_path(path, true, 0)?;
-                self.popen()?;
+                try!(self.print_path(path, true, 0));
+                try!(self.popen());
                 if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
+                    try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)));
                     if ddpos != 0 {
-                        self.word_space(",")?;
+                        try!(self.word_space(","));
                     }
-                    word(&mut self.s, "..")?;
+                    try!(word(&mut self.s, ".."));
                     if ddpos != elts.len() {
-                        word(&mut self.s, ",")?;
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
+                        try!(word(&mut self.s, ","));
+                        try!(self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p)));
                     }
                 } else {
-                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
+                    try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
                 }
-                self.pclose()?;
+                try!(self.pclose());
             }
             PatKind::Path(ref path) => {
-                self.print_path(path, true, 0)?;
+                try!(self.print_path(path, true, 0));
             }
             PatKind::QPath(ref qself, ref path) => {
-                self.print_qpath(path, qself, false)?;
+                try!(self.print_qpath(path, qself, false));
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                self.print_path(path, true, 0)?;
-                self.nbsp()?;
-                self.word_space("{")?;
-                self.commasep_cmnt(
+                try!(self.print_path(path, true, 0));
+                try!(self.nbsp());
+                try!(self.word_space("{"));
+                try!(self.commasep_cmnt(
                     Consistent, &fields[..],
                     |s, f| {
-                        s.cbox(INDENT_UNIT)?;
+                        try!(s.cbox(INDENT_UNIT));
                         if !f.node.is_shorthand {
-                            s.print_ident(f.node.ident)?;
-                            s.word_nbsp(":")?;
+                            try!(s.print_ident(f.node.ident));
+                            try!(s.word_nbsp(":"));
                         }
-                        s.print_pat(&f.node.pat)?;
+                        try!(s.print_pat(&f.node.pat));
                         s.end()
                     },
-                    |f| f.node.pat.span)?;
+                    |f| f.node.pat.span));
                 if etc {
-                    if !fields.is_empty() { self.word_space(",")?; }
-                    word(&mut self.s, "..")?;
+                    if !fields.is_empty() { try!(self.word_space(",")); }
+                    try!(word(&mut self.s, ".."));
                 }
-                space(&mut self.s)?;
-                word(&mut self.s, "}")?;
+                try!(space(&mut self.s));
+                try!(word(&mut self.s, "}"));
             }
             PatKind::Tuple(ref elts, ddpos) => {
-                self.popen()?;
+                try!(self.popen());
                 if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
+                    try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)));
                     if ddpos != 0 {
-                        self.word_space(",")?;
+                        try!(self.word_space(","));
                     }
-                    word(&mut self.s, "..")?;
+                    try!(word(&mut self.s, ".."));
                     if ddpos != elts.len() {
-                        word(&mut self.s, ",")?;
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
+                        try!(word(&mut self.s, ","));
+                        try!(self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p)));
                     }
                 } else {
-                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
+                    try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)));
                     if elts.len() == 1 {
-                        word(&mut self.s, ",")?;
+                        try!(word(&mut self.s, ","));
                     }
                 }
-                self.pclose()?;
+                try!(self.pclose());
             }
             PatKind::Box(ref inner) => {
-                word(&mut self.s, "box ")?;
-                self.print_pat(&inner)?;
+                try!(word(&mut self.s, "box "));
+                try!(self.print_pat(&inner));
             }
             PatKind::Ref(ref inner, mutbl) => {
-                word(&mut self.s, "&")?;
+                try!(word(&mut self.s, "&"));
                 if mutbl == ast::Mutability::Mutable {
-                    word(&mut self.s, "mut ")?;
+                    try!(word(&mut self.s, "mut "));
                 }
-                self.print_pat(&inner)?;
+                try!(self.print_pat(&inner));
             }
-            PatKind::Lit(ref e) => self.print_expr(&**e)?,
+            PatKind::Lit(ref e) => try!(self.print_expr(&**e)),
             PatKind::Range(ref begin, ref end) => {
-                self.print_expr(&begin)?;
-                space(&mut self.s)?;
-                word(&mut self.s, "...")?;
-                self.print_expr(&end)?;
+                try!(self.print_expr(&begin));
+                try!(space(&mut self.s));
+                try!(word(&mut self.s, "..."));
+                try!(self.print_expr(&end));
             }
             PatKind::Vec(ref before, ref slice, ref after) => {
-                word(&mut self.s, "[")?;
-                self.commasep(Inconsistent,
+                try!(word(&mut self.s, "["));
+                try!(self.commasep(Inconsistent,
                                    &before[..],
-                                   |s, p| s.print_pat(&p))?;
+                                   |s, p| s.print_pat(&p)));
                 if let Some(ref p) = *slice {
-                    if !before.is_empty() { self.word_space(",")?; }
+                    if !before.is_empty() { try!(self.word_space(",")); }
                     if p.node != PatKind::Wild {
-                        self.print_pat(&p)?;
+                        try!(self.print_pat(&p));
                     }
-                    word(&mut self.s, "..")?;
-                    if !after.is_empty() { self.word_space(",")?; }
+                    try!(word(&mut self.s, ".."));
+                    if !after.is_empty() { try!(self.word_space(",")); }
                 }
-                self.commasep(Inconsistent,
+                try!(self.commasep(Inconsistent,
                                    &after[..],
-                                   |s, p| s.print_pat(&p))?;
-                word(&mut self.s, "]")?;
+                                   |s, p| s.print_pat(&p)));
+                try!(word(&mut self.s, "]"));
             }
-            PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
+            PatKind::Mac(ref m) => try!(self.print_mac(m, token::Paren)),
         }
         self.ann.post(self, NodePat(pat))
     }
@@ -2579,43 +2577,43 @@ impl<'a> State<'a> {
         // I have no idea why this check is necessary, but here it
         // is :(
         if arm.attrs.is_empty() {
-            space(&mut self.s)?;
+            try!(space(&mut self.s));
         }
-        self.cbox(INDENT_UNIT)?;
-        self.ibox(0)?;
-        self.print_outer_attributes(&arm.attrs)?;
+        try!(self.cbox(INDENT_UNIT));
+        try!(self.ibox(0));
+        try!(self.print_outer_attributes(&arm.attrs));
         let mut first = true;
         for p in &arm.pats {
             if first {
                 first = false;
             } else {
-                space(&mut self.s)?;
-                self.word_space("|")?;
+                try!(space(&mut self.s));
+                try!(self.word_space("|"));
             }
-            self.print_pat(&p)?;
+            try!(self.print_pat(&p));
         }
-        space(&mut self.s)?;
+        try!(space(&mut self.s));
         if let Some(ref e) = arm.guard {
-            self.word_space("if")?;
-            self.print_expr(&e)?;
-            space(&mut self.s)?;
+            try!(self.word_space("if"));
+            try!(self.print_expr(&e));
+            try!(space(&mut self.s));
         }
-        self.word_space("=>")?;
+        try!(self.word_space("=>"));
 
         match arm.body.node {
             ast::ExprKind::Block(ref blk) => {
                 // the block will close the pattern's ibox
-                self.print_block_unclosed_indent(&blk, INDENT_UNIT)?;
+                try!(self.print_block_unclosed_indent(&blk, INDENT_UNIT));
 
                 // If it is a user-provided unsafe block, print a comma after it
                 if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
-                    word(&mut self.s, ",")?;
+                    try!(word(&mut self.s, ","));
                 }
             }
             _ => {
-                self.end()?; // close the ibox for the pattern
-                self.print_expr(&arm.body)?;
-                word(&mut self.s, ",")?;
+                try!(self.end()); // close the ibox for the pattern
+                try!(self.print_expr(&arm.body));
+                try!(word(&mut self.s, ","));
             }
         }
         self.end() // close enclosing cbox
@@ -2624,19 +2622,19 @@ impl<'a> State<'a> {
     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) -> io::Result<()> {
         match explicit_self.node {
             SelfKind::Value(m) => {
-                self.print_mutability(m)?;
+                try!(self.print_mutability(m));
                 word(&mut self.s, "self")
             }
             SelfKind::Region(ref lt, m) => {
-                word(&mut self.s, "&")?;
-                self.print_opt_lifetime(lt)?;
-                self.print_mutability(m)?;
+                try!(word(&mut self.s, "&"));
+                try!(self.print_opt_lifetime(lt));
+                try!(self.print_mutability(m));
                 word(&mut self.s, "self")
             }
             SelfKind::Explicit(ref typ, m) => {
-                self.print_mutability(m)?;
-                word(&mut self.s, "self")?;
-                self.word_space(":")?;
+                try!(self.print_mutability(m));
+                try!(word(&mut self.s, "self"));
+                try!(self.word_space(":"));
                 self.print_type(&typ)
             }
         }
@@ -2650,25 +2648,25 @@ impl<'a> State<'a> {
                     name: Option<ast::Ident>,
                     generics: &ast::Generics,
                     vis: &ast::Visibility) -> io::Result<()> {
-        self.print_fn_header_info(unsafety, constness, abi, vis)?;
+        try!(self.print_fn_header_info(unsafety, constness, abi, vis));
 
         if let Some(name) = name {
-            self.nbsp()?;
-            self.print_ident(name)?;
+            try!(self.nbsp());
+            try!(self.print_ident(name));
         }
-        self.print_generics(generics)?;
-        self.print_fn_args_and_ret(decl)?;
+        try!(self.print_generics(generics));
+        try!(self.print_fn_args_and_ret(decl));
         self.print_where_clause(&generics.where_clause)
     }
 
     pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl)
         -> io::Result<()> {
-        self.popen()?;
-        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
+        try!(self.popen());
+        try!(self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false)));
         if decl.variadic {
-            word(&mut self.s, ", ...")?;
+            try!(word(&mut self.s, ", ..."));
         }
-        self.pclose()?;
+        try!(self.pclose());
 
         self.print_fn_output(decl)
     }
@@ -2677,24 +2675,24 @@ impl<'a> State<'a> {
             &mut self,
             decl: &ast::FnDecl)
             -> io::Result<()> {
-        word(&mut self.s, "|")?;
-        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
-        word(&mut self.s, "|")?;
+        try!(word(&mut self.s, "|"));
+        try!(self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true)));
+        try!(word(&mut self.s, "|"));
 
         if let ast::FunctionRetTy::Default(..) = decl.output {
             return Ok(());
         }
 
-        self.space_if_not_bol()?;
-        self.word_space("->")?;
+        try!(self.space_if_not_bol());
+        try!(self.word_space("->"));
         match decl.output {
             ast::FunctionRetTy::Ty(ref ty) => {
-                self.print_type(&ty)?;
+                try!(self.print_type(&ty));
                 self.maybe_print_comment(ty.span.lo)
             }
             ast::FunctionRetTy::Default(..) => unreachable!(),
             ast::FunctionRetTy::None(span) => {
-                self.word_nbsp("!")?;
+                try!(self.word_nbsp("!"));
                 self.maybe_print_comment(span.lo)
             }
         }
@@ -2713,28 +2711,28 @@ impl<'a> State<'a> {
                         bounds: &[ast::TyParamBound])
                         -> io::Result<()> {
         if !bounds.is_empty() {
-            word(&mut self.s, prefix)?;
+            try!(word(&mut self.s, prefix));
             let mut first = true;
             for bound in bounds {
-                self.nbsp()?;
+                try!(self.nbsp());
                 if first {
                     first = false;
                 } else {
-                    self.word_space("+")?;
+                    try!(self.word_space("+"));
                 }
 
-                match *bound {
+                try!(match *bound {
                     TraitTyParamBound(ref tref, TraitBoundModifier::None) => {
                         self.print_poly_trait_ref(tref)
                     }
                     TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => {
-                        word(&mut self.s, "?")?;
+                        try!(word(&mut self.s, "?"));
                         self.print_poly_trait_ref(tref)
                     }
                     RegionTyParamBound(ref lt) => {
                         self.print_lifetime(lt)
                     }
-                }?
+                })
             }
             Ok(())
         } else {
@@ -2753,11 +2751,11 @@ impl<'a> State<'a> {
                               lifetime: &ast::LifetimeDef)
                               -> io::Result<()>
     {
-        self.print_lifetime(&lifetime.lifetime)?;
+        try!(self.print_lifetime(&lifetime.lifetime));
         let mut sep = ":";
         for v in &lifetime.bounds {
-            word(&mut self.s, sep)?;
-            self.print_lifetime(v)?;
+            try!(word(&mut self.s, sep));
+            try!(self.print_lifetime(v));
             sep = "+";
         }
         Ok(())
@@ -2772,14 +2770,14 @@ impl<'a> State<'a> {
             return Ok(());
         }
 
-        word(&mut self.s, "<")?;
+        try!(word(&mut self.s, "<"));
 
         let mut ints = Vec::new();
         for i in 0..total {
             ints.push(i);
         }
 
-        self.commasep(Inconsistent, &ints[..], |s, &idx| {
+        try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
             if idx < generics.lifetimes.len() {
                 let lifetime = &generics.lifetimes[idx];
                 s.print_lifetime_def(lifetime)
@@ -2788,19 +2786,19 @@ impl<'a> State<'a> {
                 let param = &generics.ty_params[idx];
                 s.print_ty_param(param)
             }
-        })?;
+        }));
 
-        word(&mut self.s, ">")?;
+        try!(word(&mut self.s, ">"));
         Ok(())
     }
 
     pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
-        self.print_ident(param.ident)?;
-        self.print_bounds(":", &param.bounds)?;
+        try!(self.print_ident(param.ident));
+        try!(self.print_bounds(":", &param.bounds));
         match param.default {
             Some(ref default) => {
-                space(&mut self.s)?;
-                self.word_space("=")?;
+                try!(space(&mut self.s));
+                try!(self.word_space("="));
                 self.print_type(&default)
             }
             _ => Ok(())
@@ -2813,12 +2811,12 @@ impl<'a> State<'a> {
             return Ok(())
         }
 
-        space(&mut self.s)?;
-        self.word_space("where")?;
+        try!(space(&mut self.s));
+        try!(self.word_space("where"));
 
         for (i, predicate) in where_clause.predicates.iter().enumerate() {
             if i != 0 {
-                self.word_space(",")?;
+                try!(self.word_space(","));
             }
 
             match *predicate {
@@ -2826,29 +2824,29 @@ impl<'a> State<'a> {
                                                                              ref bounded_ty,
                                                                              ref bounds,
                                                                              ..}) => {
-                    self.print_formal_lifetime_list(bound_lifetimes)?;
-                    self.print_type(&bounded_ty)?;
-                    self.print_bounds(":", bounds)?;
+                    try!(self.print_formal_lifetime_list(bound_lifetimes));
+                    try!(self.print_type(&bounded_ty));
+                    try!(self.print_bounds(":", bounds));
                 }
                 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
                                                                                ref bounds,
                                                                                ..}) => {
-                    self.print_lifetime(lifetime)?;
-                    word(&mut self.s, ":")?;
+                    try!(self.print_lifetime(lifetime));
+                    try!(word(&mut self.s, ":"));
 
                     for (i, bound) in bounds.iter().enumerate() {
-                        self.print_lifetime(bound)?;
+                        try!(self.print_lifetime(bound));
 
                         if i != 0 {
-                            word(&mut self.s, ":")?;
+                            try!(word(&mut self.s, ":"));
                         }
                     }
                 }
                 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
-                    self.print_path(path, false, 0)?;
-                    space(&mut self.s)?;
-                    self.word_space("=")?;
-                    self.print_type(&ty)?;
+                    try!(self.print_path(path, false, 0));
+                    try!(space(&mut self.s));
+                    try!(self.word_space("="));
+                    try!(self.print_type(&ty));
                 }
             }
         }
@@ -2859,52 +2857,52 @@ impl<'a> State<'a> {
     pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
         match vp.node {
             ast::ViewPathSimple(ident, ref path) => {
-                self.print_path(path, false, 0)?;
+                try!(self.print_path(path, false, 0));
 
                 if path.segments.last().unwrap().identifier.name !=
                         ident.name {
-                    space(&mut self.s)?;
-                    self.word_space("as")?;
-                    self.print_ident(ident)?;
+                    try!(space(&mut self.s));
+                    try!(self.word_space("as"));
+                    try!(self.print_ident(ident));
                 }
 
                 Ok(())
             }
 
             ast::ViewPathGlob(ref path) => {
-                self.print_path(path, false, 0)?;
+                try!(self.print_path(path, false, 0));
                 word(&mut self.s, "::*")
             }
 
             ast::ViewPathList(ref path, ref idents) => {
                 if path.segments.is_empty() {
-                    word(&mut self.s, "{")?;
+                    try!(word(&mut self.s, "{"));
                 } else {
-                    self.print_path(path, false, 0)?;
-                    word(&mut self.s, "::{")?;
+                    try!(self.print_path(path, false, 0));
+                    try!(word(&mut self.s, "::{"));
                 }
-                self.commasep(Inconsistent, &idents[..], |s, w| {
+                try!(self.commasep(Inconsistent, &idents[..], |s, w| {
                     match w.node {
                         ast::PathListItemKind::Ident { name, rename, .. } => {
-                            s.print_ident(name)?;
+                            try!(s.print_ident(name));
                             if let Some(ident) = rename {
-                                space(&mut s.s)?;
-                                s.word_space("as")?;
-                                s.print_ident(ident)?;
+                                try!(space(&mut s.s));
+                                try!(s.word_space("as"));
+                                try!(s.print_ident(ident));
                             }
                             Ok(())
                         },
                         ast::PathListItemKind::Mod { rename, .. } => {
-                            word(&mut s.s, "self")?;
+                            try!(word(&mut s.s, "self"));
                             if let Some(ident) = rename {
-                                space(&mut s.s)?;
-                                s.word_space("as")?;
-                                s.print_ident(ident)?;
+                                try!(space(&mut s.s));
+                                try!(s.word_space("as"));
+                                try!(s.print_ident(ident));
                             }
                             Ok(())
                         }
                     }
-                })?;
+                }));
                 word(&mut self.s, "}")
             }
         }
@@ -2919,17 +2917,17 @@ impl<'a> State<'a> {
     }
 
     pub fn print_mt(&mut self, mt: &ast::MutTy) -> io::Result<()> {
-        self.print_mutability(mt.mutbl)?;
+        try!(self.print_mutability(mt.mutbl));
         self.print_type(&mt.ty)
     }
 
     pub fn print_arg(&mut self, input: &ast::Arg, is_closure: bool) -> io::Result<()> {
-        self.ibox(INDENT_UNIT)?;
+        try!(self.ibox(INDENT_UNIT));
         match input.ty.node {
-            ast::TyKind::Infer if is_closure => self.print_pat(&input.pat)?,
+            ast::TyKind::Infer if is_closure => try!(self.print_pat(&input.pat)),
             _ => {
                 if let Some(eself) = input.to_self() {
-                    self.print_explicit_self(&eself)?;
+                    try!(self.print_explicit_self(&eself));
                 } else {
                     let invalid = if let PatKind::Ident(_, ident, _) = input.pat.node {
                         ident.node.name == keywords::Invalid.name()
@@ -2937,11 +2935,11 @@ impl<'a> State<'a> {
                         false
                     };
                     if !invalid {
-                        self.print_pat(&input.pat)?;
-                        word(&mut self.s, ":")?;
-                        space(&mut self.s)?;
+                        try!(self.print_pat(&input.pat));
+                        try!(word(&mut self.s, ":"));
+                        try!(space(&mut self.s));
                     }
-                    self.print_type(&input.ty)?;
+                    try!(self.print_type(&input.ty));
                 }
             }
         }
@@ -2953,17 +2951,17 @@ impl<'a> State<'a> {
             return Ok(());
         }
 
-        self.space_if_not_bol()?;
-        self.ibox(INDENT_UNIT)?;
-        self.word_space("->")?;
+        try!(self.space_if_not_bol());
+        try!(self.ibox(INDENT_UNIT));
+        try!(self.word_space("->"));
         match decl.output {
             ast::FunctionRetTy::None(_) =>
-                self.word_nbsp("!")?,
+                try!(self.word_nbsp("!")),
             ast::FunctionRetTy::Default(..) => unreachable!(),
             ast::FunctionRetTy::Ty(ref ty) =>
-                self.print_type(&ty)?
+                try!(self.print_type(&ty))
         }
-        self.end()?;
+        try!(self.end());
 
         match decl.output {
             ast::FunctionRetTy::Ty(ref output) => self.maybe_print_comment(output.span.lo),
@@ -2978,10 +2976,10 @@ impl<'a> State<'a> {
                        name: Option<ast::Ident>,
                        generics: &ast::Generics)
                        -> io::Result<()> {
-        self.ibox(INDENT_UNIT)?;
+        try!(self.ibox(INDENT_UNIT));
         if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
-            word(&mut self.s, "for")?;
-            self.print_generics(generics)?;
+            try!(word(&mut self.s, "for"));
+            try!(self.print_generics(generics));
         }
         let generics = ast::Generics {
             lifetimes: Vec::new(),
@@ -2991,13 +2989,13 @@ impl<'a> State<'a> {
                 predicates: Vec::new(),
             },
         };
-        self.print_fn(decl,
+        try!(self.print_fn(decl,
                       unsafety,
                       ast::Constness::NotConst,
                       abi,
                       name,
                       &generics,
-                      &ast::Visibility::Inherited)?;
+                      &ast::Visibility::Inherited));
         self.end()
     }
 
@@ -3008,20 +3006,19 @@ impl<'a> State<'a> {
             Some(cm) => cm,
             _ => return Ok(())
         };
-        match self.next_comment() {
-            Some(ref cmnt) => {
-                if (*cmnt).style != comments::Trailing { return Ok(()) }
-                let span_line = cm.lookup_char_pos(span.hi);
-                let comment_line = cm.lookup_char_pos((*cmnt).pos);
-                let mut next = (*cmnt).pos + BytePos(1);
-                match next_pos { None => (), Some(p) => next = p }
-                if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
-                    span_line.line == comment_line.line {
-                        self.print_comment(cmnt)?;
-                        self.cur_cmnt_and_lit.cur_cmnt += 1;
-                    }
+        if let Some(ref cmnt) = self.next_comment() {
+            if (*cmnt).style != comments::Trailing { return Ok(()) }
+            let span_line = cm.lookup_char_pos(span.hi);
+            let comment_line = cm.lookup_char_pos((*cmnt).pos);
+            let mut next = (*cmnt).pos + BytePos(1);
+            if let Some(p) = next_pos {
+                next = p;
+            }
+            if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
+               span_line.line == comment_line.line {
+                self.print_comment(cmnt)?;
+                self.cur_cmnt_and_lit.cur_cmnt += 1;
             }
-            _ => ()
         }
         Ok(())
     }
@@ -3030,12 +3027,12 @@ impl<'a> State<'a> {
         // If there aren't any remaining comments, then we need to manually
         // make sure there is a line break at the end.
         if self.next_comment().is_none() {
-            hardbreak(&mut self.s)?;
+            try!(hardbreak(&mut self.s));
         }
         loop {
             match self.next_comment() {
                 Some(ref cmnt) => {
-                    self.print_comment(cmnt)?;
+                    try!(self.print_comment(cmnt));
                     self.cur_cmnt_and_lit.cur_cmnt += 1;
                 }
                 _ => break
@@ -3050,7 +3047,7 @@ impl<'a> State<'a> {
         match opt_abi {
             Some(Abi::Rust) => Ok(()),
             Some(abi) => {
-                self.word_nbsp("extern")?;
+                try!(self.word_nbsp("extern"));
                 self.word_nbsp(&abi.to_string())
             }
             None => Ok(())
@@ -3061,7 +3058,7 @@ impl<'a> State<'a> {
                                 opt_abi: Option<Abi>) -> io::Result<()> {
         match opt_abi {
             Some(abi) => {
-                self.word_nbsp("extern")?;
+                try!(self.word_nbsp("extern"));
                 self.word_nbsp(&abi.to_string())
             }
             None => Ok(())
@@ -3073,18 +3070,18 @@ impl<'a> State<'a> {
                                 constness: ast::Constness,
                                 abi: Abi,
                                 vis: &ast::Visibility) -> io::Result<()> {
-        word(&mut self.s, &visibility_qualified(vis, ""))?;
+        try!(word(&mut self.s, &visibility_qualified(vis, "")));
 
         match constness {
             ast::Constness::NotConst => {}
-            ast::Constness::Const => self.word_nbsp("const")?
+            ast::Constness::Const => try!(self.word_nbsp("const"))
         }
 
-        self.print_unsafety(unsafety)?;
+        try!(self.print_unsafety(unsafety));
 
         if abi != Abi::Rust {
-            self.word_nbsp("extern")?;
-            self.word_nbsp(&abi.to_string())?;
+            try!(self.word_nbsp("extern"));
+            try!(self.word_nbsp(&abi.to_string()));
         }
 
         word(&mut self.s, "fn")
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index 84a7b144848..8834c026067 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -12,12 +12,9 @@ use ast;
 use attr;
 use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
 use codemap;
-use fold::Folder;
-use fold;
 use parse::token::{intern, InternedString, keywords};
 use parse::{token, ParseSess};
 use ptr::P;
-use util::small_vector::SmallVector;
 
 /// Craft a span that will be ignored by the stability lint's
 /// call to codemap's is_internal check.
@@ -37,33 +34,6 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
     return sp;
 }
 
-pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option<String>)
-                               -> ast::Crate {
-    if no_core(&krate) {
-        krate
-    } else {
-        let name = if no_std(&krate) {"core"} else {"std"};
-        let mut fold = CrateInjector {
-            item_name: token::str_to_ident(name),
-            crate_name: token::intern(&alt_std_name.unwrap_or(name.to_string())),
-        };
-        fold.fold_crate(krate)
-    }
-}
-
-pub fn maybe_inject_prelude(sess: &ParseSess, krate: ast::Crate) -> ast::Crate {
-    if no_core(&krate) {
-        krate
-    } else {
-        let name = if no_std(&krate) {"core"} else {"std"};
-        let mut fold = PreludeInjector {
-            span: ignored_span(sess, DUMMY_SP),
-            crate_identifier: token::str_to_ident(name),
-        };
-        fold.fold_crate(krate)
-    }
-}
-
 pub fn no_core(krate: &ast::Crate) -> bool {
     attr::contains_name(&krate.attrs, "no_core")
 }
@@ -72,102 +42,54 @@ pub fn no_std(krate: &ast::Crate) -> bool {
     attr::contains_name(&krate.attrs, "no_std") || no_core(krate)
 }
 
-fn no_prelude(attrs: &[ast::Attribute]) -> bool {
-    attr::contains_name(attrs, "no_implicit_prelude")
-}
-
-struct CrateInjector {
-    item_name: ast::Ident,
-    crate_name: ast::Name,
-}
-
-impl fold::Folder for CrateInjector {
-    fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
-        krate.module.items.insert(0, P(ast::Item {
-            id: ast::DUMMY_NODE_ID,
-            ident: self.item_name,
-            attrs: vec!(
-                attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(
-                        InternedString::new("macro_use")))),
-            node: ast::ItemKind::ExternCrate(Some(self.crate_name)),
-            vis: ast::Visibility::Inherited,
-            span: DUMMY_SP
-        }));
-
-        krate
-    }
-}
-
-struct PreludeInjector {
-    span: Span,
-    crate_identifier: ast::Ident,
-}
-
-impl fold::Folder for PreludeInjector {
-    fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
-        // only add `use std::prelude::*;` if there wasn't a
-        // `#![no_implicit_prelude]` at the crate level.
-        // fold_mod() will insert glob path.
-        if !no_prelude(&krate.attrs) {
-            krate.module = self.fold_mod(krate.module);
-        }
-        krate
-    }
-
-    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
-        if !no_prelude(&item.attrs) {
-            // only recur if there wasn't `#![no_implicit_prelude]`
-            // on this item, i.e. this means that the prelude is not
-            // implicitly imported though the whole subtree
-            fold::noop_fold_item(item, self)
-        } else {
-            SmallVector::one(item)
-        }
+pub fn maybe_inject_crates_ref(sess: &ParseSess,
+                               mut krate: ast::Crate,
+                               alt_std_name: Option<String>)
+                               -> ast::Crate {
+    if no_core(&krate) {
+        return krate;
     }
 
-    fn fold_mod(&mut self, mut mod_: ast::Mod) -> ast::Mod {
-        let prelude_path = ast::Path {
-            span: self.span,
+    let name = if no_std(&krate) { "core" } else { "std" };
+    let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string()));
+
+    krate.module.items.insert(0, P(ast::Item {
+        attrs: vec![attr::mk_attr_outer(attr::mk_attr_id(),
+                                        attr::mk_word_item(InternedString::new("macro_use")))],
+        vis: ast::Visibility::Inherited,
+        node: ast::ItemKind::ExternCrate(Some(crate_name)),
+        ident: token::str_to_ident(name),
+        id: ast::DUMMY_NODE_ID,
+        span: DUMMY_SP,
+    }));
+
+    let span = ignored_span(sess, DUMMY_SP);
+    krate.module.items.insert(0, P(ast::Item {
+        attrs: vec![ast::Attribute {
+            node: ast::Attribute_ {
+                style: ast::AttrStyle::Outer,
+                value: P(ast::MetaItem {
+                    node: ast::MetaItemKind::Word(token::intern_and_get_ident("prelude_import")),
+                    span: span,
+                }),
+                id: attr::mk_attr_id(),
+                is_sugared_doc: false,
+            },
+            span: span,
+        }],
+        vis: ast::Visibility::Inherited,
+        node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path {
             global: false,
-            segments: vec![
-                ast::PathSegment {
-                    identifier: self.crate_identifier,
-                    parameters: ast::PathParameters::none(),
-                },
-                ast::PathSegment {
-                    identifier: token::str_to_ident("prelude"),
-                    parameters: ast::PathParameters::none(),
-                },
-                ast::PathSegment {
-                    identifier: token::str_to_ident("v1"),
-                    parameters: ast::PathParameters::none(),
-                },
-            ],
-        };
-
-        let vp = P(codemap::dummy_spanned(ast::ViewPathGlob(prelude_path)));
-        mod_.items.insert(0, P(ast::Item {
-            id: ast::DUMMY_NODE_ID,
-            ident: keywords::Invalid.ident(),
-            node: ast::ItemKind::Use(vp),
-            attrs: vec![ast::Attribute {
-                span: self.span,
-                node: ast::Attribute_ {
-                    id: attr::mk_attr_id(),
-                    style: ast::AttrStyle::Outer,
-                    value: P(ast::MetaItem {
-                        span: self.span,
-                        node: ast::MetaItemKind::Word(
-                            token::intern_and_get_ident("prelude_import")
-                        ),
-                    }),
-                    is_sugared_doc: false,
-                },
-            }],
-            vis: ast::Visibility::Inherited,
-            span: self.span,
-        }));
-
-        fold::noop_fold_mod(mod_, self)
-    }
+            segments: vec![name, "prelude", "v1"].into_iter().map(|name| ast::PathSegment {
+                identifier: token::str_to_ident(name),
+                parameters: ast::PathParameters::none(),
+            }).collect(),
+            span: span,
+        })))),
+        id: ast::DUMMY_NODE_ID,
+        ident: keywords::Invalid.ident(),
+        span: span,
+    }));
+
+    krate
 }
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 6fbbed2ee98..ca6ed76d549 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -25,7 +25,7 @@ use codemap;
 use errors;
 use config;
 use entry::{self, EntryPointType};
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, DummyMacroLoader};
 use ext::build::AstBuilder;
 use ext::expand::ExpansionConfig;
 use fold::Folder;
@@ -81,7 +81,7 @@ pub fn modify_for_testing(sess: &ParseSess,
     if should_test {
         generate_test_harness(sess, reexport_test_harness_main, krate, span_diagnostic)
     } else {
-        strip_test_functions(krate)
+        krate
     }
 }
 
@@ -270,13 +270,13 @@ fn generate_test_harness(sess: &ParseSess,
     let mut cleaner = EntryPointCleaner { depth: 0 };
     let krate = cleaner.fold_crate(krate);
 
-    let mut feature_gated_cfgs = vec![];
+    let mut loader = DummyMacroLoader;
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
         span_diagnostic: sd,
         ext_cx: ExtCtxt::new(sess, vec![],
                              ExpansionConfig::default("test".to_string()),
-                             &mut feature_gated_cfgs),
+                             &mut loader),
         path: Vec::new(),
         testfns: Vec::new(),
         reexport_test_harness_main: reexport_test_harness_main,
@@ -304,19 +304,6 @@ fn generate_test_harness(sess: &ParseSess,
     return res;
 }
 
-fn strip_test_functions(krate: ast::Crate) -> ast::Crate {
-    // When not compiling with --test we should not compile the
-    // #[test] functions
-    struct StripTests;
-    impl config::CfgFolder for StripTests {
-        fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
-            !attr::contains_name(attrs, "test") && !attr::contains_name(attrs, "bench")
-        }
-    }
-
-    StripTests.fold_crate(krate)
-}
-
 /// Craft a span that will be ignored by the stability lint's
 /// call to codemap's is_internal check.
 /// The expanded code calls some unstable functions in the test crate.
diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs
index 8e20358027b..7295b36af0f 100644
--- a/src/libsyntax/util/interner.rs
+++ b/src/libsyntax/util/interner.rs
@@ -47,9 +47,8 @@ impl<T: Eq + Hash + Clone + 'static> Interner<T> {
 
     pub fn intern(&self, val: T) -> Name {
         let mut map = self.map.borrow_mut();
-        match (*map).get(&val) {
-            Some(&idx) => return idx,
-            None => (),
+        if let Some(&idx) = (*map).get(&val) {
+            return idx;
         }
 
         let mut vect = self.vect.borrow_mut();
@@ -161,9 +160,8 @@ impl StrInterner {
 
     pub fn intern(&self, val: &str) -> Name {
         let mut map = self.map.borrow_mut();
-        match map.get(val) {
-            Some(&idx) => return idx,
-            None => (),
+        if let Some(&idx) = map.get(val) {
+            return idx;
         }
 
         let new_idx = Name(self.len() as u32);
diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs
index 8358af69b66..06264196d9e 100644
--- a/src/libsyntax/util/parser_testing.rs
+++ b/src/libsyntax/util/parser_testing.rs
@@ -19,7 +19,7 @@ use std::iter::Peekable;
 /// Map a string to tts, using a made-up filename:
 pub fn string_to_tts(source_str: String) -> Vec<ast::TokenTree> {
     let ps = ParseSess::new();
-    filemap_to_tts(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str))
+    filemap_to_tts(&ps, ps.codemap().new_filemap("bogofile".to_string(), None, source_str))
 }
 
 /// Map string to parser (via tts)
diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs
index 8b07b21c578..893646f121f 100644
--- a/src/libsyntax/util/small_vector.rs
+++ b/src/libsyntax/util/small_vector.rs
@@ -29,6 +29,16 @@ enum SmallVectorRepr<T> {
     Many(Vec<T>),
 }
 
+impl<T> Into<Vec<T>> for SmallVector<T> {
+    fn into(self) -> Vec<T> {
+        match self.repr {
+            Zero => Vec::new(),
+            One(t) => vec![t],
+            Many(vec) => vec,
+        }
+    }
+}
+
 impl<T> FromIterator<T> for SmallVector<T> {
     fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> SmallVector<T> {
         let mut v = SmallVector::zero();
@@ -136,6 +146,15 @@ impl<T> SmallVector<T> {
     }
 
     pub fn is_empty(&self) -> bool { self.len() == 0 }
+
+    pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> SmallVector<U> {
+        let repr = match self.repr {
+            Zero => Zero,
+            One(t) => One(f(t)),
+            Many(vec) => Many(vec.into_iter().map(f).collect()),
+        };
+        SmallVector { repr: repr }
+    }
 }
 
 impl<T> IntoIterator for SmallVector<T> {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index a1d8e056b02..07a6317706b 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -185,6 +185,9 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
 }
 
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
+    for attr in local.attrs.as_attr_slice() {
+        visitor.visit_attribute(attr);
+    }
     visitor.visit_pat(&local.pat);
     walk_list!(visitor, visit_ty, &local.ty);
     walk_list!(visitor, visit_expr, &local.init);
@@ -635,6 +638,9 @@ pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) {
 }
 
 pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
+    for attr in expression.attrs.as_attr_slice() {
+        visitor.visit_attribute(attr);
+    }
     match expression.node {
         ExprKind::Box(ref subexpression) => {
             visitor.visit_expr(subexpression)
diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs
index bae0462b8d3..593bf14a018 100644
--- a/src/libsyntax_ext/cfg.rs
+++ b/src/libsyntax_ext/cfg.rs
@@ -19,7 +19,6 @@ use syntax::ext::base;
 use syntax::ext::build::AstBuilder;
 use syntax::attr;
 use syntax::parse::token;
-use syntax::config::CfgDiagReal;
 
 pub fn expand_cfg<'cx>(cx: &mut ExtCtxt,
                        sp: Span,
@@ -33,12 +32,6 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt,
         return DummyResult::expr(sp);
     }
 
-    let matches_cfg = {
-        let mut diag = CfgDiagReal {
-            diag: &cx.parse_sess.span_diagnostic,
-            feature_gated_cfgs: cx.feature_gated_cfgs,
-        };
-        attr::cfg_matches(&cx.cfg, &cfg, &mut diag)
-    };
+    let matches_cfg = attr::cfg_matches(&cx.cfg, &cfg, cx.parse_sess, cx.ecfg.features);
     MacEager::expr(cx.expr_bool(sp, matches_cfg))
 }
diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs
index d1b6fe6655a..150abc226e6 100644
--- a/src/rtstartup/rsbegin.rs
+++ b/src/rtstartup/rsbegin.rs
@@ -27,8 +27,7 @@
 #![allow(non_camel_case_types)]
 
 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
-pub mod eh_frames
-{
+pub mod eh_frames {
     #[no_mangle]
     #[link_section = ".eh_frame"]
     // Marks beginning of the stack frame unwind info section
@@ -40,7 +39,7 @@ pub mod eh_frames
 
     // Unwind info registration/deregistration routines.
     // See the docs of `unwind` module in libstd.
-    extern {
+    extern "C" {
         fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8);
         fn rust_eh_unregister_frames(eh_frame_begin: *const u8, object: *mut u8);
     }
@@ -58,8 +57,7 @@ pub mod eh_frames
     }
 
     // MSVC-specific init/uninit routine registration
-    pub mod ms_init
-    {
+    pub mod ms_init {
         // .CRT$X?? sections are roughly analogous to ELF's .init_array and .fini_array,
         // except that they exploit the fact that linker will sort them alphabitically,
         // so e.g. sections with names between .CRT$XIA and .CRT$XIZ are guaranteed to be
diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs
index 5e4e13ebd05..915c2355b04 100644
--- a/src/rtstartup/rsend.rs
+++ b/src/rtstartup/rsend.rs
@@ -14,8 +14,7 @@
 #![no_std]
 
 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
-pub mod eh_frames
-{
+pub mod eh_frames {
     // Terminate the frame unwind info section with a 0 as a sentinel;
     // this would be the 'length' field in a real FDE.
     #[no_mangle]
diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock
index 931f90a2394..3e8277e28ba 100644
--- a/src/rustc/Cargo.lock
+++ b/src/rustc/Cargo.lock
@@ -87,6 +87,7 @@ dependencies = [
  "graphviz 0.0.0",
  "log 0.0.0",
  "rustc 0.0.0",
+ "rustc_data_structures 0.0.0",
  "rustc_mir 0.0.0",
  "syntax 0.0.0",
 ]
@@ -238,7 +239,6 @@ dependencies = [
  "rustc_back 0.0.0",
  "rustc_bitflags 0.0.0",
  "rustc_metadata 0.0.0",
- "rustc_mir 0.0.0",
  "syntax 0.0.0",
 ]
 
@@ -285,7 +285,6 @@ dependencies = [
  "rustc_data_structures 0.0.0",
  "rustc_incremental 0.0.0",
  "rustc_llvm 0.0.0",
- "rustc_mir 0.0.0",
  "rustc_platform_intrinsics 0.0.0",
  "serialize 0.0.0",
  "syntax 0.0.0",
diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp
index d3f2907bfc3..1e7b04c814c 100644
--- a/src/rustllvm/ArchiveWrapper.cpp
+++ b/src/rustllvm/ArchiveWrapper.cpp
@@ -11,10 +11,7 @@
 #include "rustllvm.h"
 
 #include "llvm/Object/Archive.h"
-
-#if LLVM_VERSION_MINOR >= 7
 #include "llvm/Object/ArchiveWriter.h"
-#endif
 
 using namespace llvm;
 using namespace llvm::object;
@@ -34,13 +31,7 @@ struct LLVMRustArchiveMember {
   ~LLVMRustArchiveMember() {}
 };
 
-#if LLVM_VERSION_MINOR >= 6
 typedef OwningBinary<Archive> RustArchive;
-#define GET_ARCHIVE(a) ((a)->getBinary())
-#else
-typedef Archive RustArchive;
-#define GET_ARCHIVE(a) (a)
-#endif
 
 extern "C" void*
 LLVMRustOpenArchive(char *path) {
@@ -52,7 +43,6 @@ LLVMRustOpenArchive(char *path) {
         return nullptr;
     }
 
-#if LLVM_VERSION_MINOR >= 6
     ErrorOr<std::unique_ptr<Archive>> archive_or =
         Archive::create(buf_or.get()->getMemBufferRef());
 
@@ -63,14 +53,6 @@ LLVMRustOpenArchive(char *path) {
 
     OwningBinary<Archive> *ret = new OwningBinary<Archive>(
             std::move(archive_or.get()), std::move(buf_or.get()));
-#else
-    std::error_code err;
-    Archive *ret = new Archive(std::move(buf_or.get()), err);
-    if (err) {
-        LLVMRustSetLastError(err.message().c_str());
-        return nullptr;
-    }
-#endif
 
     return ret;
 }
@@ -87,7 +69,7 @@ struct RustArchiveIterator {
 
 extern "C" RustArchiveIterator*
 LLVMRustArchiveIteratorNew(RustArchive *ra) {
-    Archive *ar = GET_ARCHIVE(ra);
+    Archive *ar = ra->getBinary();
     RustArchiveIterator *rai = new RustArchiveIterator();
     rai->cur = ar->child_begin();
     rai->end = ar->child_end();
@@ -137,16 +119,12 @@ LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) {
 extern "C" const char*
 LLVMRustArchiveChildData(Archive::Child *child, size_t *size) {
     StringRef buf;
-#if LLVM_VERSION_MINOR >= 7
     ErrorOr<StringRef> buf_or_err = child->getBuffer();
     if (buf_or_err.getError()) {
       LLVMRustSetLastError(buf_or_err.getError().message().c_str());
       return NULL;
     }
     buf = buf_or_err.get();
-#else
-    buf = child->getBuffer();
-#endif
     *size = buf.size();
     return buf.data();
 }
@@ -172,7 +150,6 @@ LLVMRustWriteArchive(char *Dst,
                      const LLVMRustArchiveMember **NewMembers,
                      bool WriteSymbtab,
                      Archive::Kind Kind) {
-#if LLVM_VERSION_MINOR >= 7
   std::vector<NewArchiveIterator> Members;
 
   for (size_t i = 0; i < NumMembers; i++) {
@@ -196,8 +173,5 @@ LLVMRustWriteArchive(char *Dst,
   if (!pair.second)
     return 0;
   LLVMRustSetLastError(pair.second.message().c_str());
-#else
-  LLVMRustSetLastError("writing archives not supported with this LLVM version");
-#endif
   return -1;
 }
diff --git a/src/rustllvm/ExecutionEngineWrapper.cpp b/src/rustllvm/ExecutionEngineWrapper.cpp
index 8b01cac820e..b26ab446019 100644
--- a/src/rustllvm/ExecutionEngineWrapper.cpp
+++ b/src/rustllvm/ExecutionEngineWrapper.cpp
@@ -90,13 +90,8 @@ extern "C" LLVMExecutionEngineRef LLVMBuildExecutionEngine(LLVMModuleRef mod)
     RustJITMemoryManager *mm = new RustJITMemoryManager;
 
     ExecutionEngine *ee =
-    #if LLVM_VERSION_MINOR >= 6
         EngineBuilder(std::unique_ptr<Module>(unwrap(mod)))
             .setMCJITMemoryManager(std::unique_ptr<RustJITMemoryManager>(mm))
-    #else
-        EngineBuilder(unwrap(mod))
-            .setMCJITMemoryManager(mm)
-    #endif
             .setEngineKind(EngineKind::JIT)
             .setErrorStr(&error_str)
             .setTargetOptions(options)
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index b3d4e35d7b0..3564f338a02 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -15,12 +15,8 @@
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Host.h"
-#if LLVM_VERSION_MINOR >= 7
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
-#else
-#include "llvm/Target/TargetLibraryInfo.h"
-#endif
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetSubtargetInfo.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
@@ -49,7 +45,7 @@ LLVMInitializePasses() {
   initializeVectorization(Registry);
   initializeIPO(Registry);
   initializeAnalysis(Registry);
-#if LLVM_VERSION_MINOR <= 7
+#if LLVM_VERSION_MINOR == 7
   initializeIPA(Registry);
 #endif
   initializeTransformUtils(Registry);
@@ -223,17 +219,8 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
                           LLVMPassManagerRef PMR,
                           LLVMModuleRef M) {
     PassManagerBase *PM = unwrap(PMR);
-#if LLVM_VERSION_MINOR >= 7
     PM->add(createTargetTransformInfoWrapperPass(
           unwrap(TM)->getTargetIRAnalysis()));
-#else
-#if LLVM_VERSION_MINOR == 6
-    PM->add(new DataLayoutPass());
-#else
-    PM->add(new DataLayoutPass(unwrap(M)));
-#endif
-    unwrap(TM)->addAnalysisPasses(*PM);
-#endif
 }
 
 extern "C" void
@@ -242,10 +229,8 @@ LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB,
                                     bool MergeFunctions,
                                     bool SLPVectorize,
                                     bool LoopVectorize) {
-#if LLVM_VERSION_MINOR >= 6
     // Ignore mergefunc for now as enabling it causes crashes.
     //unwrap(PMB)->MergeFunctions = MergeFunctions;
-#endif
     unwrap(PMB)->SLPVectorize = SLPVectorize;
     unwrap(PMB)->OptLevel = OptLevel;
     unwrap(PMB)->LoopVectorize = LoopVectorize;
@@ -258,11 +243,7 @@ LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB,
                               LLVMModuleRef M,
                               bool DisableSimplifyLibCalls) {
     Triple TargetTriple(unwrap(M)->getTargetTriple());
-#if LLVM_VERSION_MINOR >= 7
     TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple);
-#else
-    TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
-#endif
     if (DisableSimplifyLibCalls)
       TLI->disableAllFunctions();
     unwrap(PMB)->LibraryInfo = TLI;
@@ -275,17 +256,10 @@ LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB,
                        LLVMModuleRef M,
                        bool DisableSimplifyLibCalls) {
     Triple TargetTriple(unwrap(M)->getTargetTriple());
-#if LLVM_VERSION_MINOR >= 7
     TargetLibraryInfoImpl TLII(TargetTriple);
     if (DisableSimplifyLibCalls)
       TLII.disableAllFunctions();
     unwrap(PMB)->add(new TargetLibraryInfoWrapperPass(TLII));
-#else
-    TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
-    if (DisableSimplifyLibCalls)
-      TLI->disableAllFunctions();
-    unwrap(PMB)->add(TLI);
-#endif
 }
 
 // Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
@@ -323,25 +297,16 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target,
   PassManager *PM = unwrap<PassManager>(PMR);
 
   std::string ErrorInfo;
-#if LLVM_VERSION_MINOR >= 6
   std::error_code EC;
   raw_fd_ostream OS(path, EC, sys::fs::F_None);
   if (EC)
     ErrorInfo = EC.message();
-#else
-  raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_None);
-#endif
   if (ErrorInfo != "") {
     LLVMRustSetLastError(ErrorInfo.c_str());
     return false;
   }
 
-#if LLVM_VERSION_MINOR >= 7
   unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false);
-#else
-  formatted_raw_ostream FOS(OS);
-  unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false);
-#endif
   PM->run(*unwrap(M));
 
   // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output
@@ -358,14 +323,10 @@ LLVMRustPrintModule(LLVMPassManagerRef PMR,
   PassManager *PM = unwrap<PassManager>(PMR);
   std::string ErrorInfo;
 
-#if LLVM_VERSION_MINOR >= 6
   std::error_code EC;
   raw_fd_ostream OS(path, EC, sys::fs::F_None);
   if (EC)
     ErrorInfo = EC.message();
-#else
-  raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_None);
-#endif
 
   formatted_raw_ostream FOS(OS);
 
@@ -428,22 +389,10 @@ extern "C" void
 LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module,
                                        LLVMTargetMachineRef TMR) {
     TargetMachine *Target = unwrap(TMR);
-#if LLVM_VERSION_MINOR >= 7
     unwrap(Module)->setDataLayout(Target->createDataLayout());
-#elif LLVM_VERSION_MINOR >= 6
-    if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout())
-        unwrap(Module)->setDataLayout(DL);
-#else
-    if (const DataLayout *DL = Target->getDataLayout())
-        unwrap(Module)->setDataLayout(DL);
-#endif
 }
 
 extern "C" LLVMTargetDataRef
 LLVMRustGetModuleDataLayout(LLVMModuleRef M) {
-#if LLVM_VERSION_MINOR >= 7
     return wrap(&unwrap(M)->getDataLayout());
-#else
-    return wrap(unwrap(M)->getDataLayout());
-#endif
 }
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 697b2d3f539..fadd95c9a72 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -243,7 +243,6 @@ extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty,
 
 typedef DIBuilder* DIBuilderRef;
 
-#if LLVM_VERSION_MINOR >= 6
 typedef struct LLVMOpaqueMetadata *LLVMMetadataRef;
 
 namespace llvm {
@@ -253,29 +252,15 @@ inline Metadata **unwrap(LLVMMetadataRef *Vals) {
   return reinterpret_cast<Metadata**>(Vals);
 }
 }
-#else
-typedef LLVMValueRef LLVMMetadataRef;
-#endif
 
 template<typename DIT>
 DIT* unwrapDIptr(LLVMMetadataRef ref) {
     return (DIT*) (ref ? unwrap<MDNode>(ref) : NULL);
 }
 
-#if LLVM_VERSION_MINOR <= 6
-template<typename DIT>
-DIT unwrapDI(LLVMMetadataRef ref) {
-    return DIT(ref ? unwrap<MDNode>(ref) : NULL);
-}
-#else
 #define DIDescriptor DIScope
 #define DIArray DINodeArray
 #define unwrapDI unwrapDIptr
-#endif
-
-#if LLVM_VERSION_MINOR <= 5
-#define DISubroutineType DICompositeType
-#endif
 
 extern "C" uint32_t LLVMRustDebugMetadataVersion() {
     return DEBUG_METADATA_VERSION;
@@ -339,16 +324,10 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType(
     LLVMMetadataRef File,
     LLVMMetadataRef ParameterTypes) {
     return wrap(Builder->createSubroutineType(
-#if LLVM_VERSION_MINOR <= 7
+#if LLVM_VERSION_MINOR == 7
         unwrapDI<DIFile>(File),
 #endif
-#if LLVM_VERSION_MINOR >= 7
         DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
-#elif LLVM_VERSION_MINOR >= 6
-        unwrapDI<DITypeArray>(ParameterTypes)));
-#else
-        unwrapDI<DIArray>(ParameterTypes)));
-#endif
 }
 
 extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction(
@@ -435,11 +414,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType(
         AlignInBits,
         Flags,
         unwrapDI<DIType>(DerivedFrom),
-#if LLVM_VERSION_MINOR >= 7
         DINodeArray(unwrapDI<MDTuple>(Elements)),
-#else
-        unwrapDI<DIArray>(Elements),
-#endif
         RunTimeLang,
         unwrapDI<DIType>(VTableHolder),
         UniqueId
@@ -473,9 +448,6 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock(
     return wrap(Builder->createLexicalBlock(
         unwrapDI<DIDescriptor>(Scope),
         unwrapDI<DIFile>(File), Line, Col
-#if LLVM_VERSION_MINOR == 5
-        , 0
-#endif
         ));
 }
 
@@ -490,11 +462,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable(
     bool isLocalToUnit,
     LLVMValueRef Val,
     LLVMMetadataRef Decl = NULL) {
-#if LLVM_VERSION_MINOR >= 6
     return wrap(Builder->createGlobalVariable(unwrapDI<DIDescriptor>(Context),
-#else
-    return wrap(Builder->createStaticVariable(unwrapDI<DIDescriptor>(Context),
-#endif
         Name,
         LinkageName,
         unwrapDI<DIFile>(File),
@@ -518,25 +486,6 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable(
     int64_t* AddrOps,
     unsigned AddrOpsCount,
     unsigned ArgNo) {
-#if LLVM_VERSION_MINOR == 5
-    if (AddrOpsCount > 0) {
-        SmallVector<llvm::Value *, 16> addr_ops;
-        llvm::Type *Int64Ty = Type::getInt64Ty(unwrap<MDNode>(Scope)->getContext());
-        for (unsigned i = 0; i < AddrOpsCount; ++i)
-            addr_ops.push_back(ConstantInt::get(Int64Ty, AddrOps[i]));
-
-        return wrap(Builder->createComplexVariable(
-            Tag,
-            unwrapDI<DIDescriptor>(Scope),
-            Name,
-            unwrapDI<DIFile>(File),
-            LineNo,
-            unwrapDI<DIType>(Ty),
-            addr_ops,
-            ArgNo
-        ));
-    }
-#endif
 #if LLVM_VERSION_MINOR >= 8
     if (Tag == 0x100) { // DW_TAG_auto_variable
         return wrap(Builder->createAutoVariable(
@@ -568,11 +517,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType(
     LLVMMetadataRef Subscripts) {
     return wrap(Builder->createArrayType(Size, AlignInBits,
         unwrapDI<DIType>(Ty),
-#if LLVM_VERSION_MINOR >= 7
         DINodeArray(unwrapDI<MDTuple>(Subscripts))
-#else
-        unwrapDI<DIArray>(Subscripts)
-#endif
     ));
 }
 
@@ -584,11 +529,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType(
     LLVMMetadataRef Subscripts) {
     return wrap(Builder->createVectorType(Size, AlignInBits,
         unwrapDI<DIType>(Ty),
-#if LLVM_VERSION_MINOR >= 7
         DINodeArray(unwrapDI<MDTuple>(Subscripts))
-#else
-        unwrapDI<DIArray>(Subscripts)
-#endif
     ));
 }
 
@@ -603,18 +544,9 @@ extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateArray(
     DIBuilderRef Builder,
     LLVMMetadataRef* Ptr,
     unsigned Count) {
-#if LLVM_VERSION_MINOR >= 7
     Metadata **DataValue = unwrap(Ptr);
     return wrap(Builder->getOrCreateArray(
         ArrayRef<Metadata*>(DataValue, Count)).get());
-#else
-    return wrap(Builder->getOrCreateArray(
-#if LLVM_VERSION_MINOR >= 6
-        ArrayRef<Metadata*>(unwrap(Ptr), Count)));
-#else
-        ArrayRef<Value*>(reinterpret_cast<Value**>(Ptr), Count)));
-#endif
-#endif
 }
 
 extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd(
@@ -627,18 +559,10 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd(
     LLVMBasicBlockRef InsertAtEnd) {
     return wrap(Builder->insertDeclare(
         unwrap(Val),
-#if LLVM_VERSION_MINOR >= 7
         unwrap<DILocalVariable>(VarInfo),
-#else
-        unwrapDI<DIVariable>(VarInfo),
-#endif
-#if LLVM_VERSION_MINOR >= 6
         Builder->createExpression(
           llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
-#endif
-#if LLVM_VERSION_MINOR >= 7
         DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())),
-#endif
         unwrap(InsertAtEnd)));
 }
 
@@ -650,22 +574,12 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore(
     unsigned AddrOpsCount,
     LLVMValueRef DL,
     LLVMValueRef InsertBefore) {
-#if LLVM_VERSION_MINOR >= 6
-#endif
     return wrap(Builder->insertDeclare(
         unwrap(Val),
-#if LLVM_VERSION_MINOR >= 7
         unwrap<DILocalVariable>(VarInfo),
-#else
-        unwrapDI<DIVariable>(VarInfo),
-#endif
-#if LLVM_VERSION_MINOR >= 6
         Builder->createExpression(
           llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
-#endif
-#if LLVM_VERSION_MINOR >= 7
         DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())),
-#endif
         unwrap<Instruction>(InsertBefore)));
 }
 
@@ -695,11 +609,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType(
         LineNumber,
         SizeInBits,
         AlignInBits,
-#if LLVM_VERSION_MINOR >= 7
         DINodeArray(unwrapDI<MDTuple>(Elements)),
-#else
-        unwrapDI<DIArray>(Elements),
-#endif
         unwrapDI<DIType>(ClassType)));
 }
 
@@ -724,11 +634,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType(
         SizeInBits,
         AlignInBits,
         Flags,
-#if LLVM_VERSION_MINOR >= 7
         DINodeArray(unwrapDI<MDTuple>(Elements)),
-#else
-        unwrapDI<DIArray>(Elements),
-#endif
         RunTimeLang,
         UniqueId
         ));
@@ -747,12 +653,6 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope),
       Name,
       unwrapDI<DIType>(Ty)
-#if LLVM_VERSION_MINOR <= 6
-      ,
-      unwrapDI<MDNode*>(File),
-      LineNo,
-      ColumnNo
-#endif
       ));
 }
 
@@ -785,15 +685,8 @@ extern "C" void LLVMDICompositeTypeSetTypeArray(
     LLVMMetadataRef CompositeType,
     LLVMMetadataRef TypeArray)
 {
-#if LLVM_VERSION_MINOR >= 7
     DICompositeType *tmp = unwrapDI<DICompositeType>(CompositeType);
     Builder->replaceArrays(tmp, DINodeArray(unwrap<MDTuple>(TypeArray)));
-#elif LLVM_VERSION_MINOR >= 6
-    DICompositeType tmp = unwrapDI<DICompositeType>(CompositeType);
-    Builder->replaceArrays(tmp, unwrapDI<DIArray>(TypeArray));
-#else
-    unwrapDI<DICompositeType>(CompositeType).setTypeArray(unwrapDI<DIArray>(TypeArray));
-#endif
 }
 
 extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation(
@@ -810,15 +703,7 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation(
                                        unwrapDIptr<MDNode>(Scope),
                                        unwrapDIptr<MDNode>(InlinedAt));
 
-#if LLVM_VERSION_MINOR >= 6
-    return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode(
-#if LLVM_VERSION_MINOR <= 6
-            context
-#endif
-        )));
-#else
-    return wrap(debug_loc.getAsMDNode(context));
-#endif
+    return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode()));
 }
 
 extern "C" void LLVMWriteTypeToString(LLVMTypeRef Type, RustStringRef str) {
@@ -838,40 +723,22 @@ extern "C" void LLVMWriteValueToString(LLVMValueRef Value, RustStringRef str) {
 extern "C" bool
 LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) {
     Module *Dst = unwrap(dst);
-#if LLVM_VERSION_MINOR >= 6
     std::unique_ptr<MemoryBuffer> buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
-#if LLVM_VERSION_MINOR >= 7
     ErrorOr<std::unique_ptr<Module>> Src =
         llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext());
-#else
-    ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext());
-#endif
-#else
-    MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
-    ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(buf, Dst->getContext());
-#endif
     if (!Src) {
         LLVMRustSetLastError(Src.getError().message().c_str());
-#if LLVM_VERSION_MINOR == 5
-        delete buf;
-#endif
         return false;
     }
 
     std::string Err;
 
-#if LLVM_VERSION_MINOR >= 6
     raw_string_ostream Stream(Err);
     DiagnosticPrinterRawOStream DP(Stream);
 #if LLVM_VERSION_MINOR >= 8
     if (Linker::linkModules(*Dst, std::move(Src.get()))) {
-#elif LLVM_VERSION_MINOR >= 7
-    if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) {
-#else
-    if (Linker::LinkModules(Dst, *Src, [&](const DiagnosticInfo &DI) { DI.print(DP); })) {
-#endif
 #else
-    if (Linker::LinkModules(Dst, *Src, Linker::DestroySource, &Err)) {
+    if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) {
 #endif
         LLVMRustSetLastError(Err.c_str());
         return false;
@@ -975,11 +842,7 @@ extern "C" void LLVMWriteDebugLocToString(
     RustStringRef str)
 {
     raw_rust_string_ostream os(str);
-#if LLVM_VERSION_MINOR >= 7
     unwrap(dl)->print(os);
-#else
-    unwrap(dl)->print(*unwrap(C), os);
-#endif
 }
 
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
diff --git a/src/test/codegen-units/item-collection/generic-impl.rs b/src/test/codegen-units/item-collection/generic-impl.rs
index a27515fd39b..14316a55732 100644
--- a/src/test/codegen-units/item-collection/generic-impl.rs
+++ b/src/test/codegen-units/item-collection/generic-impl.rs
@@ -77,5 +77,3 @@ fn main() {
     //~ TRANS_ITEM fn generic_impl::id[0]<generic_impl::Struct[0]<&str>>
     let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str"));
 }
-
-//~ TRANS_ITEM drop-glue i8
diff --git a/src/test/codegen/issue-32031.rs b/src/test/codegen/issue-32031.rs
new file mode 100644
index 00000000000..5d3ccbfa4ce
--- /dev/null
+++ b/src/test/codegen/issue-32031.rs
@@ -0,0 +1,33 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub struct F32(f32);
+
+// CHECK: define float @add_newtype_f32(float, float)
+#[inline(never)]
+#[no_mangle]
+pub fn add_newtype_f32(a: F32, b: F32) -> F32 {
+    F32(a.0 + b.0)
+}
+
+#[no_mangle]
+pub struct F64(f64);
+
+// CHECK: define double @add_newtype_f64(double, double)
+#[inline(never)]
+#[no_mangle]
+pub fn add_newtype_f64(a: F64, b: F64) -> F64 {
+    F64(a.0 + b.0)
+}
diff --git a/src/test/codegen/issue-32364.rs b/src/test/codegen/issue-32364.rs
new file mode 100644
index 00000000000..926987be0e0
--- /dev/null
+++ b/src/test/codegen/issue-32364.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.
+
+// compile-flags: -C no-prepopulate-passes
+
+struct Foo;
+
+impl Foo {
+// CHECK: define internal x86_stdcallcc void @{{.*}}foo{{.*}}()
+    #[inline(never)]
+    pub extern "stdcall" fn foo<T>() {
+    }
+}
+
+fn main() {
+    Foo::foo::<Foo>();
+}
diff --git a/src/test/codegen/loads.rs b/src/test/codegen/loads.rs
index 21f23b6ea18..a65a3e1bb66 100644
--- a/src/test/codegen/loads.rs
+++ b/src/test/codegen/loads.rs
@@ -11,6 +11,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
+#![feature(rustc_attrs)]
 
 pub struct Bytes {
   a: u8,
@@ -21,6 +22,7 @@ pub struct Bytes {
 
 // CHECK-LABEL: @borrow
 #[no_mangle]
+#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn borrow(x: &i32) -> &i32 {
 // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull
     x
@@ -28,6 +30,7 @@ pub fn borrow(x: &i32) -> &i32 {
 
 // CHECK-LABEL: @_box
 #[no_mangle]
+#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn _box(x: Box<i32>) -> i32 {
 // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull
     *x
diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs
index 0a600f4acad..199f7f02018 100644
--- a/src/test/codegen/naked-functions.rs
+++ b/src/test/codegen/naked-functions.rs
@@ -13,7 +13,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(naked_functions)]
+#![feature(naked_functions, rustc_attrs)]
 
 // CHECK: Function Attrs: naked uwtable
 // CHECK-NEXT: define internal void @naked_empty()
@@ -26,6 +26,7 @@ fn naked_empty() {
 // CHECK: Function Attrs: naked uwtable
 #[no_mangle]
 #[naked]
+#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}})
 fn naked_with_args(a: isize) {
     // CHECK: %a = alloca i{{[0-9]+}}
@@ -45,6 +46,7 @@ fn naked_with_return() -> isize {
 // CHECK-NEXT: define internal i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
 #[no_mangle]
 #[naked]
+#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 fn naked_with_args_and_return(a: isize) -> isize {
     // CHECK: %a = alloca i{{[0-9]+}}
     // CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs
index 8c425507975..89bb5d93c74 100644
--- a/src/test/codegen/stores.rs
+++ b/src/test/codegen/stores.rs
@@ -26,8 +26,12 @@ pub struct Bytes {
 #[no_mangle]
 #[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
-// CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 1
-// CHECK: [[VAR:%[0-9]+]] = bitcast i32* %{{.*}} to [4 x i8]*
+// CHECK: %y = alloca [4 x i8]
+// CHECK: [[TMP:%.+]] = alloca i32
+// CHECK: store i32 %1, i32* [[TMP]]
+// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8*
+// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false)
     *x = y;
 }
 
@@ -37,7 +41,11 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
 #[no_mangle]
 #[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) {
-// CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 1
-// CHECK: [[VAR:%[0-9]+]] = bitcast i32* %{{.*}} to %Bytes*
+// CHECK: %y = alloca %Bytes
+// CHECK: [[TMP:%.+]] = alloca i32
+// CHECK: store i32 %1, i32* [[TMP]]
+// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8*
+// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false)
     *x = y;
 }
diff --git a/src/test/codegen/zip.rs b/src/test/codegen/zip.rs
new file mode 100644
index 00000000000..6c956364bf8
--- /dev/null
+++ b/src/test/codegen/zip.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.
+
+// compile-flags: -C no-prepopulate-passes -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @zip_copy
+#[no_mangle]
+pub fn zip_copy(xs: &[u8], ys: &mut [u8]) {
+// CHECK: memcpy
+    for (x, y) in xs.iter().zip(ys) {
+        *y = *x;
+    }
+}
diff --git a/src/test/compile-fail-fulldeps/issue-18986.rs b/src/test/compile-fail-fulldeps/issue-18986.rs
index 5f7752bb203..4245786295b 100644
--- a/src/test/compile-fail-fulldeps/issue-18986.rs
+++ b/src/test/compile-fail-fulldeps/issue-18986.rs
@@ -15,6 +15,7 @@ pub use use_from_trait_xc::Trait;
 
 fn main() {
     match () {
-        Trait { x: 42 } => () //~ ERROR `Trait` does not name a struct
+        Trait { x: 42 } => () //~ ERROR expected variant, struct or type alias, found trait `Trait`
+        //~^ ERROR `Trait` does not name a struct or a struct variant
     }
 }
diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs
index 3e153a21e5d..89a4869bd69 100644
--- a/src/test/compile-fail-fulldeps/qquote.rs
+++ b/src/test/compile-fail-fulldeps/qquote.rs
@@ -21,10 +21,11 @@ use syntax::print::pprust;
 
 fn main() {
     let ps = syntax::parse::ParseSess::new();
+    let mut loader = syntax::ext::base::DummyMacroLoader;
     let mut cx = syntax::ext::base::ExtCtxt::new(
         &ps, vec![],
         syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
-        &mut Vec::new());
+        &mut loader);
     cx.bt_push(syntax::codemap::ExpnInfo {
         call_site: DUMMY_SP,
         callee: syntax::codemap::NameAndSpan {
diff --git a/src/test/compile-fail/associated-const-private-impl.rs b/src/test/compile-fail/associated-const-private-impl.rs
index be949db0281..6ebe80b5701 100644
--- a/src/test/compile-fail/associated-const-private-impl.rs
+++ b/src/test/compile-fail/associated-const-private-impl.rs
@@ -23,5 +23,5 @@ mod bar1 {
 
 fn main() {
     assert_eq!(1, bar1::Foo::ID);
-    //~^ERROR associated const `ID` is private
+    //~^ERROR associated constant `ID` is private
 }
diff --git a/src/test/compile-fail/bad-format-args.rs b/src/test/compile-fail/bad-format-args.rs
new file mode 100644
index 00000000000..816c696a895
--- /dev/null
+++ b/src/test/compile-fail/bad-format-args.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.
+
+// error-pattern: requires at least a format string argument
+// error-pattern: bad-format-args.rs:19:5: 19:15 note: in this expansion
+
+// error-pattern: expected token: `,`
+// error-pattern: bad-format-args.rs:20:5: 20:19 note: in this expansion
+// error-pattern: bad-format-args.rs:21:5: 21:22 note: in this expansion
+
+fn main() {
+    format!();
+    format!("" 1);
+    format!("", 1 1);
+}
diff --git a/src/test/compile-fail/blind-item-block-middle.rs b/src/test/compile-fail/blind-item-block-middle.rs
index 287eab7a563..f57727b773d 100644
--- a/src/test/compile-fail/blind-item-block-middle.rs
+++ b/src/test/compile-fail/blind-item-block-middle.rs
@@ -12,6 +12,6 @@ mod foo { pub struct bar; }
 
 fn main() {
     let bar = 5;
-    //~^ ERROR cannot be named the same
+    //~^ ERROR let bindings cannot shadow structs
     use foo::bar;
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs
index 15771295743..f595d9d81cc 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs
@@ -24,14 +24,14 @@ pub fn main() {
         Foo { string: "baz".to_string() }
     );
     let x: &[Foo] = &x;
-    match x {
-        [_, tail..] => {
+    match *x {
+        [_, ref tail..] => {
             match tail {
-                [Foo { string: a },
+                &[Foo { string: a },
                 //~^ ERROR cannot move out of borrowed content
                 //~| cannot move out
                 //~| to prevent move
-                 Foo { string: b }] => {
+                  Foo { string: b }] => {
                     //~^ NOTE and here
                 }
                 _ => {
diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs
index 98052ad31a7..63e80b90ac8 100644
--- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs
+++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs
@@ -15,7 +15,7 @@ fn a<'a>() -> &'a [isize] {
     let vec = vec!(1, 2, 3, 4);
     let vec: &[isize] = &vec; //~ ERROR does not live long enough
     let tail = match vec {
-        [_, tail..] => tail,
+        &[_, ref tail..] => tail,
         _ => panic!("a")
     };
     tail
@@ -25,7 +25,7 @@ fn b<'a>() -> &'a [isize] {
     let vec = vec!(1, 2, 3, 4);
     let vec: &[isize] = &vec; //~ ERROR does not live long enough
     let init = match vec {
-        [init.., _] => init,
+        &[ref init.., _] => init,
         _ => panic!("b")
     };
     init
@@ -35,7 +35,7 @@ fn c<'a>() -> &'a [isize] {
     let vec = vec!(1, 2, 3, 4);
     let vec: &[isize] = &vec; //~ ERROR does not live long enough
     let slice = match vec {
-        [_, slice.., _] => slice,
+        &[_, ref slice.., _] => slice,
         _ => panic!("c")
     };
     slice
diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs
index db635893c81..9dfd4d77928 100644
--- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs
+++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs
@@ -14,7 +14,7 @@ fn a() {
     let mut v = vec!(1, 2, 3);
     let vb: &mut [isize] = &mut v;
     match vb {
-        [_a, tail..] => {
+        &mut [_a, ref tail..] => {
             v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
         }
         _ => {}
diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs
index 97dcaeb0bf1..fddb9838c44 100644
--- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs
+++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs
@@ -13,7 +13,7 @@
 fn main() {
     let mut a = [1, 2, 3, 4];
     let t = match a {
-        [1, 2, tail..] => tail,
+        [1, 2, ref tail..] => tail,
         _ => unreachable!()
     };
     println!("t[0]: {}", t[0]);
diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs
index eec6c8473eb..d89b4100789 100644
--- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs
+++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs
@@ -28,7 +28,7 @@ fn b() {
     let mut vec = vec!(box 1, box 2, box 3);
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
-        [_b..] => {
+        &mut [ref _b..] => {
         //~^ borrow of `vec[..]` occurs here
             vec[0] = box 4; //~ ERROR cannot assign
             //~^ assignment to borrowed `vec[..]` occurs here
@@ -40,10 +40,11 @@ fn c() {
     let mut vec = vec!(box 1, box 2, box 3);
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
-        [_a,         //~ ERROR cannot move out
-        //~| cannot move out
-        //~| to prevent move
-         _b..] => {
+        &mut [_a, //~ ERROR cannot move out of borrowed content
+            //~| cannot move out
+            //~| to prevent move
+            ..
+        ] => {
             // Note: `_a` is *moved* here, but `b` is borrowing,
             // hence illegal.
             //
@@ -61,7 +62,7 @@ fn d() {
     let mut vec = vec!(box 1, box 2, box 3);
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
-        [_a..,     //~ ERROR cannot move out
+        &mut [ //~ ERROR cannot move out
         //~^ cannot move out
          _b] => {} //~ NOTE to prevent move
         _ => {}
@@ -75,7 +76,7 @@ fn e() {
     let mut vec = vec!(box 1, box 2, box 3);
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
-        [_a, _b, _c] => {}  //~ ERROR cannot move out
+        &mut [_a, _b, _c] => {}  //~ ERROR cannot move out
         //~| cannot move out
         //~| NOTE to prevent move
         //~| NOTE and here
diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs
index 82b3490d7d7..a849e4e2faf 100644
--- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs
+++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs
@@ -14,7 +14,7 @@ fn a<'a>() -> &'a isize {
     let vec = vec!(1, 2, 3, 4);
     let vec: &[isize] = &vec; //~ ERROR `vec` does not live long enough
     let tail = match vec {
-        [_a, tail..] => &tail[0],
+        &[_a, ref tail..] => &tail[0],
         _ => panic!("foo")
     };
     tail
diff --git a/src/test/compile-fail/cfg-non-opt-expr.rs b/src/test/compile-fail/cfg-non-opt-expr.rs
index b3ef3d72ca3..a4b24fa8b4b 100644
--- a/src/test/compile-fail/cfg-non-opt-expr.rs
+++ b/src/test/compile-fail/cfg-non-opt-expr.rs
@@ -17,4 +17,6 @@ fn main() {
     //~^ ERROR removing an expression is not supported in this position
     let _ = [1, 2, 3][#[cfg(unset)] 1];
     //~^ ERROR removing an expression is not supported in this position
+    let _ = #[test] ();
+    //~^ ERROR removing an expression is not supported in this position
 }
diff --git a/src/test/compile-fail/const-pattern-irrefutable.rs b/src/test/compile-fail/const-pattern-irrefutable.rs
index 392f391fb51..75b6397f4eb 100644
--- a/src/test/compile-fail/const-pattern-irrefutable.rs
+++ b/src/test/compile-fail/const-pattern-irrefutable.rs
@@ -19,10 +19,10 @@ use foo::d; //~ NOTE is imported here
 const a: u8 = 2; //~ NOTE is defined here
 
 fn main() {
-    let a = 4; //~ ERROR let variables cannot
-               //~^ NOTE cannot be named the same as a const variable
-    let c = 4; //~ ERROR let variables cannot
-               //~^ NOTE cannot be named the same as a const variable
-    let d = 4; //~ ERROR let variables cannot
-               //~^ NOTE cannot be named the same as a const variable
+    let a = 4; //~ ERROR let bindings cannot shadow constants
+               //~^ NOTE cannot be named the same as a constant
+    let c = 4; //~ ERROR let bindings cannot shadow constants
+               //~^ NOTE cannot be named the same as a constant
+    let d = 4; //~ ERROR let bindings cannot shadow constants
+               //~^ NOTE cannot be named the same as a constant
 }
diff --git a/src/test/compile-fail/custom_attribute.rs b/src/test/compile-fail/custom_attribute.rs
index 4e089a4e59c..eff734230ee 100644
--- a/src/test/compile-fail/custom_attribute.rs
+++ b/src/test/compile-fail/custom_attribute.rs
@@ -8,7 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(stmt_expr_attributes)]
+
 #[foo] //~ ERROR The attribute `foo`
 fn main() {
-
+    #[foo] //~ ERROR The attribute `foo`
+    let x = ();
+    #[foo] //~ ERROR The attribute `foo`
+    x
 }
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 0bd96d82095..0522a654a85 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-2.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs
@@ -29,9 +29,9 @@ fn main() {
     //     XEmpty1() => () // ERROR unresolved enum variant, struct or const `XEmpty1`
     // }
     match e1 {
-        Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
+        Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1`
     }
     match xe1 {
-        XEmpty1(..) => () //~ ERROR unresolved enum variant, struct or const `XEmpty1`
+        XEmpty1(..) => () //~ ERROR unresolved variant or struct `XEmpty1`
     }
 }
diff --git a/src/test/compile-fail/enum-in-scope.rs b/src/test/compile-fail/enum-in-scope.rs
index 6dffd1999d7..e89b08a8a06 100644
--- a/src/test/compile-fail/enum-in-scope.rs
+++ b/src/test/compile-fail/enum-in-scope.rs
@@ -11,5 +11,5 @@
 struct hello(isize);
 
 fn main() {
-    let hello = 0; //~ERROR cannot be named the same
+    let hello = 0; //~ERROR let bindings cannot shadow structs
 }
diff --git a/src/test/compile-fail/enums-pats-not-idents.rs b/src/test/compile-fail/enums-pats-not-idents.rs
index faf672415bd..c847366a707 100644
--- a/src/test/compile-fail/enums-pats-not-idents.rs
+++ b/src/test/compile-fail/enums-pats-not-idents.rs
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//error-pattern:unresolved enum variant
-
 fn main() {
-    // a bug in the parser is allowing this:
-    let a(1) = 13;
+    let a(1) = 13; //~ ERROR unresolved variant or struct `a`
 }
diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs
index 7c929d2db16..1368702b160 100644
--- a/src/test/compile-fail/ifmt-bad-arg.rs
+++ b/src/test/compile-fail/ifmt-bad-arg.rs
@@ -50,8 +50,4 @@ fn main() {
 
     format!("foo } bar"); //~ ERROR: unmatched `}` found
     format!("foo }"); //~ ERROR: unmatched `}` found
-
-    format!();          //~ ERROR: requires at least a format string argument
-    format!("" 1);      //~ ERROR: expected token: `,`
-    format!("", 1 1);   //~ ERROR: expected token: `,`
 }
diff --git a/src/test/compile-fail/issue-10200.rs b/src/test/compile-fail/issue-10200.rs
index 03d4e9b81eb..9eec8487a50 100644
--- a/src/test/compile-fail/issue-10200.rs
+++ b/src/test/compile-fail/issue-10200.rs
@@ -13,7 +13,7 @@ fn foo(_: usize) -> Foo { Foo(false) }
 
 fn main() {
     match Foo(true) {
-        foo(x) //~ ERROR `foo` is not an enum variant, struct or const
+        foo(x) //~ ERROR expected variant or struct, found function `foo`
         => ()
     }
 }
diff --git a/src/test/compile-fail/issue-12369.rs b/src/test/compile-fail/issue-12369.rs
index 1333bfac64e..978d6f59b2d 100644
--- a/src/test/compile-fail/issue-12369.rs
+++ b/src/test/compile-fail/issue-12369.rs
@@ -13,9 +13,9 @@
 fn main() {
     let sl = vec![1,2,3];
     let v: isize = match &*sl {
-        [] => 0,
-        [a,b,c] => 3,
-        [a, rest..] => a,
-        [10,a, rest..] => 10 //~ ERROR: unreachable pattern
+        &[] => 0,
+        &[a,b,c] => 3,
+        &[a, ref rest..] => a,
+        &[10,a, ref rest..] => 10 //~ ERROR: unreachable pattern
     };
 }
diff --git a/src/test/compile-fail/issue-12567.rs b/src/test/compile-fail/issue-12567.rs
index 1580ec00f94..32a6ea4f062 100644
--- a/src/test/compile-fail/issue-12567.rs
+++ b/src/test/compile-fail/issue-12567.rs
@@ -12,13 +12,15 @@
 
 fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) {
     match (l1, l2) {
-        ([], []) => println!("both empty"),
-        ([], [hd, tl..]) | ([hd, tl..], []) => println!("one empty"),
-        //~^ ERROR: cannot move out of borrowed content
+        (&[], &[]) => println!("both empty"),
+        (&[], &[hd, ..]) | (&[hd, ..], &[])
+            => println!("one empty"),
         //~^^ ERROR: cannot move out of borrowed content
-        ([hd1, tl1..], [hd2, tl2..]) => println!("both nonempty"),
-        //~^ ERROR: cannot move out of borrowed content
+        //~^^^ ERROR: cannot move out of borrowed content
+        (&[hd1, ..], &[hd2, ..])
+            => println!("both nonempty"),
         //~^^ ERROR: cannot move out of borrowed content
+        //~^^^ ERROR: cannot move out of borrowed content
     }
 }
 
diff --git a/src/test/compile-fail/issue-12863.rs b/src/test/compile-fail/issue-12863.rs
index 07676679ef1..7912410f69e 100644
--- a/src/test/compile-fail/issue-12863.rs
+++ b/src/test/compile-fail/issue-12863.rs
@@ -12,6 +12,6 @@ mod foo { pub fn bar() {} }
 
 fn main() {
     match () {
-        foo::bar => {} //~ ERROR `bar` is not an enum variant, struct or const
+        foo::bar => {} //~ ERROR expected variant, struct or constant, found function `bar`
     }
 }
diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs
index fe03373a45d..6885c8d94c6 100644
--- a/src/test/compile-fail/issue-13482-2.rs
+++ b/src/test/compile-fail/issue-13482-2.rs
@@ -15,11 +15,7 @@
 fn main() {
     let x = [1,2];
     let y = match x {
-        [] => None,
-//~^ ERROR mismatched types
-//~| expected type `[_#1i; 2]`
-//~| found type `[_#7t; 0]`
-//~| expected an array with a fixed size of 2 elements, found one with 0 elements
+        [] => None, //~ ERROR pattern requires 0 elements but array has 2
         [a,_] => Some(a)
     };
 }
diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs
index 7ed7f5898b1..82e82df3186 100644
--- a/src/test/compile-fail/issue-13482.rs
+++ b/src/test/compile-fail/issue-13482.rs
@@ -13,11 +13,7 @@
 fn main() {
   let x = [1,2];
   let y = match x {
-    [] => None,
-    //~^ ERROR mismatched types
-    //~| expected type `[_; 2]`
-    //~| found type `[_; 0]`
-    //~| expected an array with a fixed size of 2 elements
+    [] => None, //~ ERROR pattern requires 0 elements but array has 2
     [a,_] => Some(a)
   };
 }
diff --git a/src/test/compile-fail/issue-13727.rs b/src/test/compile-fail/issue-13727.rs
new file mode 100644
index 00000000000..28c2c7bc0e2
--- /dev/null
+++ b/src/test/compile-fail/issue-13727.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.
+
+fn test(val: u8) {
+  match val {
+    256 => print!("0b1110\n"),
+    512 => print!("0b1111\n"),
+    //~^ ERROR: unreachable pattern
+    _   => print!("fail\n"),
+  }
+}
+
+fn main() {
+  test(1);
+}
diff --git a/src/test/compile-fail/issue-15381.rs b/src/test/compile-fail/issue-15381.rs
index ec29a84f44e..d0964d2aabe 100644
--- a/src/test/compile-fail/issue-15381.rs
+++ b/src/test/compile-fail/issue-15381.rs
@@ -13,8 +13,8 @@
 fn main() {
     let values: Vec<u8> = vec![1,2,3,4,5,6,7,8];
 
-    for [x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
-        //~^ ERROR refutable pattern in `for` loop binding: `[]` not covered
+    for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
+        //~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered
         println!("y={}", y);
     }
 }
diff --git a/src/test/compile-fail/issue-16149.rs b/src/test/compile-fail/issue-16149.rs
index 4954c95fcd1..60117bd88d4 100644
--- a/src/test/compile-fail/issue-16149.rs
+++ b/src/test/compile-fail/issue-16149.rs
@@ -15,7 +15,7 @@ extern {
 fn main() {
     let boolValue = match 42 {
         externalValue => true,
-        //~^ ERROR static variables cannot be referenced in a pattern
+        //~^ ERROR match bindings cannot shadow statics
         _ => false
     };
 }
diff --git a/src/test/compile-fail/issue-17405.rs b/src/test/compile-fail/issue-17405.rs
index de8a4f63476..db43c1cce99 100644
--- a/src/test/compile-fail/issue-17405.rs
+++ b/src/test/compile-fail/issue-17405.rs
@@ -14,6 +14,7 @@ enum Foo {
 
 fn main() {
     match Foo::Bar(1) {
-        Foo { i } => () //~ ERROR `Foo` does not name a struct or a struct variant
+        Foo { i } => () //~ ERROR expected variant, struct or type alias, found enum `Foo`
+        //~^ ERROR `Foo` does not name a struct or a struct variant
     }
 }
diff --git a/src/test/compile-fail/issue-17718-const-privacy.rs b/src/test/compile-fail/issue-17718-const-privacy.rs
index 021edbee566..523a387956a 100644
--- a/src/test/compile-fail/issue-17718-const-privacy.rs
+++ b/src/test/compile-fail/issue-17718-const-privacy.rs
@@ -12,10 +12,10 @@
 
 extern crate issue_17718_const_privacy as other;
 
-use a::B; //~ ERROR: const `B` is private
+use a::B; //~ ERROR: constant `B` is private
 use other::{
     FOO,
-    BAR, //~ ERROR: const `BAR` is private
+    BAR, //~ ERROR: constant `BAR` is private
     FOO2,
 };
 
diff --git a/src/test/compile-fail/issue-17718-patterns.rs b/src/test/compile-fail/issue-17718-patterns.rs
index 4e63f667d26..b9f5e98b6fa 100644
--- a/src/test/compile-fail/issue-17718-patterns.rs
+++ b/src/test/compile-fail/issue-17718-patterns.rs
@@ -14,8 +14,8 @@ const A3: usize = 1;
 
 fn main() {
     match 1 {
-        A1 => {} //~ ERROR: static variables cannot be referenced in a pattern
-        A2 => {} //~ ERROR: static variables cannot be referenced in a pattern
+        A1 => {} //~ ERROR: match bindings cannot shadow statics
+        A2 => {} //~ ERROR: match bindings cannot shadow statics
         A3 => {}
         _ => {}
     }
diff --git a/src/test/compile-fail/issue-17933.rs b/src/test/compile-fail/issue-17933.rs
index 657b31fa83c..2313a3fe9c6 100644
--- a/src/test/compile-fail/issue-17933.rs
+++ b/src/test/compile-fail/issue-17933.rs
@@ -13,7 +13,7 @@ pub static X: usize = 1;
 fn main() {
     match 1 {
         self::X => { },
-        //~^ ERROR static variables cannot be referenced in a pattern, use a `const` instead
+        //~^ ERROR expected variant, struct or constant, found static `X`
         _       => { },
     }
 }
diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs
index d89b2c6ce8c..3591b982414 100644
--- a/src/test/compile-fail/issue-18819.rs
+++ b/src/test/compile-fail/issue-18819.rs
@@ -24,4 +24,5 @@ fn print_x(_: &Foo<Item=bool>, extra: &str) {
 
 fn main() {
     print_x(X);  //~error this function takes 2 parameters but 1 parameter was supplied
+    //~^ NOTE the following parameter types were expected: &Foo<Item=bool>, &str
 }
diff --git a/src/test/compile-fail/issue-22434.rs b/src/test/compile-fail/issue-22434.rs
new file mode 100644
index 00000000000..6effd02bac8
--- /dev/null
+++ b/src/test/compile-fail/issue-22434.rs
@@ -0,0 +1,18 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Foo {
+    type A;
+}
+
+type I<'a> = &'a (Foo + 'a);
+//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-23122-1.rs b/src/test/compile-fail/issue-23122-1.rs
new file mode 100644
index 00000000000..36d8450848d
--- /dev/null
+++ b/src/test/compile-fail/issue-23122-1.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.
+
+trait Next {
+    type Next: Next;
+}
+
+struct GetNext<T: Next> { t: T }
+
+impl<T: Next> Next for GetNext<T> {
+    //~^ ERROR overflow evaluating the requirement
+    type Next = <GetNext<T> as Next>::Next;
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-23122-2.rs b/src/test/compile-fail/issue-23122-2.rs
new file mode 100644
index 00000000000..faaf78f894b
--- /dev/null
+++ b/src/test/compile-fail/issue-23122-2.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.
+
+trait Next {
+    type Next: Next;
+}
+
+struct GetNext<T: Next> { t: T }
+
+impl<T: Next> Next for GetNext<T> {
+    //~^ ERROR overflow evaluating the requirement
+    type Next = <GetNext<T::Next> as Next>::Next;
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-23716.rs b/src/test/compile-fail/issue-23716.rs
index b0d36610b7a..5cf80dd172a 100644
--- a/src/test/compile-fail/issue-23716.rs
+++ b/src/test/compile-fail/issue-23716.rs
@@ -9,21 +9,21 @@
 // except according to those terms.
 
 static foo: i32 = 0;
-//~^ NOTE static variable defined here
+//~^ NOTE a static `foo` is defined here
 
 fn bar(foo: i32) {}
-//~^ ERROR static variables cannot be referenced in a pattern, use a `const` instead
-//~| static variable used in pattern
+//~^ ERROR function parameters cannot shadow statics
+//~| cannot be named the same as a static
 
 mod submod {
     pub static answer: i32 = 42;
 }
 
 use self::submod::answer;
-//~^ NOTE static variable imported here
+//~^ NOTE a static `answer` is imported here
 
 fn question(answer: i32) {}
-//~^ ERROR static variables cannot be referenced in a pattern, use a `const` instead
-//~| static variable used in pattern
+//~^ ERROR function parameters cannot shadow statics
+//~| cannot be named the same as a static
 fn main() {
 }
diff --git a/src/test/compile-fail/issue-25579.rs b/src/test/compile-fail/issue-25579.rs
new file mode 100644
index 00000000000..849c9aa18c9
--- /dev/null
+++ b/src/test/compile-fail/issue-25579.rs
@@ -0,0 +1,27 @@
+// 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.
+
+enum Sexpression {
+    Num(()),
+    Cons(&'static mut Sexpression)
+}
+
+fn causes_ice(mut l: &mut Sexpression) {
+    loop { match l {
+        &mut Sexpression::Num(ref mut n) => {},
+        &mut Sexpression::Cons(ref mut expr) => { //~ ERROR cannot borrow `l.0`
+            //~| ERROR cannot borrow `l.0`
+            l = &mut **expr; //~ ERROR cannot assign to `l`
+        }
+    }}
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/issue-26459.rs b/src/test/compile-fail/issue-26459.rs
index 48eda91fbae..6cadbef33e7 100644
--- a/src/test/compile-fail/issue-26459.rs
+++ b/src/test/compile-fail/issue-26459.rs
@@ -11,6 +11,7 @@
 fn main() {
     match 'a' {
         char{ch} => true
-        //~^ ERROR `char` does not name a struct or a struct variant
+        //~^ ERROR expected variant, struct or type alias, found builtin type `char`
+        //~| ERROR `char` does not name a struct or a struct variant
     };
 }
diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs
index 2919b0b3cac..b6d5e5458ff 100644
--- a/src/test/compile-fail/issue-26548.rs
+++ b/src/test/compile-fail/issue-26548.rs
@@ -10,10 +10,13 @@
 
 // error-pattern: overflow representing the type `S`
 
+#![feature(rustc_attrs)]
+
 trait Mirror { type It: ?Sized; }
 impl<T: ?Sized> Mirror for T { type It = Self; }
 struct S(Option<<S as Mirror>::It>);
 
+#[rustc_no_mir] // FIXME #27840 MIR tries to represent `std::option::Option<S>` first.
 fn main() {
     let _s = S(None);
 }
diff --git a/src/test/compile-fail/issue-27033.rs b/src/test/compile-fail/issue-27033.rs
index b0904dfeaa7..2a015adb498 100644
--- a/src/test/compile-fail/issue-27033.rs
+++ b/src/test/compile-fail/issue-27033.rs
@@ -10,11 +10,11 @@
 
 fn main() {
     match Some(1) {
-        None @ _ => {} //~ ERROR cannot be named the same
+        None @ _ => {} //~ ERROR match bindings cannot shadow variants
     };
     const C: u8 = 1;
     match 1 {
-        C @ 2 => { //~ ERROR cannot be named the same
+        C @ 2 => { //~ ERROR match bindings cannot shadow constant
             println!("{}", C);
         }
         _ => {}
diff --git a/src/test/compile-fail/issue-27815.rs b/src/test/compile-fail/issue-27815.rs
index b1ac2dfd1c4..d2f9abd2e31 100644
--- a/src/test/compile-fail/issue-27815.rs
+++ b/src/test/compile-fail/issue-27815.rs
@@ -14,7 +14,9 @@ fn main() {
     let u = A { x: 1 }; //~ ERROR `A` does not name a structure
     let v = u32 { x: 1 }; //~ ERROR `u32` does not name a structure
     match () {
-        A { x: 1 } => {} //~ ERROR `A` does not name a struct
-        u32 { x: 1 } => {} //~ ERROR `u32` does not name a struct
+        A { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found module `A`
+        //~^ ERROR `A` does not name a struct or a struct variant
+        u32 { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found builtin type `u32
+        //~^ ERROR `u32` does not name a struct or a struct variant
     }
 }
diff --git a/src/test/compile-fail/issue-28992-empty.rs b/src/test/compile-fail/issue-28992-empty.rs
index f7d53ba23da..e492d48fdaf 100644
--- a/src/test/compile-fail/issue-28992-empty.rs
+++ b/src/test/compile-fail/issue-28992-empty.rs
@@ -21,6 +21,6 @@ impl S {
 }
 
 fn main() {
-    if let C1(..) = 0 {} //~ ERROR `C1` does not name a tuple variant or a tuple struct
+    if let C1(..) = 0 {} //~ ERROR expected variant or struct, found constant `C1`
     if let S::C2(..) = 0 {} //~ ERROR `S::C2` does not name a tuple variant or a tuple struct
 }
diff --git a/src/test/compile-fail/issue-30240.rs b/src/test/compile-fail/issue-30240.rs
new file mode 100644
index 00000000000..9b105e7ec15
--- /dev/null
+++ b/src/test/compile-fail/issue-30240.rs
@@ -0,0 +1,21 @@
+// 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() {
+    match "world" { //~ ERROR non-exhaustive patterns: `&_`
+        "hello" => {}
+    }
+
+    match "world" { //~ ERROR non-exhaustive patterns: `&_`
+        ref _x if false => {}
+        "hello" => {}
+        "hello" => {} //~ ERROR unreachable pattern
+    }
+}
diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs
index 0f7cc2cb72b..68046056fb3 100644
--- a/src/test/compile-fail/issue-3044.rs
+++ b/src/test/compile-fail/issue-3044.rs
@@ -14,6 +14,7 @@ fn main() {
     needlesArr.iter().fold(|x, y| {
     });
     //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied
+    //~^^^ NOTE the following parameter types were expected
     //
     // the first error is, um, non-ideal.
 }
diff --git a/src/test/compile-fail/issue-30715.rs b/src/test/compile-fail/issue-30715.rs
deleted file mode 100644
index 5cacf8f53c6..00000000000
--- a/src/test/compile-fail/issue-30715.rs
+++ /dev/null
@@ -1,33 +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.
-
-// compile-flags: -Z continue-parse-after-error
-
-macro_rules! parallel {
-    (
-        // If future has `pred`/`moelarry` fragments (where "pred" is
-        // "like expr, but with `{` in its FOLLOW set"), then could
-        // use `pred` instead of future-proof erroring here. See also:
-        //
-        // https://github.com/rust-lang/rfcs/pull/1384#issuecomment-160165525
-        for $id:ident in $iter:expr { //~ WARN `$iter:expr` is followed by `{`
-            $( $inner:expr; )*
-        }
-    ) => {};
-}
-
-
-fn main() {
-    parallel! {
-        for i in 0..n {
-            x += i; //~ ERROR expected `:`, found `+=`
-        } //~ ERROR unexpected end of macro invocation
-    }
-}
diff --git a/src/test/compile-fail/issue-32086.rs b/src/test/compile-fail/issue-32086.rs
new file mode 100644
index 00000000000..926f58198df
--- /dev/null
+++ b/src/test/compile-fail/issue-32086.rs
@@ -0,0 +1,17 @@
+// 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);
+const C: S = S(10);
+
+fn main() {
+    let C(a) = S(11); //~ ERROR expected variant or struct, found constant `C`
+    let C(..) = S(11); //~ ERROR expected variant or struct, found constant `C`
+}
diff --git a/src/test/compile-fail/issue-32950.rs b/src/test/compile-fail/issue-32950.rs
new file mode 100644
index 00000000000..e47ebdd6a69
--- /dev/null
+++ b/src/test/compile-fail/issue-32950.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.
+
+#![feature(type_macros, concat_idents, rustc_attrs)]
+#![allow(unused)]
+
+#[derive(Debug)] struct FooBar;
+#[derive(Debug)] struct Baz<T>(T, concat_idents!(Foo, Bar));
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/issue-33293.rs b/src/test/compile-fail/issue-33293.rs
new file mode 100644
index 00000000000..bed577b8b9d
--- /dev/null
+++ b/src/test/compile-fail/issue-33293.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.
+
+fn main() {
+    match 0 {
+        aaa::bbb(_) => ()
+        //~^ ERROR failed to resolve. Use of undeclared type or module `aaa`
+    };
+}
diff --git a/src/test/compile-fail/issue-34047.rs b/src/test/compile-fail/issue-34047.rs
new file mode 100644
index 00000000000..630694d9156
--- /dev/null
+++ b/src/test/compile-fail/issue-34047.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.
+
+const C: u8 = 0; //~ NOTE a constant `C` is defined here
+
+fn main() {
+    match 1u8 {
+        mut C => {} //~ ERROR match bindings cannot shadow constants
+        //~^ NOTE cannot be named the same as a constant
+        _ => {}
+    }
+}
diff --git a/src/test/compile-fail/issue-34171.rs b/src/test/compile-fail/issue-34171.rs
new file mode 100644
index 00000000000..30dd34ae9a0
--- /dev/null
+++ b/src/test/compile-fail/issue-34171.rs
@@ -0,0 +1,21 @@
+// 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)]
+
+macro_rules! null { ($i:tt) => {} }
+macro_rules! apply_null {
+    ($i:item) => { null! { $i } }
+}
+
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
+    apply_null!(#[cfg(all())] fn f() {});
+}
diff --git a/src/test/compile-fail/issue-34194.rs b/src/test/compile-fail/issue-34194.rs
new file mode 100644
index 00000000000..dd607ebad62
--- /dev/null
+++ b/src/test/compile-fail/issue-34194.rs
@@ -0,0 +1,21 @@
+// 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)]
+
+struct A {
+    a: &'static (),
+}
+
+static B: &'static A = &A { a: &() };
+static C: &'static A = &B;
+//~^ ERROR cannot refer to other statics by value
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-34334.rs b/src/test/compile-fail/issue-34334.rs
new file mode 100644
index 00000000000..ffcd052369d
--- /dev/null
+++ b/src/test/compile-fail/issue-34334.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.
+
+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`
+}
diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs
index b37b8e237ed..438d238b6fe 100644
--- a/src/test/compile-fail/issue-4935.rs
+++ b/src/test/compile-fail/issue-4935.rs
@@ -12,3 +12,4 @@
 
 fn foo(a: usize) {}
 fn main() { foo(5, 6) } //~ ERROR this function takes 1 parameter but 2 parameters were supplied
+//~^ NOTE the following parameter type was expected
diff --git a/src/test/compile-fail/issue-5927.rs b/src/test/compile-fail/issue-5927.rs
index e5f091d873d..3a8ff12429a 100644
--- a/src/test/compile-fail/issue-5927.rs
+++ b/src/test/compile-fail/issue-5927.rs
@@ -11,7 +11,7 @@
 
 fn main() {
     let z = match 3 {
-        x(1) => x(1) //~ ERROR unresolved enum variant
+        x(1) => x(1) //~ ERROR unresolved variant or struct `x`
         //~^ ERROR unresolved name `x`
     };
     assert!(z == 3);
diff --git a/src/test/compile-fail/macro-backtrace-println.rs b/src/test/compile-fail/macro-backtrace-println.rs
index c2277c3e6d8..9d6da2a53a2 100644
--- a/src/test/compile-fail/macro-backtrace-println.rs
+++ b/src/test/compile-fail/macro-backtrace-println.rs
@@ -21,11 +21,11 @@ macro_rules! myprint {
 }
 
 macro_rules! myprintln {
-    ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ NOTE in this expansion of myprint!
-                                                    //~^ NOTE in this expansion of concat!
+    ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
+                                                    //~| NOTE in this expansion of concat!
+                                                    //~| NOTE in this expansion of myprint!
 }
 
 fn main() {
-    myprintln!("{}"); //~ ERROR invalid reference to argument `0`
-                      //~^ NOTE in this expansion of
+    myprintln!("{}"); //~ NOTE in this expansion of
 }
diff --git a/src/test/compile-fail/macro-follow.rs b/src/test/compile-fail/macro-follow.rs
index f985340c524..001bc42274b 100644
--- a/src/test/compile-fail/macro-follow.rs
+++ b/src/test/compile-fail/macro-follow.rs
@@ -12,9 +12,9 @@
 
 // FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
 macro_rules! follow_pat {
-    ($p:pat ()) => {};       //~WARN  `$p:pat` is followed by `(`
-    ($p:pat []) => {};       //~WARN  `$p:pat` is followed by `[`
-    ($p:pat {}) => {};       //~WARN  `$p:pat` is followed by `{`
+    ($p:pat ()) => {};       //~ERROR  `$p:pat` is followed by `(`
+    ($p:pat []) => {};       //~ERROR  `$p:pat` is followed by `[`
+    ($p:pat {}) => {};       //~ERROR  `$p:pat` is followed by `{`
     ($p:pat :) => {};        //~ERROR `$p:pat` is followed by `:`
     ($p:pat >) => {};        //~ERROR `$p:pat` is followed by `>`
     ($p:pat +) => {};        //~ERROR `$p:pat` is followed by `+`
@@ -32,9 +32,9 @@ macro_rules! follow_pat {
 }
 // FOLLOW(expr) = {FatArrow, Comma, Semicolon}
 macro_rules! follow_expr {
-    ($e:expr ()) => {};       //~WARN  `$e:expr` is followed by `(`
-    ($e:expr []) => {};       //~WARN  `$e:expr` is followed by `[`
-    ($e:expr {}) => {};       //~WARN  `$e:expr` is followed by `{`
+    ($e:expr ()) => {};       //~ERROR  `$e:expr` is followed by `(`
+    ($e:expr []) => {};       //~ERROR  `$e:expr` is followed by `[`
+    ($e:expr {}) => {};       //~ERROR  `$e:expr` is followed by `{`
     ($e:expr =) => {};        //~ERROR `$e:expr` is followed by `=`
     ($e:expr |) => {};        //~ERROR `$e:expr` is followed by `|`
     ($e:expr :) => {};        //~ERROR `$e:expr` is followed by `:`
@@ -57,7 +57,7 @@ macro_rules! follow_expr {
 // FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
 //               Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)}
 macro_rules! follow_ty {
-    ($t:ty ()) => {};       //~WARN  `$t:ty` is followed by `(`
+    ($t:ty ()) => {};       //~ERROR  `$t:ty` is followed by `(`
     ($t:ty []) => {};       // ok (RFC 1462)
     ($t:ty +) => {};        //~ERROR `$t:ty` is followed by `+`
     ($t:ty ident) => {};    //~ERROR `$t:ty` is followed by `ident`
@@ -75,9 +75,9 @@ macro_rules! follow_ty {
 }
 // FOLLOW(stmt) = FOLLOW(expr)
 macro_rules! follow_stmt {
-    ($s:stmt ()) => {};       //~WARN  `$s:stmt` is followed by `(`
-    ($s:stmt []) => {};       //~WARN  `$s:stmt` is followed by `[`
-    ($s:stmt {}) => {};       //~WARN  `$s:stmt` is followed by `{`
+    ($s:stmt ()) => {};       //~ERROR  `$s:stmt` is followed by `(`
+    ($s:stmt []) => {};       //~ERROR  `$s:stmt` is followed by `[`
+    ($s:stmt {}) => {};       //~ERROR  `$s:stmt` is followed by `{`
     ($s:stmt =) => {};        //~ERROR `$s:stmt` is followed by `=`
     ($s:stmt |) => {};        //~ERROR `$s:stmt` is followed by `|`
     ($s:stmt :) => {};        //~ERROR `$s:stmt` is followed by `:`
@@ -99,7 +99,7 @@ macro_rules! follow_stmt {
 }
 // FOLLOW(path) = FOLLOW(ty)
 macro_rules! follow_path {
-    ($p:path ()) => {};       //~WARN  `$p:path` is followed by `(`
+    ($p:path ()) => {};       //~ERROR  `$p:path` is followed by `(`
     ($p:path []) => {};       // ok (RFC 1462)
     ($p:path +) => {};        //~ERROR `$p:path` is followed by `+`
     ($p:path ident) => {};    //~ERROR `$p:path` is followed by `ident`
diff --git a/src/test/compile-fail/macro-use-scope.rs b/src/test/compile-fail/macro-use-scope.rs
new file mode 100644
index 00000000000..5256396a242
--- /dev/null
+++ b/src/test/compile-fail/macro-use-scope.rs
@@ -0,0 +1,32 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:two_macros.rs
+
+#![feature(rustc_attrs)]
+#![allow(unused)]
+
+fn f() {
+    let _ = macro_one!();
+}
+#[macro_use(macro_one)] // Check that this macro is usable in the above function
+extern crate two_macros;
+
+macro_rules! m { () => {
+    fn g() {
+        macro_two!();
+    }
+    #[macro_use(macro_two)] // Check that this macro is usable in the above function
+    extern crate two_macros as _two_macros;
+} }
+m!();
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/macros-nonfatal-errors.rs b/src/test/compile-fail/macros-nonfatal-errors.rs
index 42a0f41dd97..723e936212a 100644
--- a/src/test/compile-fail/macros-nonfatal-errors.rs
+++ b/src/test/compile-fail/macros-nonfatal-errors.rs
@@ -32,7 +32,6 @@ fn main() {
 
     foo::blah!(); //~ ERROR
 
-    format!(); //~ ERROR
     format!(invalid); //~ ERROR
 
     include!(invalid); //~ ERROR
diff --git a/src/test/compile-fail/match-vec-mismatch-2.rs b/src/test/compile-fail/match-vec-mismatch-2.rs
index 2831499c73d..375d855d1fd 100644
--- a/src/test/compile-fail/match-vec-mismatch-2.rs
+++ b/src/test/compile-fail/match-vec-mismatch-2.rs
@@ -13,9 +13,6 @@
 fn main() {
     match () {
         [()] => { }
-        //~^ ERROR mismatched types
-        //~| expected type `()`
-        //~| found type `&[_]`
-        //~| expected (), found &-ptr
+        //~^ ERROR expected an array or slice, found `()`
     }
 }
diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs
index ef75213d34b..3ac4958e7db 100644
--- a/src/test/compile-fail/match-vec-mismatch.rs
+++ b/src/test/compile-fail/match-vec-mismatch.rs
@@ -12,7 +12,36 @@
 
 fn main() {
     match "foo".to_string() {
-        ['f', 'o', ..] => {} //~ ERROR mismatched types
+        ['f', 'o', ..] => {}
+        //~^ ERROR expected an array or slice, found `std::string::String`
         _ => { }
-    }
+    };
+
+    match &[0, 1, 2] {
+        [..] => {} //~ ERROR expected an array or slice, found `&[_; 3]`
+    };
+
+    match &[0, 1, 2] {
+        &[..] => {} // ok
+    };
+
+    match [0, 1, 2] {
+        [0] => {}, //~ ERROR pattern requires
+
+        [0, 1, x..] => {
+            let a: [_; 1] = x;
+        }
+        [0, 1, 2, 3, x..] => {} //~ ERROR pattern requires
+    };
+
+    match does_not_exist { //~ ERROR unresolved name
+        [] => {}
+    };
+}
+
+fn another_fn_to_avoid_suppression() {
+    match Default::default()
+    {
+        [] => {}  //~ ERROR the type of this value
+    };
 }
diff --git a/src/test/compile-fail/match-vec-unreachable.rs b/src/test/compile-fail/match-vec-unreachable.rs
index 48b70b4bda0..57e3a58b566 100644
--- a/src/test/compile-fail/match-vec-unreachable.rs
+++ b/src/test/compile-fail/match-vec-unreachable.rs
@@ -13,7 +13,7 @@
 fn main() {
     let x: Vec<(isize, isize)> = Vec::new();
     let x: &[(isize, isize)] = &x;
-    match x {
+    match *x {
         [a, (2, 3), _] => (),
         [(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern
         _ => ()
@@ -23,7 +23,7 @@ fn main() {
                               "bar".to_string(),
                               "baz".to_string()];
     let x: &[String] = &x;
-    match x {
+    match *x {
         [a, _, _, ..] => { println!("{}", a); }
         [_, _, _, _, _] => { } //~ ERROR unreachable pattern
         _ => { }
@@ -31,8 +31,8 @@ fn main() {
 
     let x: Vec<char> = vec!('a', 'b', 'c');
     let x: &[char] = &x;
-    match x {
-        ['a', 'b', 'c', _tail..] => {}
+    match *x {
+        ['a', 'b', 'c', ref _tail..] => {}
         ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
         _ => {}
     }
diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs
index 3434cf96fce..212c09364cf 100644
--- a/src/test/compile-fail/method-call-err-msg.rs
+++ b/src/test/compile-fail/method-call-err-msg.rs
@@ -21,10 +21,13 @@ fn main() {
     let x = Foo;
     x.zero(0)   //~ ERROR this function takes 0 parameters but 1 parameter was supplied
      .one()     //~ ERROR this function takes 1 parameter but 0 parameters were supplied
+     //~^ NOTE the following parameter type was expected
      .two(0);   //~ ERROR this function takes 2 parameters but 1 parameter was supplied
+     //~^ NOTE the following parameter types were expected
 
     let y = Foo;
     y.zero()
      .take()    //~ ERROR no method named `take` found for type `Foo` in the current scope
+     //~^ NOTE the method `take` exists but the following trait bounds were not satisfied
      .one(0);
 }
diff --git a/src/test/compile-fail/method-resolvable-path-in-pattern.rs b/src/test/compile-fail/method-resolvable-path-in-pattern.rs
index 0df824e7f53..1cba64ccf2c 100644
--- a/src/test/compile-fail/method-resolvable-path-in-pattern.rs
+++ b/src/test/compile-fail/method-resolvable-path-in-pattern.rs
@@ -19,6 +19,6 @@ impl MyTrait for Foo {}
 fn main() {
     match 0u32 {
         <Foo as MyTrait>::trait_bar => {}
-        //~^ ERROR `trait_bar` is not an associated const
+        //~^ ERROR expected associated constant, found method `trait_bar`
     }
 }
diff --git a/src/test/compile-fail/name-clash-nullary.rs b/src/test/compile-fail/name-clash-nullary.rs
index 662bb7bfe57..2e2d53c4d40 100644
--- a/src/test/compile-fail/name-clash-nullary.rs
+++ b/src/test/compile-fail/name-clash-nullary.rs
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:cannot be named the same
 use std::option::*;
 
 fn main() {
-  let None: isize = 42;
+  let None: isize = 42; //~ ERROR let bindings cannot shadow variants
   log(debug, None);
+  //~^ ERROR unresolved name `debug`
+  //~| ERROR unresolved name `log`
 }
diff --git a/src/test/compile-fail/nested-cfg-attrs.rs b/src/test/compile-fail/nested-cfg-attrs.rs
new file mode 100644
index 00000000000..6010b1e695e
--- /dev/null
+++ b/src/test/compile-fail/nested-cfg-attrs.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.
+
+#[cfg_attr(all(), cfg_attr(all(), cfg(foo)))]
+fn f() {}
+
+fn main() { f() } //~ ERROR unresolved name `f`
diff --git a/src/test/compile-fail/no-warn-on-field-replace-issue-34101.rs b/src/test/compile-fail/no-warn-on-field-replace-issue-34101.rs
new file mode 100644
index 00000000000..2940b891534
--- /dev/null
+++ b/src/test/compile-fail/no-warn-on-field-replace-issue-34101.rs
@@ -0,0 +1,56 @@
+// 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.
+
+// Issue 34101: Circa 2016-06-05, `fn inline` below issued an
+// erroneous warning from the elaborate_drops pass about moving out of
+// a field in `Foo`, which has a destructor (and thus cannot have
+// content moved out of it). The reason that the warning is erroneous
+// in this case is that we are doing a *replace*, not a move, of the
+// content in question, and it is okay to replace fields within `Foo`.
+//
+// Another more subtle problem was that the elaborate_drops was
+// creating a separate drop flag for that internally replaced content,
+// even though the compiler should enforce an invariant that any drop
+// flag for such subcontent of `Foo` will always have the same value
+// as the drop flag for `Foo` itself.
+//
+// This test is structured in a funny way; we cannot test for emission
+// of the warning in question via the lint system, and therefore
+// `#![deny(warnings)]` does nothing to detect it.
+//
+// So instead we use `#[rustc_error]` and put the test into
+// `compile_fail`, where the emitted warning *will* be caught.
+
+#![feature(rustc_attrs)]
+
+struct Foo(String);
+
+impl Drop for Foo {
+    fn drop(&mut self) {}
+}
+
+fn inline() {
+    // (dummy variable so `f` gets assigned `var1` in MIR for both fn's)
+    let _s = ();
+    let mut f = Foo(String::from("foo"));
+    f.0 = String::from("bar");
+}
+
+fn outline() {
+    let _s = String::from("foo");
+    let mut f = Foo(_s);
+    f.0 = String::from("bar");
+}
+
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
+    inline();
+    outline();
+}
diff --git a/src/test/compile-fail/non-exhaustive-match-nested.rs b/src/test/compile-fail/non-exhaustive-match-nested.rs
index ad2b8c400e5..1d524217a12 100644
--- a/src/test/compile-fail/non-exhaustive-match-nested.rs
+++ b/src/test/compile-fail/non-exhaustive-match-nested.rs
@@ -14,11 +14,11 @@ enum t { a(u), b }
 enum u { c, d }
 
 fn match_nested_vecs<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
-    match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some([]), Err(_))` not covered
-        (Some([]), Ok([])) => "Some(empty), Ok(empty)",
-        (Some([_, ..]), Ok(_)) | (Some([_, ..]), Err(())) => "Some(non-empty), any",
-        (None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)",
-        (None, Ok([_, _, ..])) => "None, Ok(at least two elements)"
+    match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some(&[]), Err(_))` not covered
+        (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
+        (Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any",
+        (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)",
+        (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)"
     }
 }
 
diff --git a/src/test/compile-fail/non-exhaustive-match.rs b/src/test/compile-fail/non-exhaustive-match.rs
index b9749c2696e..017baacc9d3 100644
--- a/src/test/compile-fail/non-exhaustive-match.rs
+++ b/src/test/compile-fail/non-exhaustive-match.rs
@@ -39,20 +39,20 @@ fn main() {
     }
     let vec = vec!(Some(42), None, Some(21));
     let vec: &[Option<isize>] = &vec;
-    match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
-        [Some(..), None, tail..] => {}
-        [Some(..), Some(..), tail..] => {}
+    match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered
+        [Some(..), None, ref tail..] => {}
+        [Some(..), Some(..), ref tail..] => {}
         [None] => {}
     }
     let vec = vec!(1);
     let vec: &[isize] = &vec;
-    match vec {
-        [_, tail..] => (),
+    match *vec {
+        [_, ref tail..] => (),
         [] => ()
     }
     let vec = vec!(0.5f32);
     let vec: &[f32] = &vec;
-    match vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
+    match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
         [0.1, 0.2, 0.3] => (),
         [0.1, 0.2] => (),
         [0.1] => (),
@@ -60,11 +60,11 @@ fn main() {
     }
     let vec = vec!(Some(42), None, Some(21));
     let vec: &[Option<isize>] = &vec;
-    match vec {
-        [Some(..), None, tail..] => {}
-        [Some(..), Some(..), tail..] => {}
-        [None, None, tail..] => {}
-        [None, Some(..), tail..] => {}
+    match *vec {
+        [Some(..), None, ref tail..] => {}
+        [Some(..), Some(..), ref tail..] => {}
+        [None, None, ref tail..] => {}
+        [None, Some(..), ref tail..] => {}
         [Some(_)] => {}
         [None] => {}
         [] => {}
diff --git a/src/test/compile-fail/non-exhaustive-pattern-witness.rs b/src/test/compile-fail/non-exhaustive-pattern-witness.rs
index b986878f783..0b12a9acbcb 100644
--- a/src/test/compile-fail/non-exhaustive-pattern-witness.rs
+++ b/src/test/compile-fail/non-exhaustive-pattern-witness.rs
@@ -80,7 +80,7 @@ enum Enum {
 
 fn vectors_with_nested_enums() {
     let x: &'static [Enum] = &[Enum::First, Enum::Second(false)];
-    match x {
+    match *x {
     //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered
         [] => (),
         [_] => (),
@@ -88,7 +88,7 @@ fn vectors_with_nested_enums() {
         [Enum::Second(true), Enum::First] => (),
         [Enum::Second(true), Enum::Second(true)] => (),
         [Enum::Second(false), _] => (),
-        [_, _, tail.., _] => ()
+        [_, _, ref tail.., _] => ()
     }
 }
 
diff --git a/src/test/compile-fail/non-interger-atomic.rs b/src/test/compile-fail/non-interger-atomic.rs
index 0b7b33de421..50240b47557 100644
--- a/src/test/compile-fail/non-interger-atomic.rs
+++ b/src/test/compile-fail/non-interger-atomic.rs
@@ -60,22 +60,22 @@ unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) {
 
 unsafe fn test_Bar_load(p: &mut Bar, v: Bar) {
     intrinsics::atomic_load(p);
-    //~^ ERROR expected basic integer type, found `&'static std::ops::Fn() + 'static`
+    //~^ ERROR expected basic integer type, found `&std::ops::Fn()`
 }
 
 unsafe fn test_Bar_store(p: &mut Bar, v: Bar) {
     intrinsics::atomic_store(p, v);
-    //~^ ERROR expected basic integer type, found `&'static std::ops::Fn() + 'static`
+    //~^ ERROR expected basic integer type, found `&std::ops::Fn()`
 }
 
 unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) {
     intrinsics::atomic_xchg(p, v);
-    //~^ ERROR expected basic integer type, found `&'static std::ops::Fn() + 'static`
+    //~^ ERROR expected basic integer type, found `&std::ops::Fn()`
 }
 
 unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) {
     intrinsics::atomic_cxchg(p, v, v);
-    //~^ ERROR expected basic integer type, found `&'static std::ops::Fn() + 'static`
+    //~^ ERROR expected basic integer type, found `&std::ops::Fn()`
 }
 
 unsafe fn test_Quux_load(p: &mut Quux, v: Quux) {
diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs
index c952906e5e8..1f5a54477dd 100644
--- a/src/test/compile-fail/not-enough-arguments.rs
+++ b/src/test/compile-fail/not-enough-arguments.rs
@@ -19,4 +19,5 @@ fn foo(a: isize, b: isize, c: isize, d:isize) {
 fn main() {
   foo(1, 2, 3);
   //~^ ERROR this function takes 4 parameters but 3
+  //~^^ NOTE the following parameter types were expected
 }
diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs
index 77ac97bc8b8..8763fb0913a 100644
--- a/src/test/compile-fail/overloaded-calls-bad.rs
+++ b/src/test/compile-fail/overloaded-calls-bad.rs
@@ -36,7 +36,13 @@ fn main() {
         y: 3,
     };
     let ans = s("what");    //~ ERROR mismatched types
-    let ans = s();  //~ ERROR this function takes 1 parameter but 0 parameters were supplied
+    //~^ NOTE expected isize, found &-ptr
+    //~| NOTE expected type
+    //~| NOTE found type
+    let ans = s();
+    //~^ ERROR this function takes 1 parameter but 0 parameters were supplied
+    //~| NOTE the following parameter type was expected
     let ans = s("burma", "shave");
     //~^ ERROR this function takes 1 parameter but 2 parameters were supplied
+    //~| NOTE the following parameter type was expected
 }
diff --git a/src/test/compile-fail/pat-shadow-in-nested-binding.rs b/src/test/compile-fail/pat-shadow-in-nested-binding.rs
index 4a8513e10d7..f1683e51c64 100644
--- a/src/test/compile-fail/pat-shadow-in-nested-binding.rs
+++ b/src/test/compile-fail/pat-shadow-in-nested-binding.rs
@@ -11,5 +11,5 @@
 struct foo(usize);
 
 fn main() {
-    let (foo, _) = (2, 3); //~ ERROR `foo` cannot be named the same as
+    let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow structs
 }
diff --git a/src/test/compile-fail/pat-slice-old-style.rs b/src/test/compile-fail/pat-slice-old-style.rs
new file mode 100644
index 00000000000..ccb25d859ac
--- /dev/null
+++ b/src/test/compile-fail/pat-slice-old-style.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.
+
+#![feature(slice_patterns)]
+
+fn slice_pat(x: &[u8]) {
+    // OLD!
+    match x {
+        [a, b..] => {}
+        //~^ ERROR expected an array or slice, found `&[u8]`
+        //~| HELP the semantics of slice patterns changed recently; see issue #23121
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/qualified-path-params.rs b/src/test/compile-fail/qualified-path-params.rs
index 002080f4cb4..86873022f0f 100644
--- a/src/test/compile-fail/qualified-path-params.rs
+++ b/src/test/compile-fail/qualified-path-params.rs
@@ -27,7 +27,7 @@ impl S {
 
 fn main() {
     match 10 {
-        <S as Tr>::A::f::<u8> => {} //~ ERROR `f` is not an associated const
+        <S as Tr>::A::f::<u8> => {} //~ ERROR associated items in match patterns must be constants
         0 ... <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
     }
 }
diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs
new file mode 100644
index 00000000000..85219717758
--- /dev/null
+++ b/src/test/compile-fail/range_traits-1.rs
@@ -0,0 +1,93 @@
+// 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(inclusive_range)]
+
+use std::ops::*;
+
+// FIXME #34229 duplicated errors
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+struct AllTheRanges {
+    a: Range<usize>,
+    //~^ ERROR PartialOrd
+    //~^^ ERROR PartialOrd
+    //~^^^ ERROR Ord
+    //~^^^^ ERROR binary operation
+    //~^^^^^ ERROR binary operation
+    //~^^^^^^ ERROR binary operation
+    //~^^^^^^^ ERROR binary operation
+    //~^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^^ ERROR binary operation
+    b: RangeTo<usize>,
+    //~^ ERROR PartialOrd
+    //~^^ ERROR PartialOrd
+    //~^^^ ERROR Ord
+    //~^^^^ ERROR binary operation
+    //~^^^^^ ERROR binary operation
+    //~^^^^^^ ERROR binary operation
+    //~^^^^^^^ ERROR binary operation
+    //~^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^^ ERROR binary operation
+    c: RangeFrom<usize>,
+    //~^ ERROR PartialOrd
+    //~^^ ERROR PartialOrd
+    //~^^^ ERROR Ord
+    //~^^^^ ERROR binary operation
+    //~^^^^^ ERROR binary operation
+    //~^^^^^^ ERROR binary operation
+    //~^^^^^^^ ERROR binary operation
+    //~^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^^ ERROR binary operation
+    d: RangeFull,
+    //~^ ERROR PartialOrd
+    //~^^ ERROR PartialOrd
+    //~^^^ ERROR Ord
+    //~^^^^ ERROR binary operation
+    //~^^^^^ ERROR binary operation
+    //~^^^^^^ ERROR binary operation
+    //~^^^^^^^ ERROR binary operation
+    //~^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^^ ERROR binary operation
+    e: RangeInclusive<usize>,
+    //~^ ERROR PartialOrd
+    //~^^ ERROR PartialOrd
+    //~^^^ ERROR Ord
+    //~^^^^ ERROR binary operation
+    //~^^^^^ ERROR binary operation
+    //~^^^^^^ ERROR binary operation
+    //~^^^^^^^ ERROR binary operation
+    //~^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^^ ERROR binary operation
+    f: RangeToInclusive<usize>,
+    //~^ ERROR PartialOrd
+    //~^^ ERROR PartialOrd
+    //~^^^ ERROR Ord
+    //~^^^^ ERROR binary operation
+    //~^^^^^ ERROR binary operation
+    //~^^^^^^ ERROR binary operation
+    //~^^^^^^^ ERROR binary operation
+    //~^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^ ERROR binary operation
+    //~^^^^^^^^^^^ ERROR binary operation
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/range_traits-2.rs b/src/test/compile-fail/range_traits-2.rs
new file mode 100644
index 00000000000..64fcd25f538
--- /dev/null
+++ b/src/test/compile-fail/range_traits-2.rs
@@ -0,0 +1,17 @@
+// 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::ops::*;
+
+#[derive(Copy, Clone)] //~ ERROR Copy
+struct R(Range<usize>);
+
+fn main() {}
+
diff --git a/src/test/compile-fail/range_traits-3.rs b/src/test/compile-fail/range_traits-3.rs
new file mode 100644
index 00000000000..d26b7956ae8
--- /dev/null
+++ b/src/test/compile-fail/range_traits-3.rs
@@ -0,0 +1,17 @@
+// 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::ops::*;
+
+#[derive(Copy, Clone)] //~ ERROR Copy
+struct R(RangeFrom<usize>);
+
+fn main() {}
+
diff --git a/src/test/compile-fail/range_traits-4.rs b/src/test/compile-fail/range_traits-4.rs
new file mode 100644
index 00000000000..630969bdbdf
--- /dev/null
+++ b/src/test/compile-fail/range_traits-4.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.
+
+#![feature(rustc_attrs)]
+
+use std::ops::*;
+
+#[derive(Copy, Clone)]
+struct R(RangeTo<usize>);
+
+#[rustc_error]
+fn main() {} //~ ERROR success
+
diff --git a/src/test/compile-fail/range_traits-5.rs b/src/test/compile-fail/range_traits-5.rs
new file mode 100644
index 00000000000..5963c4a9496
--- /dev/null
+++ b/src/test/compile-fail/range_traits-5.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.
+
+#![feature(rustc_attrs)]
+
+use std::ops::*;
+
+#[derive(Copy, Clone)]
+struct R(RangeFull);
+
+#[rustc_error]
+fn main() {} //~ ERROR success
+
diff --git a/src/test/compile-fail/range_traits-6.rs b/src/test/compile-fail/range_traits-6.rs
new file mode 100644
index 00000000000..7c62711feae
--- /dev/null
+++ b/src/test/compile-fail/range_traits-6.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.
+
+#![feature(inclusive_range)]
+
+use std::ops::*;
+
+#[derive(Copy, Clone)] //~ ERROR Copy
+struct R(RangeInclusive<usize>);
+
+fn main() {}
+
diff --git a/src/test/compile-fail/range_traits-7.rs b/src/test/compile-fail/range_traits-7.rs
new file mode 100644
index 00000000000..b6fec773a77
--- /dev/null
+++ b/src/test/compile-fail/range_traits-7.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.
+
+#![feature(rustc_attrs, inclusive_range)]
+
+use std::ops::*;
+
+#[derive(Copy, Clone)]
+struct R(RangeToInclusive<usize>);
+
+#[rustc_error]
+fn main() {} //~ ERROR success
+
diff --git a/src/test/compile-fail/static-mut-not-pat.rs b/src/test/compile-fail/static-mut-not-pat.rs
index 76fecea0c3a..351a47fdf39 100644
--- a/src/test/compile-fail/static-mut-not-pat.rs
+++ b/src/test/compile-fail/static-mut-not-pat.rs
@@ -20,7 +20,7 @@ fn main() {
     // instead of spitting out a custom error about some identifier collisions
     // (we should allow shadowing)
     match 4 {
-        a => {} //~ ERROR static variables cannot be referenced in a pattern
+        a => {} //~ ERROR match bindings cannot shadow statics
         _ => {}
     }
 }
@@ -44,7 +44,7 @@ fn mutable_statics() {
     match (Foo { bar: Some(Direction::North), baz: NewBool(true) }) {
         Foo { bar: None, baz: NewBool(true) } => (),
         STATIC_MUT_FOO => (),
-        //~^ ERROR static variables cannot be referenced in a pattern
+        //~^ ERROR match bindings cannot shadow statics
         Foo { bar: Some(Direction::South), .. } => (),
         Foo { bar: Some(EAST), .. } => (),
         Foo { bar: Some(Direction::North), baz: NewBool(true) } => (),
diff --git a/src/test/compile-fail/trace_macros-gate.rs b/src/test/compile-fail/trace_macros-gate.rs
index d627de24d67..e9b7ddf6d1c 100644
--- a/src/test/compile-fail/trace_macros-gate.rs
+++ b/src/test/compile-fail/trace_macros-gate.rs
@@ -23,8 +23,9 @@ fn main() {
     // of the below being caught.
 
     macro_rules! expando {
-        ($x: ident) => { trace_macros!($x) }
+        ($x: ident) => { trace_macros!($x) } //~ ERROR `trace_macros` is not stable
     }
 
-    expando!(true); //~ ERROR `trace_macros` is not stable
+    expando!(true); //~ NOTE in this expansion
+                    //~^ NOTE in this expansion
 }
diff --git a/src/test/compile-fail/trait-impl-for-module.rs b/src/test/compile-fail/trait-impl-for-module.rs
index c04e197b6bd..1fe8f6294da 100644
--- a/src/test/compile-fail/trait-impl-for-module.rs
+++ b/src/test/compile-fail/trait-impl-for-module.rs
@@ -14,7 +14,7 @@ mod a {
 trait A {
 }
 
-impl A for a { //~ ERROR type name `a` is undefined or not in scope
+impl A for a { //~ ERROR expected type, found module
 }
 
 fn main() {
diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs
index b43159b0d96..d8620ead836 100644
--- a/src/test/compile-fail/variadic-ffi-3.rs
+++ b/src/test/compile-fail/variadic-ffi-3.rs
@@ -17,7 +17,9 @@ extern "C" fn bar(f: isize, x: u8) {}
 fn main() {
     unsafe {
         foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied
+        //~^ NOTE the following parameter types were expected
         foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied
+        //~^ NOTE the following parameter types were expected
 
         let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
         //~^ ERROR: mismatched types
diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs
index d007b507556..add09384094 100644
--- a/src/test/debuginfo/function-arg-initialization.rs
+++ b/src/test/debuginfo/function-arg-initialization.rs
@@ -228,7 +228,7 @@
 #![omit_gdb_pretty_printer_section]
 
 fn immediate_args(a: isize, b: bool, c: f64) {
-    println!("") // #break
+    zzz(); // #break
 }
 
 struct BigStruct {
@@ -243,7 +243,7 @@ struct BigStruct {
 }
 
 fn non_immediate_args(a: BigStruct, b: BigStruct) {
-    println!("") // #break
+    zzz(); // #break
 }
 
 fn binding(a: i64, b: u64, c: f64) {
@@ -257,7 +257,7 @@ fn assignment(mut a: u64, b: u64, c: f64) {
 }
 
 fn function_call(x: u64, y: u64, z: f64) {
-    println!("Hi!") // #break
+    zzz(); // #break
 }
 
 fn identifier(x: u64, y: u64, z: f64) -> u64 {
@@ -333,3 +333,5 @@ fn main() {
     while_expr(40, 41, 42);
     loop_expr(43, 44, 45);
 }
+
+fn zzz() {()}
diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
index f0ecda92993..b5b6ca75727 100644
--- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
+++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
@@ -247,11 +247,10 @@
 // lldb-command:continue
 
 #![allow(dead_code, unused_assignments, unused_variables)]
-#![feature(omit_gdb_pretty_printer_section, rustc_attrs)]
+#![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn immediate_args(a: isize, b: bool, c: f64) {
     println!("");
 }
@@ -268,51 +267,43 @@ struct BigStruct {
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn non_immediate_args(a: BigStruct, b: BigStruct) {
     println!("");
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn binding(a: i64, b: u64, c: f64) {
     let x = 0;
     println!("");
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn assignment(mut a: u64, b: u64, c: f64) {
     a = b;
     println!("");
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn function_call(x: u64, y: u64, z: f64) {
     println!("Hi!")
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn identifier(x: u64, y: u64, z: f64) -> u64 {
     x
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn return_expr(x: u64, y: u64, z: f64) -> u64 {
     return x;
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
     x + y
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn if_expr(x: u64, y: u64, z: f64) -> u64 {
     if x + y < 1000 {
         x
@@ -322,7 +313,6 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 {
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
     while x + y < 1000 {
         x += z
@@ -331,7 +321,6 @@ fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
     loop {
         x += z;
diff --git a/src/test/pretty/attr-variant-data.rs b/src/test/pretty/attr-variant-data.rs
new file mode 100644
index 00000000000..1ffacaa9f5a
--- /dev/null
+++ b/src/test/pretty/attr-variant-data.rs
@@ -0,0 +1,51 @@
+// 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.
+
+// pp-exact
+// Testing that both the inner item and next outer item are
+// preserved, and that the first outer item parsed in main is not
+// accidentally carried over to each inner function
+
+#![feature(custom_attribute)]
+#![feature(custom_derive)]
+
+#[derive(Serialize, Deserialize)]
+struct X;
+
+#[derive(Serialize, Deserialize)]
+struct WithRef<'a, T: 'a> {
+    #[serde(skip_deserializing)]
+    t: Option<&'a T>,
+    #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+    x: X,
+}
+
+#[derive(Serialize, Deserialize)]
+enum EnumWith<T> {
+    Unit,
+    Newtype(
+            #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+            X),
+    Tuple(T,
+          #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+          X),
+    Struct {
+        t: T,
+        #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+        x: X,
+    },
+}
+
+#[derive(Serialize, Deserialize)]
+struct Tuple<T>(T,
+                #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+                X);
+
+fn main() { }
diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs
index 41a6fd05c37..560b742f8a6 100644
--- a/src/test/run-fail-fulldeps/qquote.rs
+++ b/src/test/run-fail-fulldeps/qquote.rs
@@ -23,11 +23,11 @@ use syntax::print::pprust;
 
 fn main() {
     let ps = syntax::parse::ParseSess::new();
-    let mut feature_gated_cfgs = vec![];
+    let mut loader = syntax::ext::base::DummyMacroLoader;
     let mut cx = syntax::ext::base::ExtCtxt::new(
         &ps, vec![],
         syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
-        &mut feature_gated_cfgs);
+        &mut loader);
     cx.bt_push(syntax::codemap::ExpnInfo {
         call_site: DUMMY_SP,
         callee: syntax::codemap::NameAndSpan {
diff --git a/src/test/run-fail/args-panic.rs b/src/test/run-fail/args-panic.rs
index 47831f1af73..b8fb03faf08 100644
--- a/src/test/run-fail/args-panic.rs
+++ b/src/test/run-fail/args-panic.rs
@@ -14,6 +14,10 @@
 #![allow(unknown_features)]
 #![feature(box_syntax)]
 
-fn f(_a: isize, _b: isize, _c: Box<isize>) { panic!("moop"); }
+fn f(_a: isize, _b: isize, _c: Box<isize>) {
+    panic!("moop");
+}
 
-fn main() { f(1, panic!("meep"), box 42); }
+fn main() {
+    f(1, panic!("meep"), box 42);
+}
diff --git a/src/test/run-fail/assert-eq-macro-panic.rs b/src/test/run-fail/assert-eq-macro-panic.rs
index 0b35062b186..a3e0a1f904f 100644
--- a/src/test/run-fail/assert-eq-macro-panic.rs
+++ b/src/test/run-fail/assert-eq-macro-panic.rs
@@ -11,5 +11,5 @@
 // error-pattern:assertion failed: `(left == right)` (left: `14`, right: `15`)
 
 fn main() {
-    assert_eq!(14,15);
+    assert_eq!(14, 15);
 }
diff --git a/src/test/run-fail/binop-fail-3.rs b/src/test/run-fail/binop-fail-3.rs
index 8cabd3b3262..5be9cd4a9bc 100644
--- a/src/test/run-fail/binop-fail-3.rs
+++ b/src/test/run-fail/binop-fail-3.rs
@@ -9,7 +9,9 @@
 // except according to those terms.
 
 // error-pattern:quux
-fn foo() -> ! { panic!("quux"); }
+fn foo() -> ! {
+    panic!("quux");
+}
 fn main() {
     foo() == foo(); // these types wind up being defaulted to ()
 }
diff --git a/src/test/run-fail/binop-panic.rs b/src/test/run-fail/binop-panic.rs
index 159c33198a6..fb2db7ea998 100644
--- a/src/test/run-fail/binop-panic.rs
+++ b/src/test/run-fail/binop-panic.rs
@@ -9,5 +9,10 @@
 // except according to those terms.
 
 // error-pattern:quux
-fn my_err(s: String) -> ! { println!("{}", s); panic!("quux"); }
-fn main() { 3_usize == my_err("bye".to_string()); }
+fn my_err(s: String) -> ! {
+    println!("{}", s);
+    panic!("quux");
+}
+fn main() {
+    3_usize == my_err("bye".to_string());
+}
diff --git a/src/test/run-fail/bug-2470-bounds-check-overflow.rs b/src/test/run-fail/bug-2470-bounds-check-overflow.rs
index 5e3da8476af..4a294d8fabc 100644
--- a/src/test/run-fail/bug-2470-bounds-check-overflow.rs
+++ b/src/test/run-fail/bug-2470-bounds-check-overflow.rs
@@ -20,7 +20,7 @@ fn main() {
     // address of the 0th cell in the array (even though the index is
     // huge).
 
-    let x = vec!(1_usize,2_usize,3_usize);
+    let x = vec![1_usize, 2_usize, 3_usize];
 
     let base = x.as_ptr() as usize;
     let idx = base / mem::size_of::<usize>();
@@ -28,7 +28,7 @@ fn main() {
     println!("ov1 idx = 0x{:x}", idx);
     println!("ov1 sizeof::<usize>() = 0x{:x}", mem::size_of::<usize>());
     println!("ov1 idx * sizeof::<usize>() = 0x{:x}",
-           idx * mem::size_of::<usize>());
+             idx * mem::size_of::<usize>());
 
     // This should panic.
     println!("ov1 0x{:x}", x[idx]);
diff --git a/src/test/run-fail/bug-811.rs b/src/test/run-fail/bug-811.rs
index fc64d7c1ba3..c0e02ccd61b 100644
--- a/src/test/run-fail/bug-811.rs
+++ b/src/test/run-fail/bug-811.rs
@@ -12,7 +12,9 @@
 
 use std::marker::PhantomData;
 
-fn test00_start(ch: chan_t<isize>, message: isize) { send(ch, message); }
+fn test00_start(ch: chan_t<isize>, message: isize) {
+    send(ch, message);
+}
 
 type task_id = isize;
 type port_id = isize;
@@ -23,6 +25,10 @@ struct chan_t<T> {
     marker: PhantomData<*mut T>,
 }
 
-fn send<T:Send>(_ch: chan_t<T>, _data: T) { panic!(); }
+fn send<T: Send>(_ch: chan_t<T>, _data: T) {
+    panic!();
+}
 
-fn main() { panic!("quux"); }
+fn main() {
+    panic!("quux");
+}
diff --git a/src/test/run-fail/doublepanic.rs b/src/test/run-fail/doublepanic.rs
index 3835a16a5c2..936ebd96897 100644
--- a/src/test/run-fail/doublepanic.rs
+++ b/src/test/run-fail/doublepanic.rs
@@ -10,7 +10,7 @@
 
 #![allow(unreachable_code)]
 
-//error-pattern:One
+// error-pattern:One
 fn main() {
     panic!("One");
     panic!("Two");
diff --git a/src/test/run-fail/explicit-panic-msg.rs b/src/test/run-fail/explicit-panic-msg.rs
index c9c04e5f2da..907fae02b41 100644
--- a/src/test/run-fail/explicit-panic-msg.rs
+++ b/src/test/run-fail/explicit-panic-msg.rs
@@ -14,6 +14,8 @@
 // error-pattern:wooooo
 fn main() {
     let mut a = 1;
-    if 1 == 1 { a = 2; }
+    if 1 == 1 {
+        a = 2;
+    }
     panic!(format!("woooo{}", "o"));
 }
diff --git a/src/test/run-fail/explicit-panic.rs b/src/test/run-fail/explicit-panic.rs
index 4699897bf8a..928e7326b66 100644
--- a/src/test/run-fail/explicit-panic.rs
+++ b/src/test/run-fail/explicit-panic.rs
@@ -12,4 +12,6 @@
 
 
 // error-pattern:explicit
-fn main() { panic!(); }
+fn main() {
+    panic!();
+}
diff --git a/src/test/run-fail/expr-fn-panic.rs b/src/test/run-fail/expr-fn-panic.rs
index 8cf018fb770..f7a88975425 100644
--- a/src/test/run-fail/expr-fn-panic.rs
+++ b/src/test/run-fail/expr-fn-panic.rs
@@ -10,6 +10,10 @@
 
 // error-pattern:explicit panic
 
-fn f() -> ! { panic!() }
+fn f() -> ! {
+    panic!()
+}
 
-fn main() { f(); }
+fn main() {
+    f();
+}
diff --git a/src/test/run-fail/expr-if-panic-fn.rs b/src/test/run-fail/expr-if-panic-fn.rs
index e9f493c16f1..a8ec8f3f414 100644
--- a/src/test/run-fail/expr-if-panic-fn.rs
+++ b/src/test/run-fail/expr-if-panic-fn.rs
@@ -10,8 +10,19 @@
 
 // error-pattern:explicit panic
 
-fn f() -> ! { panic!() }
+fn f() -> ! {
+    panic!()
+}
 
-fn g() -> isize { let x = if true { f() } else { 10 }; return x; }
+fn g() -> isize {
+    let x = if true {
+        f()
+    } else {
+        10
+    };
+    return x;
+}
 
-fn main() { g(); }
+fn main() {
+    g();
+}
diff --git a/src/test/run-fail/expr-if-panic.rs b/src/test/run-fail/expr-if-panic.rs
index b6791271a11..25bf43751f0 100644
--- a/src/test/run-fail/expr-if-panic.rs
+++ b/src/test/run-fail/expr-if-panic.rs
@@ -10,4 +10,12 @@
 
 // error-pattern:explicit panic
 
-fn main() { let _x = if false { 0 } else if true { panic!() } else { 10 }; }
+fn main() {
+    let _x = if false {
+        0
+    } else if true {
+        panic!()
+    } else {
+        10
+    };
+}
diff --git a/src/test/run-fail/expr-match-panic-fn.rs b/src/test/run-fail/expr-match-panic-fn.rs
index 0269eb0af9c..6758ac6c4d4 100644
--- a/src/test/run-fail/expr-match-panic-fn.rs
+++ b/src/test/run-fail/expr-match-panic-fn.rs
@@ -10,8 +10,18 @@
 
 // error-pattern:explicit panic
 
-fn f() -> ! { panic!() }
+fn f() -> ! {
+    panic!()
+}
 
-fn g() -> isize { let x = match true { true => { f() } false => { 10 } }; return x; }
+fn g() -> isize {
+    let x = match true {
+        true => f(),
+        false => 10,
+    };
+    return x;
+}
 
-fn main() { g(); }
+fn main() {
+    g();
+}
diff --git a/src/test/run-fail/expr-match-panic.rs b/src/test/run-fail/expr-match-panic.rs
index 3a6bd59b3ac..8876fb1f49b 100644
--- a/src/test/run-fail/expr-match-panic.rs
+++ b/src/test/run-fail/expr-match-panic.rs
@@ -10,4 +10,9 @@
 
 // error-pattern:explicit panic
 
-fn main() { let _x = match true { false => { 0 } true => { panic!() } }; }
+fn main() {
+    let _x = match true {
+        false => 0,
+        true => panic!(),
+    };
+}
diff --git a/src/test/run-fail/for-each-loop-panic.rs b/src/test/run-fail/for-each-loop-panic.rs
index a1a760c040c..a462d836019 100644
--- a/src/test/run-fail/for-each-loop-panic.rs
+++ b/src/test/run-fail/for-each-loop-panic.rs
@@ -10,4 +10,8 @@
 
 // error-pattern:moop
 
-fn main() { for _ in 0_usize..10_usize { panic!("moop"); } }
+fn main() {
+    for _ in 0_usize..10_usize {
+        panic!("moop");
+    }
+}
diff --git a/src/test/run-fail/if-check-panic.rs b/src/test/run-fail/if-check-panic.rs
index 8c4caccdb65..f8b2d11cb64 100644
--- a/src/test/run-fail/if-check-panic.rs
+++ b/src/test/run-fail/if-check-panic.rs
@@ -12,7 +12,11 @@
 fn even(x: usize) -> bool {
     if x < 2 {
         return false;
-    } else if x == 2 { return true; } else { return even(x - 2); }
+    } else if x == 2 {
+        return true;
+    } else {
+        return even(x - 2);
+    }
 }
 
 fn foo(x: usize) {
@@ -23,4 +27,6 @@ fn foo(x: usize) {
     }
 }
 
-fn main() { foo(3); }
+fn main() {
+    foo(3);
+}
diff --git a/src/test/run-fail/if-cond-bot.rs b/src/test/run-fail/if-cond-bot.rs
index f38b00ab46d..203bc8fc65f 100644
--- a/src/test/run-fail/if-cond-bot.rs
+++ b/src/test/run-fail/if-cond-bot.rs
@@ -9,5 +9,11 @@
 // except according to those terms.
 
 // error-pattern:quux
-fn my_err(s: String) -> ! { println!("{}", s); panic!("quux"); }
-fn main() { if my_err("bye".to_string()) { } }
+fn my_err(s: String) -> ! {
+    println!("{}", s);
+    panic!("quux");
+}
+fn main() {
+    if my_err("bye".to_string()) {
+    }
+}
diff --git a/src/test/run-fail/issue-12920.rs b/src/test/run-fail/issue-12920.rs
index cbc92c640d2..39a819f3d52 100644
--- a/src/test/run-fail/issue-12920.rs
+++ b/src/test/run-fail/issue-12920.rs
@@ -11,5 +11,6 @@
 // error-pattern:explicit panic
 
 pub fn main() {
-    panic!(); println!("{}", 1);
+    panic!();
+    println!("{}", 1);
 }
diff --git a/src/test/run-fail/issue-18576.rs b/src/test/run-fail/issue-18576.rs
index e326949458e..88fb8f1b0c4 100644
--- a/src/test/run-fail/issue-18576.rs
+++ b/src/test/run-fail/issue-18576.rs
@@ -20,4 +20,4 @@ fn main() {
     let pointer = other;
     pointer();
 }
-extern fn other() {}
+extern "C" fn other() {}
diff --git a/src/test/run-fail/issue-20971.rs b/src/test/run-fail/issue-20971.rs
index 818f0e13941..e433a45731f 100644
--- a/src/test/run-fail/issue-20971.rs
+++ b/src/test/run-fail/issue-20971.rs
@@ -19,16 +19,13 @@ pub trait Parser {
 
 impl Parser for () {
     type Input = ();
-    fn parse(&mut self, input: ()) {
-
-    }
+    fn parse(&mut self, input: ()) {}
 }
 
-pub fn many() -> Box<Parser<Input=<() as Parser>::Input> + 'static> {
+pub fn many() -> Box<Parser<Input = <() as Parser>::Input> + 'static> {
     panic!("Hello, world!")
 }
 
 fn main() {
-    many()
-        .parse(());
+    many().parse(());
 }
diff --git a/src/test/run-fail/issue-2444.rs b/src/test/run-fail/issue-2444.rs
index ce91af95d96..f55b1ba03de 100644
--- a/src/test/run-fail/issue-2444.rs
+++ b/src/test/run-fail/issue-2444.rs
@@ -12,10 +12,14 @@
 
 use std::sync::Arc;
 
-enum e<T> { ee(Arc<T>) }
+enum e<T> {
+    ee(Arc<T>),
+}
 
-fn foo() -> e<isize> {panic!();}
+fn foo() -> e<isize> {
+    panic!();
+}
 
 fn main() {
-   let _f = foo();
+    let _f = foo();
 }
diff --git a/src/test/run-fail/issue-28934.rs b/src/test/run-fail/issue-28934.rs
index 2f437c7a814..b32a504cb6b 100644
--- a/src/test/run-fail/issue-28934.rs
+++ b/src/test/run-fail/issue-28934.rs
@@ -17,9 +17,14 @@ struct Parser<'i: 't, 't>(&'i u8, &'t u8);
 
 impl<'i, 't> Parser<'i, 't> {
     fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()>
-        where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T { panic!() }
+        where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T
+    {
+        panic!()
+    }
 
-    fn expect_exhausted(&mut self) -> Result<(), ()> { Ok(()) }
+    fn expect_exhausted(&mut self) -> Result<(), ()> {
+        Ok(())
+    }
 }
 
 fn main() {
diff --git a/src/test/run-fail/issue-3029.rs b/src/test/run-fail/issue-3029.rs
index 4d048fe0fcf..1ada7771cd6 100644
--- a/src/test/run-fail/issue-3029.rs
+++ b/src/test/run-fail/issue-3029.rs
@@ -16,7 +16,7 @@
 // error-pattern:so long
 fn main() {
     let mut x = Vec::new();
-    let y = vec!(3);
+    let y = vec![3];
     panic!("so long");
     x.extend(y.into_iter());
 }
diff --git a/src/test/run-fail/issue-6458-1.rs b/src/test/run-fail/issue-6458-1.rs
index 631517f6a3c..7da27bd15f2 100644
--- a/src/test/run-fail/issue-6458-1.rs
+++ b/src/test/run-fail/issue-6458-1.rs
@@ -11,4 +11,6 @@
 // error-pattern:explicit panic
 
 fn foo<T>(t: T) {}
-fn main() { foo(panic!()) }
+fn main() {
+    foo(panic!())
+}
diff --git a/src/test/run-fail/issue-948.rs b/src/test/run-fail/issue-948.rs
index 272d85d7b50..4a1bc856a39 100644
--- a/src/test/run-fail/issue-948.rs
+++ b/src/test/run-fail/issue-948.rs
@@ -12,9 +12,12 @@
 
 #![allow(unused_variables)]
 
-struct Point { x: isize, y: isize }
+struct Point {
+    x: isize,
+    y: isize,
+}
 
 fn main() {
-    let origin = Point {x: 0, y: 0};
-    let f: Point = Point {x: (panic!("beep boop")),.. origin};
+    let origin = Point { x: 0, y: 0 };
+    let f: Point = Point { x: (panic!("beep boop")), ..origin };
 }
diff --git a/src/test/run-fail/match-bot-panic.rs b/src/test/run-fail/match-bot-panic.rs
index c1f90bb8f2b..5a6eedb4863 100644
--- a/src/test/run-fail/match-bot-panic.rs
+++ b/src/test/run-fail/match-bot-panic.rs
@@ -13,10 +13,12 @@
 #![allow(unreachable_code)]
 #![allow(unused_variables)]
 
-fn foo(s: String) { }
+fn foo(s: String) {}
 
 fn main() {
-    let i =
-        match Some::<isize>(3) { None::<isize> => { panic!() } Some::<isize>(_) => { panic!() } };
+    let i = match Some::<isize>(3) {
+        None::<isize> => panic!(),
+        Some::<isize>(_) => panic!(),
+    };
     foo(i);
 }
diff --git a/src/test/run-fail/match-disc-bot.rs b/src/test/run-fail/match-disc-bot.rs
index 90b729a6dd2..a369a9889cc 100644
--- a/src/test/run-fail/match-disc-bot.rs
+++ b/src/test/run-fail/match-disc-bot.rs
@@ -9,6 +9,15 @@
 // except according to those terms.
 
 // error-pattern:quux
-fn f() -> ! { panic!("quux") }
-fn g() -> isize { match f() { true => { 1 } false => { 0 } } }
-fn main() { g(); }
+fn f() -> ! {
+    panic!("quux")
+}
+fn g() -> isize {
+    match f() {
+        true => 1,
+        false => 0,
+    }
+}
+fn main() {
+    g();
+}
diff --git a/src/test/run-fail/match-wildcards.rs b/src/test/run-fail/match-wildcards.rs
index 54e24de3165..61bfd38c5f4 100644
--- a/src/test/run-fail/match-wildcards.rs
+++ b/src/test/run-fail/match-wildcards.rs
@@ -11,10 +11,18 @@
 // error-pattern:squirrelcupcake
 fn cmp() -> isize {
     match (Some('a'), None::<char>) {
-        (Some(_), _) => { panic!("squirrelcupcake"); }
-        (_, Some(_)) => { panic!(); }
-        _                    => { panic!("wat"); }
+        (Some(_), _) => {
+            panic!("squirrelcupcake");
+        }
+        (_, Some(_)) => {
+            panic!();
+        }
+        _ => {
+            panic!("wat");
+        }
     }
 }
 
-fn main() { println!("{}", cmp()); }
+fn main() {
+    println!("{}", cmp());
+}
diff --git a/src/test/run-fail/meta-revision-bad.rs b/src/test/run-fail/meta-revision-bad.rs
index bf521d4b4e5..0b7c464800a 100644
--- a/src/test/run-fail/meta-revision-bad.rs
+++ b/src/test/run-fail/meta-revision-bad.rs
@@ -16,7 +16,15 @@
 //[foo] error-pattern:bar
 //[bar] error-pattern:foo
 
-#[cfg(foo)] fn die() {panic!("foo");}
-#[cfg(bar)] fn die() {panic!("bar");}
+#[cfg(foo)]
+fn die() {
+    panic!("foo");
+}
+#[cfg(bar)]
+fn die() {
+    panic!("bar");
+}
 
-fn main() { die(); }
+fn main() {
+    die();
+}
diff --git a/src/test/run-fail/meta-revision-ok.rs b/src/test/run-fail/meta-revision-ok.rs
index f74ec39fdf2..99dd332c558 100644
--- a/src/test/run-fail/meta-revision-ok.rs
+++ b/src/test/run-fail/meta-revision-ok.rs
@@ -15,7 +15,15 @@
 //[foo] error-pattern:foo
 //[bar] error-pattern:bar
 
-#[cfg(foo)] fn die() {panic!("foo");}
-#[cfg(bar)] fn die() {panic!("bar");}
+#[cfg(foo)]
+fn die() {
+    panic!("foo");
+}
+#[cfg(bar)]
+fn die() {
+    panic!("bar");
+}
 
-fn main() { die(); }
+fn main() {
+    die();
+}
diff --git a/src/test/run-fail/mir_dynamic_drops_1.rs b/src/test/run-fail/mir_dynamic_drops_1.rs
index 590b9fbe43c..16160a1496f 100644
--- a/src/test/run-fail/mir_dynamic_drops_1.rs
+++ b/src/test/run-fail/mir_dynamic_drops_1.rs
@@ -27,7 +27,7 @@ impl<'a> Drop for Droppable<'a> {
 }
 
 #[rustc_mir]
-fn mir(){
+fn mir() {
     let (mut xv, mut yv) = (false, false);
     let x = Droppable(&mut xv, 1);
     let y = Droppable(&mut yv, 2);
diff --git a/src/test/run-fail/mir_dynamic_drops_2.rs b/src/test/run-fail/mir_dynamic_drops_2.rs
index eafd3d351fb..803ca53bf7a 100644
--- a/src/test/run-fail/mir_dynamic_drops_2.rs
+++ b/src/test/run-fail/mir_dynamic_drops_2.rs
@@ -26,7 +26,7 @@ impl<'a> Drop for Droppable<'a> {
 }
 
 #[rustc_mir]
-fn mir<'a>(d: Droppable<'a>){
+fn mir<'a>(d: Droppable<'a>) {
     loop {
         let x = d;
         break;
diff --git a/src/test/run-fail/mir_dynamic_drops_3.rs b/src/test/run-fail/mir_dynamic_drops_3.rs
index 730d9c8f226..afc037f48aa 100644
--- a/src/test/run-fail/mir_dynamic_drops_3.rs
+++ b/src/test/run-fail/mir_dynamic_drops_3.rs
@@ -33,7 +33,7 @@ fn may_panic<'a>() -> Droppable<'a> {
 }
 
 #[rustc_mir]
-fn mir<'a>(d: Droppable<'a>){
+fn mir<'a>(d: Droppable<'a>) {
     let (mut a, mut b) = (false, false);
     let y = Droppable(&mut a, 2);
     let x = [Droppable(&mut b, 1), y, d, may_panic()];
diff --git a/src/test/run-fail/panic-arg.rs b/src/test/run-fail/panic-arg.rs
index 0e029b6ecbc..9023784050f 100644
--- a/src/test/run-fail/panic-arg.rs
+++ b/src/test/run-fail/panic-arg.rs
@@ -9,6 +9,10 @@
 // except according to those terms.
 
 // error-pattern:woe
-fn f(a: isize) { println!("{}", a); }
+fn f(a: isize) {
+    println!("{}", a);
+}
 
-fn main() { f(panic!("woe")); }
+fn main() {
+    f(panic!("woe"));
+}
diff --git a/src/test/run-fail/panic-macro-any.rs b/src/test/run-fail/panic-macro-any.rs
index ce6a5d46cc7..7ca45565d85 100644
--- a/src/test/run-fail/panic-macro-any.rs
+++ b/src/test/run-fail/panic-macro-any.rs
@@ -14,5 +14,5 @@
 #![feature(box_syntax)]
 
 fn main() {
-    panic!(box 413 as Box<::std::any::Any+Send>);
+    panic!(box 413 as Box<::std::any::Any + Send>);
 }
diff --git a/src/test/run-fail/panic-main.rs b/src/test/run-fail/panic-main.rs
index 877ea9cd0a4..fd2919bfe12 100644
--- a/src/test/run-fail/panic-main.rs
+++ b/src/test/run-fail/panic-main.rs
@@ -9,4 +9,6 @@
 // except according to those terms.
 
 // error-pattern:moop
-fn main() { panic!("moop"); }
+fn main() {
+    panic!("moop");
+}
diff --git a/src/test/run-fail/panic-parens.rs b/src/test/run-fail/panic-parens.rs
index 06655e4c681..1917a7e2a7f 100644
--- a/src/test/run-fail/panic-parens.rs
+++ b/src/test/run-fail/panic-parens.rs
@@ -13,11 +13,15 @@
 // error-pattern:oops
 
 fn bigpanic() {
-    while (panic!("oops")) { if (panic!()) {
-        match (panic!()) { () => {
+    while (panic!("oops")) {
+        if (panic!()) {
+            match (panic!()) {
+                () => {}
+            }
         }
-                     }
-    }};
+    }
 }
 
-fn main() { bigpanic(); }
+fn main() {
+    bigpanic();
+}
diff --git a/src/test/run-fail/panic-task-name-none.rs b/src/test/run-fail/panic-task-name-none.rs
index 3a5ac5a1009..ab505038305 100644
--- a/src/test/run-fail/panic-task-name-none.rs
+++ b/src/test/run-fail/panic-task-name-none.rs
@@ -13,8 +13,9 @@
 use std::thread;
 
 fn main() {
-    let r: Result<(),_> = thread::spawn(move|| {
-        panic!("test");
-    }).join();
+    let r: Result<(), _> = thread::spawn(move || {
+                               panic!("test");
+                           })
+                               .join();
     assert!(r.is_ok());
 }
diff --git a/src/test/run-fail/panic-task-name-owned.rs b/src/test/run-fail/panic-task-name-owned.rs
index 561f141100c..2d2371f5ce7 100644
--- a/src/test/run-fail/panic-task-name-owned.rs
+++ b/src/test/run-fail/panic-task-name-owned.rs
@@ -13,9 +13,14 @@
 use std::thread::Builder;
 
 fn main() {
-    let r: () = Builder::new().name("owned name".to_string()).spawn(move|| {
-        panic!("test");
-        ()
-    }).unwrap().join().unwrap();
+    let r: () = Builder::new()
+                    .name("owned name".to_string())
+                    .spawn(move || {
+                        panic!("test");
+                        ()
+                    })
+                    .unwrap()
+                    .join()
+                    .unwrap();
     panic!();
 }
diff --git a/src/test/run-fail/panic.rs b/src/test/run-fail/panic.rs
index 6773c6b9b51..f59e6001794 100644
--- a/src/test/run-fail/panic.rs
+++ b/src/test/run-fail/panic.rs
@@ -9,4 +9,6 @@
 // except according to those terms.
 
 // error-pattern:1 == 2
-fn main() { assert!(1 == 2); }
+fn main() {
+    assert!(1 == 2);
+}
diff --git a/src/test/run-fail/result-get-panic.rs b/src/test/run-fail/result-get-panic.rs
index dbded107544..6378b4ec795 100644
--- a/src/test/run-fail/result-get-panic.rs
+++ b/src/test/run-fail/result-get-panic.rs
@@ -13,5 +13,5 @@
 use std::result::Result::Err;
 
 fn main() {
-    println!("{}", Err::<isize,String>("kitty".to_string()).unwrap());
+    println!("{}", Err::<isize, String>("kitty".to_string()).unwrap());
 }
diff --git a/src/test/run-fail/rhs-type.rs b/src/test/run-fail/rhs-type.rs
index ff4040ded5f..e16ce9c8edb 100644
--- a/src/test/run-fail/rhs-type.rs
+++ b/src/test/run-fail/rhs-type.rs
@@ -15,9 +15,11 @@
 #![allow(unreachable_code)]
 #![allow(unused_variables)]
 
-struct T { t: String }
+struct T {
+    t: String,
+}
 
 fn main() {
     let pth = panic!("bye");
-    let _rs: T = T {t: pth};
+    let _rs: T = T { t: pth };
 }
diff --git a/src/test/run-fail/run-unexported-tests.rs b/src/test/run-fail/run-unexported-tests.rs
index 0e218740ab1..8158333ade8 100644
--- a/src/test/run-fail/run-unexported-tests.rs
+++ b/src/test/run-fail/run-unexported-tests.rs
@@ -14,8 +14,10 @@
 // ignore-pretty: does not work well with `--test`
 
 mod m {
-    pub fn exported() { }
+    pub fn exported() {}
 
     #[test]
-    fn unexported() { panic!("runned an unexported test"); }
+    fn unexported() {
+        panic!("runned an unexported test");
+    }
 }
diff --git a/src/test/run-fail/unimplemented-macro-panic.rs b/src/test/run-fail/unimplemented-macro-panic.rs
index 7eff1fee625..e3d8aa2e460 100644
--- a/src/test/run-fail/unimplemented-macro-panic.rs
+++ b/src/test/run-fail/unimplemented-macro-panic.rs
@@ -9,4 +9,6 @@
 // except according to those terms.
 
 // error-pattern:not yet implemented
-fn main() { unimplemented!() }
+fn main() {
+    unimplemented!()
+}
diff --git a/src/test/run-fail/unique-panic.rs b/src/test/run-fail/unique-panic.rs
index 83b2bb91f00..3dc3d0afda1 100644
--- a/src/test/run-fail/unique-panic.rs
+++ b/src/test/run-fail/unique-panic.rs
@@ -10,4 +10,6 @@
 
 // error-pattern: panic
 
-fn main() { Box::new(panic!()); }
+fn main() {
+    Box::new(panic!());
+}
diff --git a/src/test/run-fail/unreachable-macro-panic.rs b/src/test/run-fail/unreachable-macro-panic.rs
index 07e05c6fed9..493fe7ee4f8 100644
--- a/src/test/run-fail/unreachable-macro-panic.rs
+++ b/src/test/run-fail/unreachable-macro-panic.rs
@@ -9,4 +9,6 @@
 // except according to those terms.
 
 // error-pattern:internal error: entered unreachable code
-fn main() { unreachable!() }
+fn main() {
+    unreachable!()
+}
diff --git a/src/test/run-fail/unreachable-static-msg.rs b/src/test/run-fail/unreachable-static-msg.rs
index 25894a88541..0a9dee3d0b9 100644
--- a/src/test/run-fail/unreachable-static-msg.rs
+++ b/src/test/run-fail/unreachable-static-msg.rs
@@ -9,4 +9,6 @@
 // except according to those terms.
 
 // error-pattern:internal error: entered unreachable code: uhoh
-fn main() { unreachable!("uhoh") }
+fn main() {
+    unreachable!("uhoh")
+}
diff --git a/src/test/run-fail/unreachable.rs b/src/test/run-fail/unreachable.rs
index 07e05c6fed9..493fe7ee4f8 100644
--- a/src/test/run-fail/unreachable.rs
+++ b/src/test/run-fail/unreachable.rs
@@ -9,4 +9,6 @@
 // except according to those terms.
 
 // error-pattern:internal error: entered unreachable code
-fn main() { unreachable!() }
+fn main() {
+    unreachable!()
+}
diff --git a/src/test/run-fail/unwind-interleaved.rs b/src/test/run-fail/unwind-interleaved.rs
index 91a33329a4f..0a7be154d5d 100644
--- a/src/test/run-fail/unwind-interleaved.rs
+++ b/src/test/run-fail/unwind-interleaved.rs
@@ -10,13 +10,15 @@
 
 // error-pattern:fail
 
-fn a() { }
+fn a() {}
 
-fn b() { panic!(); }
+fn b() {
+    panic!();
+}
 
 fn main() {
-    let _x = vec!(0);
+    let _x = vec![0];
     a();
-    let _y = vec!(0);
+    let _y = vec![0];
     b();
 }
diff --git a/src/test/run-fail/unwind-rec.rs b/src/test/run-fail/unwind-rec.rs
index 6df279b047f..5177b4091d7 100644
--- a/src/test/run-fail/unwind-rec.rs
+++ b/src/test/run-fail/unwind-rec.rs
@@ -15,10 +15,10 @@ fn build() -> Vec<isize> {
     panic!();
 }
 
-struct Blk { node: Vec<isize> }
+struct Blk {
+    node: Vec<isize>,
+}
 
 fn main() {
-    let _blk = Blk {
-        node: build()
-    };
+    let _blk = Blk { node: build() };
 }
diff --git a/src/test/run-fail/unwind-rec2.rs b/src/test/run-fail/unwind-rec2.rs
index d5d60d18924..3be5036b216 100644
--- a/src/test/run-fail/unwind-rec2.rs
+++ b/src/test/run-fail/unwind-rec2.rs
@@ -12,18 +12,21 @@
 
 
 fn build1() -> Vec<isize> {
-    vec!(0,0,0,0,0,0,0)
+    vec![0, 0, 0, 0, 0, 0, 0]
 }
 
 fn build2() -> Vec<isize> {
     panic!();
 }
 
-struct Blk { node: Vec<isize> , span: Vec<isize> }
+struct Blk {
+    node: Vec<isize>,
+    span: Vec<isize>,
+}
 
 fn main() {
     let _blk = Blk {
         node: build1(),
-        span: build2()
+        span: build2(),
     };
 }
diff --git a/src/test/run-fail/vec-overrun.rs b/src/test/run-fail/vec-overrun.rs
index da52cd56a1a..457ae75a451 100644
--- a/src/test/run-fail/vec-overrun.rs
+++ b/src/test/run-fail/vec-overrun.rs
@@ -12,7 +12,7 @@
 
 
 fn main() {
-    let v: Vec<isize> = vec!(10);
+    let v: Vec<isize> = vec![10];
     let x: usize = 0;
     assert_eq!(v[x], 10);
     // Bounds-check panic.
diff --git a/src/test/run-fail/while-body-panics.rs b/src/test/run-fail/while-body-panics.rs
index cfe499f8a4a..29482612c24 100644
--- a/src/test/run-fail/while-body-panics.rs
+++ b/src/test/run-fail/while-body-panics.rs
@@ -11,4 +11,11 @@
 #![allow(while_true)]
 
 // error-pattern:quux
-fn main() { let _x: isize = { while true { panic!("quux"); } ; 8 } ; }
+fn main() {
+    let _x: isize = {
+        while true {
+            panic!("quux");
+        }
+        8
+    };
+}
diff --git a/src/test/run-fail/while-panic.rs b/src/test/run-fail/while-panic.rs
index f6081e497bf..e410684cd34 100644
--- a/src/test/run-fail/while-panic.rs
+++ b/src/test/run-fail/while-panic.rs
@@ -12,5 +12,10 @@
 
 // error-pattern:giraffe
 fn main() {
-    panic!({ while true { panic!("giraffe") }; "clandestine" });
+    panic!({
+        while true {
+            panic!("giraffe")
+        }
+        "clandestine"
+    });
 }
diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
index 0abf71ba444..604933d40a1 100644
--- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
@@ -29,6 +29,7 @@ use rustc_plugin::Registry;
 struct Pass;
 
 impl transform::Pass for Pass {}
+
 impl<'tcx> MirPass<'tcx> for Pass {
     fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>,
                     _: MirSource, mir: &mut Mir<'tcx>) {
diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs
index 0bb3e610020..65c642a1eca 100644
--- a/src/test/run-pass-fulldeps/qquote.rs
+++ b/src/test/run-pass-fulldeps/qquote.rs
@@ -20,11 +20,11 @@ use syntax::parse::token::intern;
 
 fn main() {
     let ps = syntax::parse::ParseSess::new();
-    let mut feature_gated_cfgs = vec![];
+    let mut loader = syntax::ext::base::DummyMacroLoader;
     let mut cx = syntax::ext::base::ExtCtxt::new(
         &ps, vec![],
         syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
-        &mut feature_gated_cfgs);
+        &mut loader);
     cx.bt_push(syntax::codemap::ExpnInfo {
         call_site: DUMMY_SP,
         callee: syntax::codemap::NameAndSpan {
diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs
index 7b00ea4a520..cee0caeb465 100644
--- a/src/test/run-pass/issue-15080.rs
+++ b/src/test/run-pass/issue-15080.rs
@@ -16,12 +16,12 @@ fn main() {
 
     let mut result = vec!();
     loop {
-        x = match x {
-            [1, n, 3, rest..] => {
+        x = match *x {
+            [1, n, 3, ref rest..] => {
                 result.push(n);
                 rest
             }
-            [n, rest..] => {
+            [n, ref rest..] => {
                 result.push(n);
                 rest
             }
diff --git a/src/test/run-pass/issue-15104.rs b/src/test/run-pass/issue-15104.rs
index b55754ee59b..508360cb701 100644
--- a/src/test/run-pass/issue-15104.rs
+++ b/src/test/run-pass/issue-15104.rs
@@ -16,9 +16,9 @@ fn main() {
 }
 
 fn count_members(v: &[usize]) -> usize {
-    match v {
+    match *v {
         []         => 0,
         [_]        => 1,
-        [_x, xs..] => 1 + count_members(xs)
+        [_, ref xs..] => 1 + count_members(xs)
     }
 }
diff --git a/src/test/run-pass/issue-16648.rs b/src/test/run-pass/issue-16648.rs
index 384bd9df7cf..e596bee8bfe 100644
--- a/src/test/run-pass/issue-16648.rs
+++ b/src/test/run-pass/issue-16648.rs
@@ -9,14 +9,15 @@
 // except according to those terms.
 
 
-#![feature(slice_patterns)]
+#![feature(slice_patterns, rustc_attrs)]
 
+#[rustc_mir]
 fn main() {
     let x: (isize, &[isize]) = (2, &[1, 2]);
     assert_eq!(match x {
-        (0, [_, _]) => 0,
+        (0, &[_, _]) => 0,
         (1, _) => 1,
-        (2, [_, _]) => 2,
+        (2, &[_, _]) => 2,
         (2, _) => 3,
         _ => 4
     }, 2);
diff --git a/src/test/run-pass/issue-21058.rs b/src/test/run-pass/issue-21058.rs
index af767464db3..19cd1cf3df7 100644
--- a/src/test/run-pass/issue-21058.rs
+++ b/src/test/run-pass/issue-21058.rs
@@ -26,5 +26,5 @@ fn main() {
         std::intrinsics::type_name::<NT>(),
         // DST
         std::intrinsics::type_name::<DST>()
-    )}, ("[u8]", "str", "std::marker::Send + 'static", "NT", "DST"));
+    )}, ("[u8]", "str", "std::marker::Send", "NT", "DST"));
 }
diff --git a/src/test/run-pass/issue-23477.rs b/src/test/run-pass/issue-23477.rs
new file mode 100644
index 00000000000..d4671c919b7
--- /dev/null
+++ b/src/test/run-pass/issue-23477.rs
@@ -0,0 +1,23 @@
+// 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.
+// compiler-flags: -g
+
+pub struct Dst {
+    pub a: (),
+    pub b: (),
+    pub data: [u8],
+}
+
+pub unsafe fn borrow(bytes: &[u8]) -> &Dst {
+    let dst: &Dst = std::mem::transmute((bytes.as_ptr(), bytes.len()));
+    dst
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-30240.rs b/src/test/run-pass/issue-30240.rs
new file mode 100644
index 00000000000..3be661ce35e
--- /dev/null
+++ b/src/test/run-pass/issue-30240.rs
@@ -0,0 +1,23 @@
+// 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() {
+    let &ref a = &[0i32] as &[_];
+    assert_eq!(a, &[0i32] as &[_]);
+
+    let &ref a = "hello";
+    assert_eq!(a, "hello");
+
+    match "foo" {
+        "fool" => unreachable!(),
+        "foo" => {},
+        ref _x => unreachable!()
+    }
+}
diff --git a/src/test/run-pass/issue-30276.rs b/src/test/run-pass/issue-30276.rs
new file mode 100644
index 00000000000..5dd0cd8ba53
--- /dev/null
+++ b/src/test/run-pass/issue-30276.rs
@@ -0,0 +1,14 @@
+// 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.
+
+struct Test([i32]);
+fn main() {
+    let _x: fn(_) -> Test = Test;
+}
diff --git a/src/test/run-pass/issue-34074.rs b/src/test/run-pass/issue-34074.rs
new file mode 100644
index 00000000000..169a87f0b12
--- /dev/null
+++ b/src/test/run-pass/issue-34074.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.
+
+// Make sure several unnamed function arguments don't conflict with each other
+
+trait Tr {
+    fn f(u8, u8) {}
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs
index badc013cd62..0008825226b 100644
--- a/src/test/run-pass/issue-7784.rs
+++ b/src/test/run-pass/issue-7784.rs
@@ -11,6 +11,7 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
+#![feature(rustc_attrs)]
 
 use std::ops::Add;
 
@@ -21,6 +22,7 @@ fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] {
     [a, b, b, a]
 }
 
+#[rustc_mir]
 fn main() {
     assert_eq!(foo([1, 2, 3]), (1, 3, 6));
 
diff --git a/src/test/run-pass/match-unsized.rs b/src/test/run-pass/match-unsized.rs
new file mode 100644
index 00000000000..7253672a7ff
--- /dev/null
+++ b/src/test/run-pass/match-unsized.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.
+
+fn main() {
+    let data: &'static str = "Hello, World!";
+    match data {
+        &ref xs => {
+            assert_eq!(data, xs);
+        }
+    }
+}
diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs
index 43e0b442251..010c1455210 100644
--- a/src/test/run-pass/match-vec-alternatives.rs
+++ b/src/test/run-pass/match-vec-alternatives.rs
@@ -11,47 +11,53 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
+#![feature(rustc_attrs)]
 
+#[rustc_mir]
 fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     match (l1, l2) {
-        ([], []) => "both empty",
-        ([], [..]) | ([..], []) => "one empty",
-        ([..], [..]) => "both non-empty"
+        (&[], &[]) => "both empty",
+        (&[], &[..]) | (&[..], &[]) => "one empty",
+        (&[..], &[..]) => "both non-empty"
     }
 }
 
+#[rustc_mir]
 fn match_vecs_cons<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     match (l1, l2) {
-        ([], []) => "both empty",
-        ([], [_, ..]) | ([_, ..], []) => "one empty",
-        ([_, ..], [_, ..]) => "both non-empty"
+        (&[], &[]) => "both empty",
+        (&[], &[_, ..]) | (&[_, ..], &[]) => "one empty",
+        (&[_, ..], &[_, ..]) => "both non-empty"
     }
 }
 
+#[rustc_mir]
 fn match_vecs_snoc<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     match (l1, l2) {
-        ([], []) => "both empty",
-        ([], [.., _]) | ([.., _], []) => "one empty",
-        ([.., _], [.., _]) => "both non-empty"
+        (&[], &[]) => "both empty",
+        (&[], &[.., _]) | (&[.., _], &[]) => "one empty",
+        (&[.., _], &[.., _]) => "both non-empty"
     }
 }
 
+#[rustc_mir]
 fn match_nested_vecs_cons<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
     match (l1, l2) {
-        (Some([]), Ok([])) => "Some(empty), Ok(empty)",
-        (Some([_, ..]), Ok(_)) | (Some([_, ..]), Err(())) => "Some(non-empty), any",
-        (None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)",
-        (None, Ok([_, _, ..])) => "None, Ok(at least two elements)",
+        (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
+        (Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any",
+        (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)",
+        (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
         _ => "other"
     }
 }
 
+#[rustc_mir]
 fn match_nested_vecs_snoc<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
     match (l1, l2) {
-        (Some([]), Ok([])) => "Some(empty), Ok(empty)",
-        (Some([.., _]), Ok(_)) | (Some([.., _]), Err(())) => "Some(non-empty), any",
-        (None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)",
-        (None, Ok([.., _, _])) => "None, Ok(at least two elements)",
+        (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
+        (Some(&[.., _]), Ok(_)) | (Some(&[.., _]), Err(())) => "Some(non-empty), any",
+        (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)",
+        (None, Ok(&[.., _, _])) => "None, Ok(at least two elements)",
         _ => "other"
     }
 }
diff --git a/src/test/run-pass/mir_constval_adts.rs b/src/test/run-pass/mir_constval_adts.rs
index 4e9c0bce646..0ce9e88ef3d 100644
--- a/src/test/run-pass/mir_constval_adts.rs
+++ b/src/test/run-pass/mir_constval_adts.rs
@@ -15,21 +15,23 @@ struct Point {
     _y: i32,
 }
 
+#[derive(PartialEq, Eq, Debug)]
+struct Newtype<T>(T);
+
 const STRUCT: Point = Point { _x: 42, _y: 42 };
 const TUPLE1: (i32, i32) = (42, 42);
 const TUPLE2: (&'static str, &'static str) = ("hello","world");
+const PAIR_NEWTYPE: (Newtype<i32>, Newtype<i32>) = (Newtype(42), Newtype(42));
 
 #[rustc_mir]
-fn mir() -> (Point, (i32, i32), (&'static str, &'static str)){
+fn mir() -> (Point, (i32, i32), (&'static str, &'static str), (Newtype<i32>, Newtype<i32>)) {
     let struct1 = STRUCT;
     let tuple1 = TUPLE1;
     let tuple2 = TUPLE2;
-    (struct1, tuple1, tuple2)
+    let pair_newtype = PAIR_NEWTYPE;
+    (struct1, tuple1, tuple2, pair_newtype)
 }
 
-#[derive(PartialEq, Eq, Debug)]
-struct Newtype<T>(T);
-
 const NEWTYPE: Newtype<&'static str> = Newtype("foobar");
 
 #[rustc_mir]
@@ -39,7 +41,7 @@ fn test_promoted_newtype_str_ref() {
 }
 
 fn main(){
-    assert_eq!(mir(), (STRUCT, TUPLE1, TUPLE2));
+    assert_eq!(mir(), (STRUCT, TUPLE1, TUPLE2, PAIR_NEWTYPE));
     test_promoted_newtype_str_ref();
 }
 
diff --git a/src/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs
index 31e2c892571..2371909b31b 100644
--- a/src/test/run-pass/mir_trans_calls.rs
+++ b/src/test/run-pass/mir_trans_calls.rs
@@ -30,6 +30,7 @@ fn test2(a: isize) -> isize {
     callee(a)
 }
 
+#[derive(PartialEq, Eq, Debug)]
 struct Foo;
 impl Foo {
     fn inherent_method(&self, a: isize) -> isize { a }
@@ -147,6 +148,29 @@ fn test_fn_transmute_zst(x: ()) -> [(); 1] {
     })
 }
 
+#[rustc_mir]
+fn test_fn_ignored_pair() -> ((), ()) {
+    ((), ())
+}
+
+#[rustc_mir]
+fn test_fn_ignored_pair_0() {
+    test_fn_ignored_pair().0
+}
+
+#[rustc_mir]
+fn id<T>(x: T) -> T { x }
+
+#[rustc_mir]
+fn ignored_pair_named() -> (Foo, Foo) {
+    (Foo, Foo)
+}
+
+#[rustc_mir]
+fn test_fn_ignored_pair_named() -> (Foo, Foo) {
+    id(ignored_pair_named())
+}
+
 fn main() {
     assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
     assert_eq!(test2(98), 98);
@@ -169,4 +193,7 @@ fn main() {
 
     assert_eq!(test_fn_nil_call(&(|| 42)), 42);
     assert_eq!(test_fn_transmute_zst(()), [()]);
+
+    assert_eq!(test_fn_ignored_pair_0(), ());
+    assert_eq!(test_fn_ignored_pair_named(), (Foo, Foo));
 }
diff --git a/src/test/run-pass/vec-matching-fold.rs b/src/test/run-pass/vec-matching-fold.rs
index ee70ea58750..7a6129d311e 100644
--- a/src/test/run-pass/vec-matching-fold.rs
+++ b/src/test/run-pass/vec-matching-fold.rs
@@ -11,21 +11,28 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
+#![feature(rustc_attrs)]
 
+use std::fmt::Debug;
+
+#[rustc_mir(graphviz="mir.gv")]
 fn foldl<T, U, F>(values: &[T],
                   initial: U,
                   mut function: F)
                   -> U where
-    U: Clone,
+    U: Clone+Debug, T:Debug,
     F: FnMut(U, &T) -> U,
-{
-    match values {
-        [ref head, tail..] =>
+{    match values {
+        &[ref head, ref tail..] =>
             foldl(tail, function(initial, head), function),
-        [] => initial.clone()
+        &[] => {
+            // FIXME: call guards
+            let res = initial.clone(); res
+        }
     }
 }
 
+#[rustc_mir]
 fn foldr<T, U, F>(values: &[T],
                   initial: U,
                   mut function: F)
@@ -34,9 +41,12 @@ fn foldr<T, U, F>(values: &[T],
     F: FnMut(&T, U) -> U,
 {
     match values {
-        [head.., ref tail] =>
+        &[ref head.., ref tail] =>
             foldr(head, function(tail, initial), function),
-        [] => initial.clone()
+        &[] => {
+            // FIXME: call guards
+            let res = initial.clone(); res
+        }
     }
 }
 
diff --git a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs
index e7553c8e157..1093bc7c18b 100644
--- a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs
+++ b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs
@@ -8,14 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(slice_patterns)]
+#![feature(slice_patterns, rustc_attrs)]
 
+#[rustc_mir]
 pub fn main() {
     let x = &[1, 2, 3, 4, 5];
     let x: &[isize] = &[1, 2, 3, 4, 5];
     if !x.is_empty() {
         let el = match x {
-            [1, ref tail..] => &tail[0],
+            &[1, ref tail..] => &tail[0],
             _ => unreachable!()
         };
         println!("{}", *el);
diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs
index eedf27f8577..075709a63b5 100644
--- a/src/test/run-pass/vec-matching.rs
+++ b/src/test/run-pass/vec-matching.rs
@@ -11,7 +11,9 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
+#![feature(rustc_attrs)]
 
+#[rustc_mir]
 fn a() {
     let x = [1];
     match x {
@@ -21,6 +23,7 @@ fn a() {
     }
 }
 
+#[rustc_mir]
 fn b() {
     let x = [1, 2, 3];
     match x {
@@ -56,6 +59,48 @@ fn b() {
     }
 }
 
+
+#[rustc_mir]
+fn b_slice() {
+    let x : &[_] = &[1, 2, 3];
+    match x {
+        &[a, b, ref c..] => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            let expected: &[_] = &[3];
+            assert_eq!(c, expected);
+        }
+        _ => unreachable!()
+    }
+    match x {
+        &[ref a.., b, c] => {
+            let expected: &[_] = &[1];
+            assert_eq!(a, expected);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+        _ => unreachable!()
+    }
+    match x {
+        &[a, ref b.., c] => {
+            assert_eq!(a, 1);
+            let expected: &[_] = &[2];
+            assert_eq!(b, expected);
+            assert_eq!(c, 3);
+        }
+        _ => unreachable!()
+    }
+    match x {
+        &[a, b, c] => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+        _ => unreachable!()
+    }
+}
+
+#[rustc_mir]
 fn c() {
     let x = [1];
     match x {
@@ -64,6 +109,7 @@ fn c() {
     }
 }
 
+#[rustc_mir]
 fn d() {
     let x = [1, 2, 3];
     let branch = match x {
@@ -75,17 +121,40 @@ fn d() {
     assert_eq!(branch, 1);
 }
 
+#[rustc_mir]
 fn e() {
     let x: &[isize] = &[1, 2, 3];
-    match x {
-        [1, 2] => (),
-        [..] => ()
-    }
+    let a = match *x {
+        [1, 2] => 0,
+        [..] => 1,
+    };
+
+    assert_eq!(a, 1);
+
+    let b = match *x {
+        [2, ..] => 0,
+        [1, 2, ..] => 1,
+        [_] => 2,
+        [..] => 3
+    };
+
+    assert_eq!(b, 1);
+
+
+    let c = match *x {
+        [_, _, _, _, ..] => 0,
+        [1, 2, ..] => 1,
+        [_] => 2,
+        [..] => 3
+    };
+
+    assert_eq!(c, 1);
 }
 
 pub fn main() {
     a();
     b();
+    b_slice();
     c();
     d();
     e();
diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs
index 6cc7e3a072c..6084a0d07a1 100644
--- a/src/test/run-pass/vec-tail-matching.rs
+++ b/src/test/run-pass/vec-tail-matching.rs
@@ -11,26 +11,28 @@
 
 
 #![feature(slice_patterns)]
+#![feature(rustc_attrs)]
 
 struct Foo {
-    string: String
+    string: &'static str
 }
 
+#[rustc_mir]
 pub fn main() {
     let x = [
-        Foo { string: "foo".to_string() },
-        Foo { string: "bar".to_string() },
-        Foo { string: "baz".to_string() }
+        Foo { string: "foo" },
+        Foo { string: "bar" },
+        Foo { string: "baz" }
     ];
     match x {
-        [ref first, tail..] => {
-            assert_eq!(first.string, "foo".to_string());
+        [ref first, ref tail..] => {
+            assert_eq!(first.string, "foo");
             assert_eq!(tail.len(), 2);
-            assert_eq!(tail[0].string, "bar".to_string());
-            assert_eq!(tail[1].string, "baz".to_string());
+            assert_eq!(tail[0].string, "bar");
+            assert_eq!(tail[1].string, "baz");
 
-            match tail {
-                [Foo { .. }, _, Foo { .. }, _tail..] => {
+            match *(tail as &[_]) {
+                [Foo { .. }, _, Foo { .. }, ref _tail..] => {
                     unreachable!();
                 }
                 [Foo { string: ref a }, Foo { string: ref b }] => {
diff --git a/src/test/run-pass/zero_sized_subslice_match.rs b/src/test/run-pass/zero_sized_subslice_match.rs
index 697508ae488..00f4aa98a3e 100644
--- a/src/test/run-pass/zero_sized_subslice_match.rs
+++ b/src/test/run-pass/zero_sized_subslice_match.rs
@@ -8,15 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
+#![feature(rustc_attrs)]
 #![feature(slice_patterns)]
 
+#[rustc_mir]
 fn main() {
     let x = [(), ()];
 
     // The subslice used to go out of bounds for zero-sized array items, check that this doesn't
     // happen anymore
     match x {
-        [_, y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
+        [_, ref y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
     }
 }
diff --git a/src/test/rustdoc/deprecated-impls.rs b/src/test/rustdoc/deprecated-impls.rs
new file mode 100644
index 00000000000..bcf0645766b
--- /dev/null
+++ b/src/test/rustdoc/deprecated-impls.rs
@@ -0,0 +1,128 @@
+// 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.
+
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo0.html
+pub struct Foo0;
+
+impl Foo0 {
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.1: fn_with_doc'
+    // @has - 'fn_with_doc short'
+    // @has - 'fn_with_doc full'
+    /// fn_with_doc short
+    ///
+    /// fn_with_doc full
+    #[deprecated(since = "1.0.1", note = "fn_with_doc")]
+    pub fn fn_with_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.2: fn_without_doc'
+    #[deprecated(since = "1.0.2", note = "fn_without_doc")]
+    pub fn fn_without_doc() {}
+}
+
+pub trait Bar {
+    /// fn_empty_with_doc short
+    ///
+    /// fn_empty_with_doc full
+    #[deprecated(since = "1.0.3", note = "fn_empty_with_doc")]
+    fn fn_empty_with_doc();
+
+    #[deprecated(since = "1.0.4", note = "fn_empty_without_doc")]
+    fn fn_empty_without_doc();
+
+    /// fn_def_with_doc short
+    ///
+    /// fn_def_with_doc full
+    #[deprecated(since = "1.0.5", note = "fn_def_with_doc")]
+    fn fn_def_with_doc() {}
+
+    #[deprecated(since = "1.0.6", note = "fn_def_without_doc")]
+    fn fn_def_without_doc() {}
+
+    /// fn_def_def_with_doc short
+    ///
+    /// fn_def_def_with_doc full
+    #[deprecated(since = "1.0.7", note = "fn_def_def_with_doc")]
+    fn fn_def_def_with_doc() {}
+
+    #[deprecated(since = "1.0.8", note = "fn_def_def_without_doc")]
+    fn fn_def_def_without_doc() {}
+}
+
+// @has foo/struct.Foo1.html
+pub struct Foo1;
+
+impl Bar for Foo1 {
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.3: fn_empty_with_doc'
+    // @has - 'fn_empty_with_doc_impl short'
+    // @has - 'fn_empty_with_doc_impl full'
+    /// fn_empty_with_doc_impl short
+    ///
+    /// fn_empty_with_doc_impl full
+    fn fn_empty_with_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.4: fn_empty_without_doc'
+    fn fn_empty_without_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc'
+    // @has - 'fn_def_with_doc_impl short'
+    // @has - 'fn_def_with_doc_impl full'
+    /// fn_def_with_doc_impl short
+    ///
+    /// fn_def_with_doc_impl full
+    fn fn_def_with_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc'
+    fn fn_def_without_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.7: fn_def_def_with_doc'
+    // @has - 'fn_def_def_with_doc short'
+    // @!has - 'fn_def_def_with_doc full'
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.8: fn_def_def_without_doc'
+}
+
+// @has foo/struct.Foo2.html
+pub struct Foo2;
+
+impl Bar for Foo2 {
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.3: fn_empty_with_doc'
+    // @has - 'fn_empty_with_doc short'
+    // @!has - 'fn_empty_with_doc full'
+    fn fn_empty_with_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.4: fn_empty_without_doc'
+    // @has - 'fn_empty_without_doc_impl short'
+    // @has - 'fn_empty_without_doc_impl full'
+    /// fn_empty_without_doc_impl short
+    ///
+    /// fn_empty_without_doc_impl full
+    fn fn_empty_without_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc'
+    // @has - 'fn_def_with_doc short'
+    // @!has - 'fn_def_with full'
+    fn fn_def_with_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc'
+    // @has - 'fn_def_without_doc_impl short'
+    // @has - 'fn_def_without_doc_impl full'
+    /// fn_def_without_doc_impl short
+    ///
+    /// fn_def_without_doc_impl full
+    fn fn_def_without_doc() {}
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.7: fn_def_def_with_doc'
+    // @has - 'fn_def_def_with_doc short'
+    // @!has - 'fn_def_def_with_doc full'
+
+    // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.8: fn_def_def_without_doc'
+}
diff --git a/src/test/rustdoc/inline_cross/hidden-use.rs b/src/test/rustdoc/inline_cross/hidden-use.rs
new file mode 100644
index 00000000000..dd668c20362
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/hidden-use.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.
+
+// aux-build:rustdoc-hidden.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate rustdoc_hidden;
+
+// @has hidden_use/index.html
+// @!has - 'rustdoc_hidden'
+// @!has - 'Bar'
+// @!has hidden_use/struct.Bar.html
+#[doc(hidden)]
+pub use rustdoc_hidden::Bar;
diff --git a/src/test/rustdoc/inline_local/hidden-use.rs b/src/test/rustdoc/inline_local/hidden-use.rs
new file mode 100644
index 00000000000..1b1dafcf58b
--- /dev/null
+++ b/src/test/rustdoc/inline_local/hidden-use.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.
+
+mod private {
+    pub struct Foo {}
+}
+
+// @has hidden_use/index.html
+// @!has - 'private'
+// @!has - 'Foo'
+// @!has hidden_use/struct.Foo.html
+#[doc(hidden)]
+pub use private::Foo;
diff --git a/src/test/rustdoc/issue-34025.rs b/src/test/rustdoc/issue-34025.rs
new file mode 100644
index 00000000000..8c0a7703c91
--- /dev/null
+++ b/src/test/rustdoc/issue-34025.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.
+
+#![crate_name = "foo"]
+
+// @!has 'foo/sys/index.html'
+// @!has 'foo/sys/sidebar-items.js'
+#[doc(hidden)]
+pub mod sys {
+    extern "C" {
+        // @!has 'foo/sys/fn.foo.html'
+        #[doc(hidden)]
+        pub fn foo();
+    }
+}
diff --git a/src/test/rustdoc/redirect-const.rs b/src/test/rustdoc/redirect-const.rs
new file mode 100644
index 00000000000..c95e5537c88
--- /dev/null
+++ b/src/test/rustdoc/redirect-const.rs
@@ -0,0 +1,23 @@
+// 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"]
+
+pub use hidden::STATIC_FOO;
+pub use hidden::CONST_FOO;
+
+mod hidden {
+    // @has foo/hidden/static.STATIC_FOO.html
+    // @has - '//p/a' '../../foo/static.STATIC_FOO.html'
+    pub static STATIC_FOO: u64 = 0;
+    // @has foo/hidden/constant.CONST_FOO.html
+    // @has - '//p/a' '../../foo/constant.CONST_FOO.html'
+    pub const CONST_FOO: u64 = 0;
+}
diff --git a/src/test/rustdoc/redirect-rename.rs b/src/test/rustdoc/redirect-rename.rs
new file mode 100644
index 00000000000..b7c702dcc1f
--- /dev/null
+++ b/src/test/rustdoc/redirect-rename.rs
@@ -0,0 +1,32 @@
+// 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"]
+
+mod hidden {
+    // @has foo/hidden/struct.Foo.html
+    // @has - '//p/a' '../../foo/struct.FooBar.html'
+    pub struct Foo {}
+
+    // @has foo/hidden/bar/index.html
+    // @has - '//p/a' '../../foo/baz/index.html'
+    pub mod bar {
+        // @has foo/hidden/bar/struct.Thing.html
+        // @has - '//p/a' '../../foo/baz/struct.Thing.html'
+        pub struct Thing {}
+    }
+}
+
+// @has foo/struct.FooBar.html
+pub use hidden::Foo as FooBar;
+
+// @has foo/baz/index.html
+// @has foo/baz/struct.Thing.html
+pub use hidden::bar as baz;
diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs
index 9332a8e5f6c..8b7164819a7 100644
--- a/src/tools/cargotest/main.rs
+++ b/src/tools/cargotest/main.rs
@@ -21,20 +21,18 @@ struct Test {
     lock: Option<&'static str>,
 }
 
-const TEST_REPOS: &'static [Test] = &[
-    Test {
-        name: "cargo",
-        repo: "https://github.com/rust-lang/cargo",
-        sha: "7d79da08238e3d47e0bc4406155bdcc45ccb8c82",
-        lock: None,
-    },
-    Test {
-        name: "iron",
-        repo: "https://github.com/iron/iron",
-        sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
-        lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
-    },
-];
+const TEST_REPOS: &'static [Test] = &[Test {
+                                          name: "cargo",
+                                          repo: "https://github.com/rust-lang/cargo",
+                                          sha: "7d79da08238e3d47e0bc4406155bdcc45ccb8c82",
+                                          lock: None,
+                                      },
+                                      Test {
+                                          name: "iron",
+                                          repo: "https://github.com/iron/iron",
+                                          sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
+                                          lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
+                                      }];
 
 
 fn main() {
@@ -52,8 +50,10 @@ fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
     println!("testing {}", test.repo);
     let dir = clone_repo(test, out_dir);
     if let Some(lockfile) = test.lock {
-        File::create(&dir.join("Cargo.lock")).expect("")
-            .write_all(lockfile.as_bytes()).expect("");
+        File::create(&dir.join("Cargo.lock"))
+            .expect("")
+            .write_all(lockfile.as_bytes())
+            .expect("");
     }
     if !run_cargo_test(cargo, &dir) {
         panic!("tests failed for {}", test.repo);
@@ -65,10 +65,10 @@ fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
 
     if !out_dir.join(".git").is_dir() {
         let status = Command::new("git")
-            .arg("init")
-            .arg(&out_dir)
-            .status()
-            .expect("");
+                         .arg("init")
+                         .arg(&out_dir)
+                         .status()
+                         .expect("");
         assert!(status.success());
     }
 
@@ -77,23 +77,23 @@ fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
     for depth in &[0, 1, 10, 100, 1000, 100000] {
         if *depth > 0 {
             let status = Command::new("git")
-                .arg("fetch")
-                .arg(test.repo)
-                .arg("master")
-                .arg(&format!("--depth={}", depth))
-                .current_dir(&out_dir)
-                .status()
-                .expect("");
+                             .arg("fetch")
+                             .arg(test.repo)
+                             .arg("master")
+                             .arg(&format!("--depth={}", depth))
+                             .current_dir(&out_dir)
+                             .status()
+                             .expect("");
             assert!(status.success());
         }
 
         let status = Command::new("git")
-            .arg("reset")
-            .arg(test.sha)
-            .arg("--hard")
-            .current_dir(&out_dir)
-            .status()
-            .expect("");
+                         .arg("reset")
+                         .arg(test.sha)
+                         .arg("--hard")
+                         .current_dir(&out_dir)
+                         .status()
+                         .expect("");
 
         if status.success() {
             found = true;
@@ -105,11 +105,11 @@ fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
         panic!("unable to find commit {}", test.sha)
     }
     let status = Command::new("git")
-        .arg("clean")
-        .arg("-fdx")
-        .current_dir(&out_dir)
-        .status()
-        .unwrap();
+                     .arg("clean")
+                     .arg("-fdx")
+                     .current_dir(&out_dir)
+                     .status()
+                     .unwrap();
     assert!(status.success());
 
     out_dir
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index c02fc8a3f91..4b74833eaf7 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -75,30 +75,20 @@ struct FileEntry {
 type Cache = HashMap<PathBuf, FileEntry>;
 
 impl FileEntry {
-    fn parse_ids(&mut self,
-                file: &Path,
-                contents: &str,
-                errors: &mut bool)
-{
+    fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
         if self.ids.is_empty() {
             with_attrs_in_source(contents, " id", |fragment, i| {
                 let frag = fragment.trim_left_matches("#").to_owned();
                 if !self.ids.insert(frag) {
                     *errors = true;
-                    println!("{}:{}: id is not unique: `{}`",
-                             file.display(), i, fragment);
+                    println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
                 }
             });
         }
     }
 }
 
-fn walk(cache: &mut Cache,
-        root: &Path,
-        dir: &Path,
-        url: &mut Url,
-        errors: &mut bool)
-{
+fn walk(cache: &mut Cache, root: &Path, dir: &Path, url: &mut Url, errors: &mut bool) {
     for entry in t!(dir.read_dir()).map(|e| t!(e)) {
         let path = entry.path();
         let kind = t!(entry.file_type());
@@ -122,8 +112,8 @@ fn check(cache: &mut Cache,
          root: &Path,
          file: &Path,
          base: &Url,
-         errors: &mut bool) -> Option<PathBuf>
-{
+         errors: &mut bool)
+         -> Option<PathBuf> {
     // ignore js files as they are not prone to errors as the rest of the
     // documentation is and they otherwise bring up false positives.
     if file.extension().and_then(|s| s.to_str()) == Some("js") {
@@ -173,8 +163,9 @@ fn check(cache: &mut Cache,
         Err(_) => return None,
     };
     {
-        cache.get_mut(&pretty_file).unwrap()
-                                   .parse_ids(&pretty_file, &contents, errors);
+        cache.get_mut(&pretty_file)
+             .unwrap()
+             .parse_ids(&pretty_file, &contents, errors);
     }
 
     // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
@@ -195,8 +186,10 @@ fn check(cache: &mut Cache,
                 // the docs offline so it's best to avoid them.
                 *errors = true;
                 let pretty_path = path.strip_prefix(root).unwrap_or(&path);
-                println!("{}:{}: directory link - {}", pretty_file.display(),
-                         i + 1, pretty_path.display());
+                println!("{}:{}: directory link - {}",
+                         pretty_file.display(),
+                         i + 1,
+                         pretty_path.display());
                 return;
             }
             let res = load_file(cache, root, path.clone(), FromRedirect(false));
@@ -205,7 +198,9 @@ fn check(cache: &mut Cache,
                 Err(LoadError::IOError(err)) => panic!(format!("{}", err)),
                 Err(LoadError::BrokenRedirect(target, _)) => {
                     print!("{}:{}: broken redirect to {}",
-                           pretty_file.display(), i + 1, target.display());
+                           pretty_file.display(),
+                           i + 1,
+                           target.display());
                     return;
                 }
                 Err(LoadError::IsRedirect) => unreachable!(),
@@ -225,9 +220,9 @@ fn check(cache: &mut Cache,
                 if !entry.ids.contains(fragment) {
                     *errors = true;
                     print!("{}:{}: broken link fragment  ",
-                           pretty_file.display(), i + 1);
-                    println!("`#{}` pointing to `{}`",
-                             fragment, pretty_path.display());
+                           pretty_file.display(),
+                           i + 1);
+                    println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
                 };
             }
         } else {
@@ -243,7 +238,8 @@ fn check(cache: &mut Cache,
 fn load_file(cache: &mut Cache,
              root: &Path,
              file: PathBuf,
-             redirect: Redirect) -> Result<(PathBuf, String), LoadError> {
+             redirect: Redirect)
+             -> Result<(PathBuf, String), LoadError> {
     let mut contents = String::new();
     let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));
 
@@ -251,7 +247,7 @@ fn load_file(cache: &mut Cache,
         Entry::Occupied(entry) => {
             contents = entry.get().source.clone();
             None
-        },
+        }
         Entry::Vacant(entry) => {
             let mut fp = try!(File::open(file.clone()).map_err(|err| {
                 if let FromRedirect(true) = redirect {
@@ -275,7 +271,7 @@ fn load_file(cache: &mut Cache,
                 });
             }
             maybe
-        },
+        }
     };
     let base = Url::from_file_path(&file).unwrap();
     let mut parser = UrlParser::new();
@@ -286,7 +282,7 @@ fn load_file(cache: &mut Cache,
             let path = PathBuf::from(redirect_file);
             load_file(cache, root, path, FromRedirect(true))
         }
-        None => Ok((pretty_file, contents))
+        None => Ok((pretty_file, contents)),
     }
 }
 
@@ -307,25 +303,22 @@ fn maybe_redirect(source: &str) -> Option<String> {
 }
 
 fn url_to_file_path(parser: &UrlParser, url: &str) -> Option<(Url, PathBuf)> {
-    parser.parse(url).ok().and_then(|parsed_url| {
-        parsed_url.to_file_path().ok().map(|f| (parsed_url, f))
-    })
+    parser.parse(url)
+          .ok()
+          .and_then(|parsed_url| parsed_url.to_file_path().ok().map(|f| (parsed_url, f)))
 }
 
-fn with_attrs_in_source<F: FnMut(&str, usize)>(contents: &str,
-                                               attr: &str,
-                                               mut f: F)
-{
+fn with_attrs_in_source<F: FnMut(&str, usize)>(contents: &str, attr: &str, mut f: F) {
     for (i, mut line) in contents.lines().enumerate() {
         while let Some(j) = line.find(attr) {
-            let rest = &line[j + attr.len() ..];
+            let rest = &line[j + attr.len()..];
             line = rest;
             let pos_equals = match rest.find("=") {
                 Some(i) => i,
                 None => continue,
             };
             if rest[..pos_equals].trim_left_matches(" ") != "" {
-                continue
+                continue;
             }
 
             let rest = &rest[pos_equals + 1..];
@@ -337,7 +330,7 @@ fn with_attrs_in_source<F: FnMut(&str, usize)>(contents: &str,
             let quote_delim = rest.as_bytes()[pos_quote] as char;
 
             if rest[..pos_quote].trim_left_matches(" ") != "" {
-                continue
+                continue;
             }
             let rest = &rest[pos_quote + 1..];
             let url = match rest.find(quote_delim) {