about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--mk/crates.mk15
-rw-r--r--mk/rt.mk4
-rw-r--r--mk/tests.mk14
-rw-r--r--src/bootstrap/bootstrap.py3
-rw-r--r--src/bootstrap/build/compile.rs13
-rw-r--r--src/bootstrap/build/sanity.rs2
-rw-r--r--src/doc/book/iterators.md5
-rw-r--r--src/doc/book/ownership.md2
-rw-r--r--src/doc/book/references-and-borrowing.md2
-rw-r--r--src/doc/book/syntax-index.md24
-rw-r--r--src/doc/reference.md53
-rw-r--r--src/etc/platform-intrinsics/generator.py6
-rw-r--r--src/etc/platform-intrinsics/x86/fma.json47
-rwxr-xr-xsrc/etc/unicode.py4
-rw-r--r--src/liballoc/lib.rs5
-rw-r--r--src/liballoc_jemalloc/build.rs2
-rw-r--r--src/libcollections/btree/map.rs111
-rw-r--r--src/libcollections/fmt.rs10
-rw-r--r--src/libcollections/lib.rs2
-rw-r--r--src/libcollections/range.rs1
-rw-r--r--src/libcollections/str.rs2
-rw-r--r--src/libcollections/string.rs34
-rw-r--r--src/libcollections/vec.rs32
-rw-r--r--src/libcollectionstest/lib.rs3
-rw-r--r--src/libcollectionstest/str.rs22
-rw-r--r--src/libcollectionstest/vec_deque.rs4
-rw-r--r--src/libcore/clone.rs2
-rw-r--r--src/libcore/fmt/mod.rs2
-rw-r--r--src/libcore/iter.rs309
-rw-r--r--src/libcore/mem.rs2
-rw-r--r--src/libcore/ops.rs99
-rw-r--r--src/libcore/option.rs2
-rw-r--r--src/libcore/ptr.rs2
-rw-r--r--src/libcore/result.rs2
-rw-r--r--src/libcore/slice.rs57
-rw-r--r--src/libcore/str/mod.rs144
-rw-r--r--src/libgetopts/lib.rs13
m---------src/liblibc0
-rw-r--r--src/librand/lib.rs5
-rw-r--r--src/librustc/lint/builtin.rs9
-rw-r--r--src/librustc/lint/context.rs12
-rw-r--r--src/librustc/middle/cfg/construct.rs6
-rw-r--r--src/librustc/middle/check_match.rs9
-rw-r--r--src/librustc/middle/cstore.rs2
-rw-r--r--src/librustc/middle/effect.rs3
-rw-r--r--src/librustc/middle/expr_use_visitor.rs7
-rw-r--r--src/librustc/middle/infer/freshen.rs3
-rw-r--r--src/librustc/middle/infer/mod.rs14
-rw-r--r--src/librustc/middle/intrinsicck.rs6
-rw-r--r--src/librustc/middle/lang_items.rs39
-rw-r--r--src/librustc/middle/liveness.rs29
-rw-r--r--src/librustc/middle/mem_categorization.rs14
-rw-r--r--src/librustc/middle/subst.rs4
-rw-r--r--src/librustc/middle/traits/coherence.rs3
-rw-r--r--src/librustc/middle/traits/mod.rs2
-rw-r--r--src/librustc/middle/traits/project.rs2
-rw-r--r--src/librustc/middle/traits/select.rs19
-rw-r--r--src/librustc/middle/traits/structural_impls.rs3
-rw-r--r--src/librustc/middle/ty/adjustment.rs6
-rw-r--r--src/librustc/middle/ty/cast.rs2
-rw-r--r--src/librustc/middle/ty/contents.rs2
-rw-r--r--src/librustc/middle/ty/context.rs38
-rw-r--r--src/librustc/middle/ty/error.rs4
-rw-r--r--src/librustc/middle/ty/fast_reject.rs2
-rw-r--r--src/librustc/middle/ty/flags.rs7
-rw-r--r--src/librustc/middle/ty/mod.rs26
-rw-r--r--src/librustc/middle/ty/outlives.rs3
-rw-r--r--src/librustc/middle/ty/relate.rs24
-rw-r--r--src/librustc/middle/ty/structural_impls.rs16
-rw-r--r--src/librustc/middle/ty/sty.rs41
-rw-r--r--src/librustc/middle/ty/util.rs18
-rw-r--r--src/librustc/middle/ty/walk.rs6
-rw-r--r--src/librustc/middle/ty/wf.rs4
-rw-r--r--src/librustc/mir/repr.rs10
-rw-r--r--src/librustc/util/ppaux.rs31
-rw-r--r--src/librustc_back/svh.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_data_structures/bitvec.rs36
-rw-r--r--src/librustc_data_structures/fnv.rs8
-rw-r--r--src/librustc_data_structures/graph/mod.rs136
-rw-r--r--src/librustc_data_structures/graph/tests.rs40
-rw-r--r--src/librustc_data_structures/ivar.rs15
-rw-r--r--src/librustc_data_structures/lib.rs3
-rw-r--r--src/librustc_data_structures/obligation_forest/mod.rs152
-rw-r--r--src/librustc_data_structures/obligation_forest/node_index.rs7
-rw-r--r--src/librustc_data_structures/obligation_forest/test.rs105
-rw-r--r--src/librustc_data_structures/obligation_forest/tree_index.rs3
-rw-r--r--src/librustc_data_structures/snapshot_vec.rs50
-rw-r--r--src/librustc_data_structures/transitive_relation.rs118
-rw-r--r--src/librustc_data_structures/tuple_slice.rs14
-rw-r--r--src/librustc_data_structures/unify/mod.rs97
-rw-r--r--src/librustc_data_structures/unify/tests.rs35
-rw-r--r--src/librustc_data_structures/veccell/mod.rs4
-rw-r--r--src/librustc_driver/driver.rs32
-rw-r--r--src/librustc_driver/lib.rs23
-rw-r--r--src/librustc_driver/pretty.rs2
-rw-r--r--src/librustc_driver/test.rs21
-rw-r--r--src/librustc_front/fold.rs4
-rw-r--r--src/librustc_front/hir.rs3
-rw-r--r--src/librustc_front/intravisit.rs4
-rw-r--r--src/librustc_front/lowering.rs166
-rw-r--r--src/librustc_front/print/pprust.rs9
-rw-r--r--src/librustc_lint/builtin.rs4
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_lint/types.rs6
-rw-r--r--src/librustc_metadata/csearch.rs5
-rw-r--r--src/librustc_metadata/decoder.rs11
-rw-r--r--src/librustc_metadata/tydecode.rs5
-rw-r--r--src/librustc_metadata/tyencode.rs5
-rw-r--r--src/librustc_mir/build/expr/into.rs4
-rw-r--r--src/librustc_mir/build/misc.rs13
-rw-r--r--src/librustc_mir/build/scope.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs55
-rw-r--r--src/librustc_mir/hair/mod.rs10
-rw-r--r--src/librustc_mir/mir_map.rs6
-rw-r--r--src/librustc_mir/transform/type_check.rs2
-rw-r--r--src/librustc_passes/consts.rs5
-rw-r--r--src/librustc_platform_intrinsics/x86.rs120
-rw-r--r--src/librustc_privacy/lib.rs13
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs14
-rw-r--r--src/librustc_resolve/lib.rs7
-rw-r--r--src/librustc_trans/trans/adt.rs4
-rw-r--r--src/librustc_trans/trans/asm.rs3
-rw-r--r--src/librustc_trans/trans/attributes.rs4
-rw-r--r--src/librustc_trans/trans/base.rs66
-rw-r--r--src/librustc_trans/trans/callee.rs696
-rw-r--r--src/librustc_trans/trans/closure.rs85
-rw-r--r--src/librustc_trans/trans/collector.rs67
-rw-r--r--src/librustc_trans/trans/common.rs10
-rw-r--r--src/librustc_trans/trans/consts.rs37
-rw-r--r--src/librustc_trans/trans/debuginfo/create_scope_map.rs5
-rw-r--r--src/librustc_trans/trans/debuginfo/metadata.rs5
-rw-r--r--src/librustc_trans/trans/debuginfo/mod.rs2
-rw-r--r--src/librustc_trans/trans/debuginfo/type_names.rs3
-rw-r--r--src/librustc_trans/trans/declare.rs3
-rw-r--r--src/librustc_trans/trans/expr.rs366
-rw-r--r--src/librustc_trans/trans/foreign.rs14
-rw-r--r--src/librustc_trans/trans/glue.rs33
-rw-r--r--src/librustc_trans/trans/intrinsic.rs86
-rw-r--r--src/librustc_trans/trans/meth.rs366
-rw-r--r--src/librustc_trans/trans/mir/block.rs145
-rw-r--r--src/librustc_trans/trans/mir/constant.rs38
-rw-r--r--src/librustc_trans/trans/mir/did.rs171
-rw-r--r--src/librustc_trans/trans/mir/mod.rs1
-rw-r--r--src/librustc_trans/trans/mir/rvalue.rs16
-rw-r--r--src/librustc_trans/trans/monomorphize.rs11
-rw-r--r--src/librustc_trans/trans/type_of.rs34
-rw-r--r--src/librustc_typeck/astconv.rs3
-rw-r--r--src/librustc_typeck/check/_match.rs100
-rw-r--r--src/librustc_typeck/check/callee.rs7
-rw-r--r--src/librustc_typeck/check/cast.rs27
-rw-r--r--src/librustc_typeck/check/coercion.rs380
-rw-r--r--src/librustc_typeck/check/compare_method.rs12
-rw-r--r--src/librustc_typeck/check/demand.rs50
-rw-r--r--src/librustc_typeck/check/dropck.rs2
-rw-r--r--src/librustc_typeck/check/intrinsic.rs16
-rw-r--r--src/librustc_typeck/check/method/confirm.rs178
-rw-r--r--src/librustc_typeck/check/method/mod.rs7
-rw-r--r--src/librustc_typeck/check/method/probe.rs8
-rw-r--r--src/librustc_typeck/check/method/suggest.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs438
-rw-r--r--src/librustc_typeck/check/regionck.rs2
-rw-r--r--src/librustc_typeck/check/upvar.rs24
-rw-r--r--src/librustc_typeck/check/wfcheck.rs4
-rw-r--r--src/librustc_typeck/coherence/mod.rs12
-rw-r--r--src/librustc_typeck/collect.rs69
-rw-r--r--src/librustc_typeck/constrained_type_params.rs3
-rw-r--r--src/librustc_typeck/diagnostics.rs31
-rw-r--r--src/librustc_typeck/lib.rs20
-rw-r--r--src/librustc_typeck/variance/constraints.rs3
-rw-r--r--src/librustc_unicode/lib.rs5
-rw-r--r--src/librustc_unicode/tables.rs9
-rw-r--r--src/librustdoc/clean/inline.rs47
-rw-r--r--src/librustdoc/clean/mod.rs223
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/fold.rs39
-rw-r--r--src/librustdoc/html/render.rs430
-rw-r--r--src/librustdoc/lib.rs98
-rw-r--r--src/librustdoc/passes.rs69
-rw-r--r--src/librustdoc/test.rs23
-rw-r--r--src/librustdoc/visit_ast.rs6
-rw-r--r--src/libstd/ascii.rs14
-rw-r--r--src/libstd/build.rs2
-rw-r--r--src/libstd/fs.rs8
-rw-r--r--src/libstd/io/stdio.rs12
-rw-r--r--src/libstd/lib.rs3
-rw-r--r--src/libstd/macros.rs12
-rw-r--r--src/libstd/net/ip.rs37
-rw-r--r--src/libstd/net/tcp.rs5
-rw-r--r--src/libstd/os/emscripten/fs.rs128
-rw-r--r--src/libstd/os/emscripten/mod.rs16
-rw-r--r--src/libstd/os/emscripten/raw.rs80
-rw-r--r--src/libstd/os/mod.rs8
-rw-r--r--src/libstd/prelude/mod.rs2
-rw-r--r--src/libstd/primitive_docs.rs2
-rw-r--r--src/libstd/process.rs49
-rw-r--r--src/libstd/sync/mod.rs2
-rw-r--r--src/libstd/sys/common/libunwind.rs10
-rw-r--r--src/libstd/sys/common/net.rs4
-rw-r--r--src/libstd/sys/unix/fd.rs38
-rw-r--r--src/libstd/sys/unix/fs.rs14
-rw-r--r--src/libstd/sys/unix/net.rs4
-rw-r--r--src/libstd/sys/unix/pipe.rs59
-rw-r--r--src/libstd/sys/unix/process.rs15
-rw-r--r--src/libstd/sys/unix/stdio.rs9
-rw-r--r--src/libstd/sys/windows/c.rs38
-rw-r--r--src/libstd/sys/windows/fs.rs5
-rw-r--r--src/libstd/sys/windows/handle.rs89
-rw-r--r--src/libstd/sys/windows/net.rs23
-rw-r--r--src/libstd/sys/windows/pipe.rs275
-rw-r--r--src/libstd/sys/windows/process.rs6
-rw-r--r--src/libstd/sys/windows/stdio.rs19
-rw-r--r--src/libstd/thread/mod.rs2
-rw-r--r--src/libsyntax/ast.rs18
-rw-r--r--src/libsyntax/ext/expand.rs6
-rw-r--r--src/libsyntax/ext/quote.rs42
-rw-r--r--src/libsyntax/feature_gate.rs22
-rw-r--r--src/libsyntax/fold.rs8
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libsyntax/parse/lexer/comments.rs4
-rw-r--r--src/libsyntax/parse/lexer/mod.rs20
-rw-r--r--src/libsyntax/parse/mod.rs134
-rw-r--r--src/libsyntax/parse/parser.rs136
-rw-r--r--src/libsyntax/parse/token.rs2
-rw-r--r--src/libsyntax/print/pprust.rs12
-rw-r--r--src/libsyntax/util/parser.rs14
-rw-r--r--src/libsyntax/util/parser_testing.rs108
-rw-r--r--src/libsyntax/visit.rs5
-rw-r--r--src/libtest/Cargo.toml1
-rw-r--r--src/libtest/lib.rs5
-rw-r--r--src/test/auxiliary/empty.rs9
-rw-r--r--src/test/auxiliary/issue13507.rs72
-rw-r--r--src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs (renamed from src/test/compile-fail/derive-no-std-not-supported.rs)0
-rw-r--r--src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs (renamed from src/test/compile-fail/dropck_tarena_cycle_checked.rs)0
-rw-r--r--src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs (renamed from src/test/compile-fail/dropck_tarena_unsound_drop.rs)0
-rw-r--r--src/test/compile-fail/duplicate_entry_error.rs5
-rw-r--r--src/test/compile-fail/feature-gate-try-operator.rs20
-rw-r--r--src/test/compile-fail/fn-item-type.rs38
-rw-r--r--src/test/compile-fail/invalid-intrinsic.rs16
-rw-r--r--src/test/compile-fail/issue-13482-2.rs2
-rw-r--r--src/test/compile-fail/issue-17728.rs4
-rw-r--r--src/test/compile-fail/issue-2149.rs2
-rw-r--r--src/test/compile-fail/issue-30730.rs (renamed from src/test/parse-fail/struct-variant-no-pub.rs)12
-rw-r--r--src/test/compile-fail/issue-31561.rs20
-rw-r--r--src/test/compile-fail/liveness-unused.rs46
-rw-r--r--src/test/compile-fail/range-1.rs2
-rw-r--r--src/test/compile-fail/range-2.rs10
-rw-r--r--src/test/compile-fail/range_inclusive_gate.rs25
-rw-r--r--src/test/compile-fail/trait-privacy.rs7
-rw-r--r--src/test/compile-fail/transmute-from-fn-item-types-lint.rs51
-rw-r--r--src/test/compile-fail/useless-pub.rs7
-rw-r--r--src/test/compile-fail/variadic-ffi-3.rs2
-rw-r--r--src/test/parse-fail/issue-19096.rs2
-rw-r--r--src/test/parse-fail/issue-3036.rs2
-rw-r--r--src/test/parse-fail/macros-no-semicolon.rs2
-rw-r--r--src/test/parse-fail/match-refactor-to-expr.rs2
-rw-r--r--src/test/parse-fail/range-3.rs2
-rw-r--r--src/test/parse-fail/range-4.rs2
-rw-r--r--src/test/parse-fail/range_inclusive.rs18
-rw-r--r--src/test/parse-fail/range_inclusive_gate.rs74
-rw-r--r--src/test/parse-fail/raw-str-unbalanced.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-mut-vec-expr.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-uniq-mut-expr.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-with-1.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-for.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-if.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-match-discriminant.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-while.rs2
-rw-r--r--src/test/pretty/issue-4264.pp6
-rw-r--r--src/test/run-make/execution-engine/test.rs4
-rw-r--r--src/test/run-pass-fulldeps/conditional-debug-macro-off.rs (renamed from src/test/run-pass/conditional-debug-macro-off.rs)0
-rw-r--r--src/test/run-pass-fulldeps/deprecated-derive.rs (renamed from src/test/run-pass/deprecated-derive.rs)0
-rw-r--r--src/test/run-pass-fulldeps/derive-no-std.rs (renamed from src/test/run-pass/derive-no-std.rs)0
-rw-r--r--src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs (renamed from src/test/run-pass/deriving-encodable-decodable-box.rs)0
-rw-r--r--src/test/run-pass-fulldeps/deriving-encodable-decodable-cell-refcell.rs (renamed from src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs)0
-rw-r--r--src/test/run-pass-fulldeps/deriving-global.rs (renamed from src/test/run-pass/deriving-global.rs)0
-rw-r--r--src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs (renamed from src/test/run-pass/dropck_tarena_sound_drop.rs)0
-rw-r--r--src/test/run-pass-fulldeps/empty-struct-braces-derive.rs (renamed from src/test/run-pass/empty-struct-braces-derive.rs)0
-rw-r--r--src/test/run-pass-fulldeps/extern-mod-syntax.rs (renamed from src/test/run-pass/extern-mod-syntax.rs)0
-rw-r--r--src/test/run-pass-fulldeps/issue-11881.rs (renamed from src/test/run-pass/issue-11881.rs)0
-rw-r--r--src/test/run-pass-fulldeps/issue-14021.rs (renamed from src/test/run-pass/issue-14021.rs)0
-rw-r--r--src/test/run-pass-fulldeps/issue-15924.rs (renamed from src/test/run-pass/issue-15924.rs)0
-rw-r--r--src/test/run-pass-fulldeps/issue-24972.rs (renamed from src/test/run-pass/issue-24972.rs)0
-rw-r--r--src/test/run-pass-fulldeps/issue-2804.rs (renamed from src/test/run-pass/issue-2804.rs)0
-rw-r--r--src/test/run-pass-fulldeps/issue-4016.rs (renamed from src/test/run-pass/issue-4016.rs)0
-rw-r--r--src/test/run-pass-fulldeps/issue-4036.rs (renamed from src/test/run-pass/issue-4036.rs)0
-rw-r--r--src/test/run-pass-fulldeps/logging-enabled-debug.rs (renamed from src/test/run-pass/logging-enabled-debug.rs)0
-rw-r--r--src/test/run-pass-fulldeps/logging-enabled.rs (renamed from src/test/run-pass/logging-enabled.rs)0
-rw-r--r--src/test/run-pass-fulldeps/logging-right-crate.rs (renamed from src/test/run-pass/logging-right-crate.rs)0
-rw-r--r--src/test/run-pass-fulldeps/logging-separate-lines.rs (renamed from src/test/run-pass/logging-separate-lines.rs)0
-rw-r--r--src/test/run-pass-fulldeps/placement-new-arena.rs (renamed from src/test/run-pass/placement-new-arena.rs)0
-rw-r--r--src/test/run-pass-fulldeps/regions-mock-tcx.rs (renamed from src/test/run-pass/regions-mock-tcx.rs)0
-rw-r--r--src/test/run-pass-fulldeps/rust-log-filter.rs (renamed from src/test/run-pass/rust-log-filter.rs)0
-rw-r--r--src/test/run-pass/augmented-assignments.rs18
-rw-r--r--src/test/run-pass/coerce-unify.rs77
-rw-r--r--src/test/run-pass/empty-type-parameter-list.rs33
-rw-r--r--src/test/run-pass/enum-clike-ffi-as-int.rs13
-rw-r--r--src/test/run-pass/fn-item-type-zero-sized.rs22
-rw-r--r--src/test/run-pass/issue-13507-2.rs34
-rw-r--r--src/test/run-pass/mir_refs_correct.rs81
-rw-r--r--src/test/run-pass/nullable-pointer-ffi-compat.rs5
-rw-r--r--src/test/run-pass/nullable-pointer-iotareduction.rs11
-rw-r--r--src/test/run-pass/parser-unicode-whitespace.rs22
-rw-r--r--src/test/run-pass/range.rs3
-rw-r--r--src/test/run-pass/range_inclusive.rs129
-rw-r--r--src/test/run-pass/range_inclusive_gate.rs23
-rw-r--r--src/test/run-pass/transmute-from-fn-item-types.rs27
-rw-r--r--src/test/run-pass/try-operator-hygiene.rs34
-rw-r--r--src/test/run-pass/try-operator.rs200
-rw-r--r--src/test/rustdoc/issue-15347.rs2
-rw-r--r--src/test/rustdoc/issue-27104.rs20
312 files changed, 6130 insertions, 4125 deletions
diff --git a/README.md b/README.md
index a83f51e1571..4ea6e28546a 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,7 @@ build.
 
 Download [MinGW from
 here](http://mingw-w64.org/doku.php/download/mingw-builds), and choose the
-`threads=win32,exceptions=dwarf/seh` flavor when installing. After installing,
+`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.
 
diff --git a/mk/crates.mk b/mk/crates.mk
index b7bb7c1083d..1ecceb9280a 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -49,16 +49,17 @@
 # automatically generated for all stage/host/target combinations.
 ################################################################################
 
-TARGET_CRATES := libc std flate arena term \
-                 serialize getopts collections test rand \
-                 log graphviz core rbml alloc \
+TARGET_CRATES := libc std term \
+                 getopts collections test rand \
+                 core alloc \
                  rustc_unicode rustc_bitflags \
 		 alloc_system alloc_jemalloc
 RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
                 rustc_data_structures rustc_front rustc_platform_intrinsics \
                 rustc_plugin rustc_metadata rustc_passes
-HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros
+HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \
+		flate arena graphviz rbml log serialize
 TOOLS := compiletest rustdoc rustc rustbook error_index_generator
 
 DEPS_core :=
@@ -84,10 +85,10 @@ DEPS_log := std
 DEPS_num := std
 DEPS_rbml := std log serialize
 DEPS_serialize := std log
-DEPS_term := std log
-DEPS_test := std getopts serialize rbml term native:rust_test_helpers
+DEPS_term := std
+DEPS_test := std getopts term native:rust_test_helpers
 
-DEPS_syntax := std term serialize log arena libc rustc_bitflags
+DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
 DEPS_syntax_ext := syntax fmt_macros
 
 DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
diff --git a/mk/rt.mk b/mk/rt.mk
index bd17490955d..5f46b3a20c9 100644
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -253,7 +253,7 @@ COMPRT_AR_$(1) := $$(AR_$(1))
 # We chomp -Werror here because GCC warns about the type signature of
 # builtins not matching its own and the build fails. It's a bit hacky,
 # but what can we do, we're building libclang-rt using GCC ......
-COMPRT_CFLAGS_$(1) := $$(filter-out -Werror -Werror=*,$$(CFG_GCCISH_CFLAGS_$(1))) -std=c99
+COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error -std=c99
 
 # FreeBSD Clang's packaging is problematic; it doesn't copy unwind.h to
 # the standard include directory. This should really be in our changes to
@@ -361,7 +361,7 @@ $$(BACKTRACE_BUILD_DIR_$(1))/Makefile: $$(BACKTRACE_DEPS) $$(MKFILE_DEPS)
 	      CC="$$(CC_$(1))" \
 	      AR="$$(AR_$(1))" \
 	      RANLIB="$$(AR_$(1)) s" \
-	      CFLAGS="$$(CFG_GCCISH_CFLAGS_$(1):-Werror=) -fno-stack-protector" \
+	      CFLAGS="$$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error -fno-stack-protector" \
 	      $(S)src/libbacktrace/configure --build=$(CFG_GNU_TRIPLE_$(CFG_BUILD)) --host=$(CFG_GNU_TRIPLE_$(1)))
 	$$(Q)echo '#undef HAVE_ATOMIC_FUNCTIONS' >> \
 	      $$(BACKTRACE_BUILD_DIR_$(1))/config.h
diff --git a/mk/tests.mk b/mk/tests.mk
index ea88a7d34f5..7f5dbeff1e4 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -299,9 +299,6 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
 	check-stage$(1)-T-$(2)-H-$(3)-cfail-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-pfail-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-rpass-valgrind-exec \
-	check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
-	check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \
-	check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-crates-exec \
@@ -317,6 +314,15 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
 # able to build a compiler (when the target triple is in the set of host triples)
 ifneq ($$(findstring $(2),$$(CFG_HOST)),)
 
+check-stage$(1)-T-$(2)-H-$(3)-exec: \
+	check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
+	check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \
+	check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec
+
+check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
+	check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \
+	check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec
+
 check-stage$(1)-T-$(2)-H-$(3)-crates-exec: \
 	$$(foreach crate,$$(TEST_CRATES), \
            check-stage$(1)-T-$(2)-H-$(3)-$$(crate)-exec)
@@ -340,9 +346,7 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-exec: \
 check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
 	check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-exec \
     check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-valgrind-exec \
-	check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-exec \
-	check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec \
 	check-stage$(1)-T-$(2)-H-$(3)-pretty-pretty-exec
 
 endef
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 6659894a171..5de7e6957c6 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -73,7 +73,8 @@ class RustBuild:
 
         if self.rustc().startswith(self.bin_root()) and \
            (not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
-            shutil.rmtree(self.bin_root())
+            if os.path.exists(self.bin_root()):
+                shutil.rmtree(self.bin_root())
             filename = "rust-std-nightly-" + self.build + ".tar.gz"
             url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date()
             tarball = os.path.join(rustc_cache, filename)
diff --git a/src/bootstrap/build/compile.rs b/src/bootstrap/build/compile.rs
index 3be4199352c..fb0a840bfa2 100644
--- a/src/bootstrap/build/compile.rs
+++ b/src/bootstrap/build/compile.rs
@@ -83,6 +83,19 @@ pub fn std_link(build: &Build,
                          libdir.join(staticlib("compiler-rt", target))));
     }
     add_to_sysroot(&out_dir, &libdir);
+
+    if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
+        copy_third_party_objects(build, target, &libdir);
+    }
+}
+
+/// Copies the crt(1,i,n).o startup objects
+///
+/// Only required for musl targets that statically link to libc
+fn copy_third_party_objects(build: &Build, target: &str, into: &Path) {
+    for &obj in &["crt1.o", "crti.o", "crtn.o"] {
+        t!(fs::copy(compiler_file(build.cc(target), obj), into.join(obj)));
+    }
 }
 
 /// Build and prepare startup objects like rsbegin.o and rsend.o
diff --git a/src/bootstrap/build/sanity.rs b/src/bootstrap/build/sanity.rs
index 6ac581a7c69..be4416c697c 100644
--- a/src/bootstrap/build/sanity.rs
+++ b/src/bootstrap/build/sanity.rs
@@ -79,7 +79,7 @@ pub fn check(build: &mut Build) {
         }
 
         // Make sure musl-root is valid if specified
-        if target.contains("musl") && target.contains("x86_64") {
+        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
             match build.config.musl_root {
                 Some(ref root) => {
                     if fs::metadata(root.join("lib/libc.a")).is_err() {
diff --git a/src/doc/book/iterators.md b/src/doc/book/iterators.md
index 0c4f8041266..c174d2d6bac 100644
--- a/src/doc/book/iterators.md
+++ b/src/doc/book/iterators.md
@@ -14,6 +14,11 @@ Now that you know more Rust, we can talk in detail about how this works.
 Ranges (the `0..10`) are 'iterators'. An iterator is something that we can
 call the `.next()` method on repeatedly, and it gives us a sequence of things.
 
+(By the way, a range with two dots like `0..10` is inclusive on the left (so it
+starts at 0) and exclusive on the right (so it ends at 9). A mathematician
+would write "[0, 10)". To get a range that goes all the way up to 10 you can
+write `0...10`.)
+
 Like this:
 
 ```rust
diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md
index 70d71c14ddf..7f7f7d4c8eb 100644
--- a/src/doc/book/ownership.md
+++ b/src/doc/book/ownership.md
@@ -51,7 +51,7 @@ fn foo() {
 }
 ```
 
-When `v` comes into scope, a new [vector] is created on [the stack][stack],
+When `v` comes into scope, a new [vector][vectors] is created on [the stack][stack],
 and it allocates space on [the heap][heap] for its elements. When `v` goes out
 of scope at the end of `foo()`, Rust will clean up everything related to the
 vector, even the heap-allocated memory. This happens deterministically, at the
diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md
index 0a4e09ed00a..7be5cc442dd 100644
--- a/src/doc/book/references-and-borrowing.md
+++ b/src/doc/book/references-and-borrowing.md
@@ -23,7 +23,7 @@ Before we get to the details, two important notes about the ownership system.
 Rust has a focus on safety and speed. It accomplishes these goals through many
 ‘zero-cost abstractions’, which means that in Rust, abstractions cost as little
 as possible in order to make them work. The ownership system is a prime example
-of a zero cost abstraction. All of the analysis we’ll talk about in this guide
+of a zero-cost abstraction. All of the analysis we’ll talk about in this guide
 is _done at compile time_. You do not pay any run-time cost for any of these
 features.
 
diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md
index 6782bdb4985..3e889f51f54 100644
--- a/src/doc/book/syntax-index.md
+++ b/src/doc/book/syntax-index.md
@@ -43,39 +43,40 @@
 * `!` (`!expr`): bitwise or logical complement.  Overloadable (`Not`).
 * `!=` (`var != expr`): nonequality comparison.  Overloadable (`PartialEq`).
 * `%` (`expr % expr`): arithmetic remainder.  Overloadable (`Rem`).
-* `%=` (`var %= expr`): arithmetic remainder & assignment.
+* `%=` (`var %= expr`): arithmetic remainder & assignment. Overloadable (`RemAssign`).
 * `&` (`expr & expr`): bitwise and.  Overloadable (`BitAnd`).
 * `&` (`&expr`): borrow.  See [References and Borrowing].
 * `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type.  See [References and Borrowing].
-* `&=` (`var &= expr`): bitwise and & assignment.
+* `&=` (`var &= expr`): bitwise and & assignment. Overloadable (`BitAndAssign`).
 * `&&` (`expr && expr`): logical and.
 * `*` (`expr * expr`): arithmetic multiplication.  Overloadable (`Mul`).
 * `*` (`*expr`): dereference.
 * `*` (`*const type`, `*mut type`): raw pointer.  See [Raw Pointers].
-* `*=` (`var *= expr`): arithmetic multiplication & assignment.
+* `*=` (`var *= expr`): arithmetic multiplication & assignment. Overloadable (`MulAssign`).
 * `+` (`expr + expr`): arithmetic addition.  Overloadable (`Add`).
 * `+` (`trait + trait`, `'a + trait`): compound type constraint.  See [Traits (Multiple Trait Bounds)].
-* `+=` (`var += expr`): arithmetic addition & assignment.
+* `+=` (`var += expr`): arithmetic addition & assignment. Overloadable (`AddAssign`).
 * `,`: argument and element separator.  See [Attributes], [Functions], [Structs], [Generics], [Match], [Closures], [Crates and Modules (Importing Modules with `use`)].
 * `-` (`expr - expr`): arithmetic subtraction.  Overloadable (`Sub`).
 * `-` (`- expr`): arithmetic negation.  Overloadable (`Neg`).
-* `-=` (`var -= expr`): arithmetic subtraction & assignment.
+* `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`).
 * `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type.  See [Functions], [Closures].
 * `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions].
 * `.` (`expr.ident`): member access.  See [Structs], [Method Syntax].
 * `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
 * `..` (`..expr`): struct literal update syntax.  See [Structs (Update syntax)].
 * `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding.  See [Patterns (Ignoring bindings)].
-* `...` (`expr ... expr`): inclusive range pattern.  See [Patterns (Ranges)].
+* `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. See [Iterators].
+* `...` (`expr...expr`) *in a pattern*: inclusive range pattern.  See [Patterns (Ranges)].
 * `/` (`expr / expr`): arithmetic division.  Overloadable (`Div`).
-* `/=` (`var /= expr`): arithmetic division & assignment.
+* `/=` (`var /= expr`): arithmetic division & assignment. Overloadable (`DivAssign`).
 * `:` (`pat: type`, `ident: type`): constraints.  See [Variable Bindings], [Functions], [Structs], [Traits].
 * `:` (`ident: expr`): struct field initializer.  See [Structs].
 * `:` (`'a: loop {…}`): loop label.  See [Loops (Loops Labels)].
 * `;`: statement and item terminator.
 * `;` (`[…; len]`): part of fixed-size array syntax.  See [Primitive Types (Arrays)].
 * `<<` (`expr << expr`): left-shift.  Overloadable (`Shl`).
-* `<<=` (`var <<= expr`): left-shift & assignment.
+* `<<=` (`var <<= expr`): left-shift & assignment. Overloadable (`ShlAssign`).
 * `<` (`expr < expr`): less-than comparison.  Overloadable (`PartialOrd`).
 * `<=` (`var <= expr`): less-than or equal-to comparison.  Overloadable (`PartialOrd`).
 * `=` (`var = expr`, `ident = type`): assignment/equivalence.  See [Variable Bindings], [`type` Aliases], generic parameter defaults.
@@ -84,14 +85,14 @@
 * `>` (`expr > expr`): greater-than comparison.  Overloadable (`PartialOrd`).
 * `>=` (`var >= expr`): greater-than or equal-to comparison.  Overloadable (`PartialOrd`).
 * `>>` (`expr >> expr`): right-shift.  Overloadable (`Shr`).
-* `>>=` (`var >>= expr`): right-shift & assignment.
+* `>>=` (`var >>= expr`): right-shift & assignment. Overloadable (`ShrAssign`).
 * `@` (`ident @ pat`): pattern binding.  See [Patterns (Bindings)].
 * `^` (`expr ^ expr`): bitwise exclusive or.  Overloadable (`BitXor`).
-* `^=` (`var ^= expr`): bitwise exclusive or & assignment.
+* `^=` (`var ^= expr`): bitwise exclusive or & assignment. Overloadable (`BitXorAssign`).
 * `|` (`expr | expr`): bitwise or.  Overloadable (`BitOr`).
 * `|` (`pat | pat`): pattern alternatives.  See [Patterns (Multiple patterns)].
 * `|` (`|…| expr`): closures.  See [Closures].
-* `|=` (`var |= expr`): bitwise or & assignment.
+* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`).
 * `||` (`expr || expr`): logical or.
 * `_`: "ignored" pattern binding.  See [Patterns (Ignoring bindings)].
 
@@ -205,6 +206,7 @@
 [Functions (Early Returns)]: functions.html#early-returns
 [Functions]: functions.html
 [Generics]: generics.html
+[Iterators]: iterators.html
 [Lifetimes]: lifetimes.html
 [Loops (`for`)]: loops.html#for
 [Loops (`loop`)]: loops.html#loop
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 6fb8de78094..8e655ee22e3 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -379,6 +379,10 @@ Examples of integer literals of various forms:
 0usize;                            // type usize
 ```
 
+Note that the Rust syntax considers `-1i8` as an application of the [unary minus
+operator](#unary-operator-expressions) to an integer literal `1i8`, rather than
+a single integer literal.
+
 ##### Floating-point literals
 
 A _floating-point literal_ has one of two forms:
@@ -1114,6 +1118,16 @@ type Point = (u8, u8);
 let p: Point = (41, 68);
 ```
 
+Currently a type alias to an enum type cannot be used to qualify the
+constructors:
+
+```
+enum E { A }
+type F = E;
+let _: F = E::A;  // OK
+// let _: F = F::A;  // Doesn't work
+```
+
 ### Structs
 
 A _struct_ is a nominal [struct type](#struct-types) defined with the
@@ -1191,7 +1205,8 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
 In this example, `Cat` is a _struct-like enum variant_,
 whereas `Dog` is simply called an enum variant.
 
-Enums have a discriminant. You can assign them explicitly:
+Each enum value has a _discriminant_ which is an integer associated to it. You
+can specify it explicitly:
 
 ```
 enum Foo {
@@ -1199,10 +1214,15 @@ enum Foo {
 }
 ```
 
-If a discriminant isn't assigned, they start at zero, and add one for each
+The right hand side of the specification is interpreted as an `isize` value,
+but the compiler is allowed to use a smaller type in the actual memory layout.
+The [`repr` attribute](#ffi-attributes) can be added in order to change
+the type of the right hand side and specify the memory layout.
+
+If a discriminant isn't specified, they start at zero, and add one for each
 variant, in order.
 
-You can cast an enum to get this value:
+You can cast an enum to get its discriminant:
 
 ```
 # enum Foo { Bar = 123 }
@@ -2277,6 +2297,10 @@ The currently implemented features of the reference compiler are:
                     `#[derive_Foo] #[derive_Bar]`, which can be user-defined syntax
                     extensions.
 
+* `inclusive_range_syntax` - Allows use of the `a...b` and `...b` syntax for inclusive ranges.
+
+* `inclusive_range` - Allows use of the types that represent desugared inclusive ranges.
+
 * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
                  are inherently unstable and no promise about them is made.
 
@@ -2747,13 +2771,34 @@ let y = 0..10;
 assert_eq!(x, y);
 ```
 
+Similarly, the `...` operator will construct an object of one of the
+`std::ops::RangeInclusive` variants.
+
+```
+# #![feature(inclusive_range_syntax)]
+1...2;   // std::ops::RangeInclusive
+...4;    // std::ops::RangeToInclusive
+```
+
+The following expressions are equivalent.
+
+```
+# #![feature(inclusive_range_syntax, inclusive_range)]
+let x = std::ops::RangeInclusive::NonEmpty {start: 0, end: 10};
+let y = 0...10;
+
+assert_eq!(x, y);
+```
+
 ### Unary operator expressions
 
 Rust defines the following unary operators. They are all written as prefix operators,
 before the expression they apply to.
 
 * `-`
-  : Negation. May only be applied to numeric types.
+  : Negation. Signed integer types and floating-point types support negation. It
+    is an error to apply negation to unsigned types; for example, the compiler
+    rejects `-1u32`.
 * `*`
   : Dereference. When applied to a [pointer](#pointer-types) it denotes the
     pointed-to location. For pointers to mutable locations, the resulting
diff --git a/src/etc/platform-intrinsics/generator.py b/src/etc/platform-intrinsics/generator.py
index e3aa4e688d3..0e0d4841063 100644
--- a/src/etc/platform-intrinsics/generator.py
+++ b/src/etc/platform-intrinsics/generator.py
@@ -691,7 +691,7 @@ def parse_args():
     parser.add_argument('-o', '--out', type=argparse.FileType('w'), default=sys.stdout,
                         help = 'File to output to (default stdout).')
     parser.add_argument('-i', '--info', type=argparse.FileType('r'),
-                        help = 'File containing platform specific information to merge into'
+                        help = 'File containing platform specific information to merge into '
                                 'the input files\' header.')
     parser.add_argument('in_', metavar="FILE", type=argparse.FileType('r'), nargs='+',
                         help = 'JSON files to load')
@@ -735,12 +735,12 @@ class CompilerDefs(object):
 
 use {{Intrinsic, i, i_, u, u_, f, v, v_, agg, p, void}};
 use IntrinsicDef::Named;
-use rustc::middle::ty;
+use rustc::middle::ty::TyCtxt;
 
 // The default inlining settings trigger a pathological behaviour in
 // LLVM, which causes makes compilation very slow. See #28273.
 #[inline(never)]
-pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {{
+pub fn find<'tcx>(_tcx: &TyCtxt<'tcx>, name: &str) -> Option<Intrinsic> {{
     if !name.starts_with("{0}") {{ return None }}
     Some(match &name["{0}".len()..] {{'''.format(platform.intrinsic_prefix())
 
diff --git a/src/etc/platform-intrinsics/x86/fma.json b/src/etc/platform-intrinsics/x86/fma.json
new file mode 100644
index 00000000000..c922d166c8f
--- /dev/null
+++ b/src/etc/platform-intrinsics/x86/fma.json
@@ -0,0 +1,47 @@
+{
+    "llvm_prefix": "llvm.x86.fma.",
+    "intrinsics": [
+        {
+            "intrinsic": "{0.width_mm}_fmadd_{0.data_type}",
+            "width": [128, 256],
+            "llvm": "vfmadd.{0.data_type_short}{0.width_suffix}",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "0"]
+        },
+        {
+            "intrinsic": "{0.width_mm}_fmaddsub_{0.data_type}",
+            "width": [128, 256],
+            "llvm": "vfmaddsub.{0.data_type_short}{0.width_suffix}",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "0"]
+        },
+        {
+            "intrinsic": "{0.width_mm}_fmsub_{0.data_type}",
+            "width": [128, 256],
+            "llvm": "vfmsub.{0.data_type_short}{0.width_suffix}",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "0"]
+        },
+        {
+            "intrinsic": "{0.width_mm}_fmsubadd_{0.data_type}",
+            "width": [128, 256],
+            "llvm": "vfmsubadd.{0.data_type_short}{0.width_suffix}",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "0"]
+        },
+        {
+            "intrinsic": "{0.width_mm}_fnmadd_{0.data_type}",
+            "width": [128, 256],
+            "llvm": "vfnmadd.{0.data_type_short}{0.width_suffix}",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "0"]
+        },
+        {
+            "intrinsic": "{0.width_mm}_fnmsub_{0.data_type}",
+            "width": [128, 256],
+            "llvm": "vfnmsub.{0.data_type_short}{0.width_suffix}",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "0"]
+        }
+    ]
+}
diff --git a/src/etc/unicode.py b/src/etc/unicode.py
index 10b864a902d..5a7632868e4 100755
--- a/src/etc/unicode.py
+++ b/src/etc/unicode.py
@@ -398,7 +398,7 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
         derived = load_properties("DerivedCoreProperties.txt", want_derived)
         scripts = load_properties("Scripts.txt", [])
         props = load_properties("PropList.txt",
-                ["White_Space", "Join_Control", "Noncharacter_Code_Point"])
+                ["White_Space", "Join_Control", "Noncharacter_Code_Point", "Pattern_White_Space"])
         norm_props = load_properties("DerivedNormalizationProps.txt",
                      ["Full_Composition_Exclusion"])
 
@@ -408,7 +408,7 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
         # category tables
         for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \
                                   ("derived_property", derived, want_derived), \
-                                  ("property", props, ["White_Space"]):
+                                  ("property", props, ["White_Space", "Pattern_White_Space"]):
             emit_property_module(rf, name, cat, pfuns)
 
         # normalizations and conversions module
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 300142d5ec1..0293d5402c4 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -92,16 +92,13 @@
 #![feature(unsize)]
 
 #![cfg_attr(not(test), feature(raw, fn_traits, placement_new_protocol))]
-#![cfg_attr(test, feature(test, rustc_private, box_heap))]
+#![cfg_attr(test, feature(test, box_heap))]
 
 // Allow testing this library
 
 #[cfg(test)]
 #[macro_use]
 extern crate std;
-#[cfg(test)]
-#[macro_use]
-extern crate log;
 
 // Heaps provided for low-level allocation strategies
 
diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs
index c9508322a31..9e2090c3246 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -111,7 +111,7 @@ fn main() {
     println!("cargo:rustc-link-search=native={}/lib", build_dir.display());
     if target.contains("android") {
         println!("cargo:rustc-link-lib=gcc");
-    } else if !target.contains("windows") {
+    } else if !target.contains("windows") && !target.contains("musl") {
         println!("cargo:rustc-link-lib=pthread");
     }
 }
diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs
index 2a950ce0ab7..1967f83ab27 100644
--- a/src/libcollections/btree/map.rs
+++ b/src/libcollections/btree/map.rs
@@ -58,6 +58,74 @@ use self::Entry::*;
 /// It is a logic error for a key to be modified in such a way that the key's ordering relative to
 /// any other key, as determined by the `Ord` trait, changes while it is in the map. This is
 /// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::BTreeMap;
+///
+/// // type inference lets us omit an explicit type signature (which
+/// // would be `BTreeMap<&str, &str>` in this example).
+/// let mut movie_reviews = BTreeMap::new();
+///
+/// // review some books.
+/// 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.");
+/// movie_reviews.insert("The Blues Brothers", "Eye lyked it alot.");
+///
+/// // check for a specific one.
+/// if !movie_reviews.contains_key("Les Misérables") {
+///     println!("We've got {} reviews, but Les Misérables ain't one.",
+///              movie_reviews.len());
+/// }
+///
+/// // oops, this review has a lot of spelling mistakes, let's delete it.
+/// movie_reviews.remove("The Blues Brothers");
+///
+/// // look up the values associated with some keys.
+/// let to_find = ["Up!", "Office Space"];
+/// for book in &to_find {
+///     match movie_reviews.get(book) {
+///        Some(review) => println!("{}: {}", book, review),
+///        None => println!("{} is unreviewed.", book)
+///     }
+/// }
+///
+/// // iterate over everything.
+/// for (movie, review) in &movie_reviews {
+///     println!("{}: \"{}\"", movie, review);
+/// }
+/// ```
+///
+/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows
+/// for more complex methods of getting, setting, updating and removing keys and
+/// their values:
+///
+/// ```
+/// use std::collections::BTreeMap;
+///
+/// // type inference lets us omit an explicit type signature (which
+/// // would be `BTreeMap<&str, u8>` in this example).
+/// let mut player_stats = BTreeMap::new();
+///
+/// fn random_stat_buff() -> u8 {
+///     // could actually return some random value here - let's just return
+///     // some fixed value for now
+///     42
+/// }
+///
+/// // insert a key only if it doesn't already exist
+/// player_stats.entry("health").or_insert(100);
+///
+/// // insert a key using a function that provides a new value only if it
+/// // doesn't already exist
+/// player_stats.entry("defence").or_insert_with(random_stat_buff);
+///
+/// // update a key, guarding against the key possibly not being set
+/// let stat = player_stats.entry("attack").or_insert(100);
+/// *stat += random_stat_buff();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BTreeMap<K, V> {
     root: node::Root<K, V>,
@@ -276,6 +344,19 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
 
 impl<K: Ord, V> BTreeMap<K, V> {
     /// Makes a new empty BTreeMap with a reasonable choice for B.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map = BTreeMap::new();
+    ///
+    /// // entries can now be inserted into the empty map
+    /// map.insert(1, "a");
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> BTreeMap<K, V> {
         BTreeMap {
@@ -288,6 +369,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -309,6 +392,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -332,6 +417,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -352,6 +439,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -384,6 +473,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -414,6 +505,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -443,6 +536,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// #![feature(btree_range, collections_bound)]
     ///
@@ -516,6 +611,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// #![feature(btree_range, collections_bound)]
     ///
@@ -591,6 +688,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -1199,6 +1298,8 @@ impl<K, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -1229,6 +1330,8 @@ impl<K, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -1262,6 +1365,8 @@ impl<K, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -1281,6 +1386,8 @@ impl<K, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -1300,6 +1407,8 @@ impl<K, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
@@ -1317,6 +1426,8 @@ impl<K, V> BTreeMap<K, V> {
     ///
     /// # Examples
     ///
+    /// Basic usage:
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs
index 97b01a607f5..435c9f0e9f4 100644
--- a/src/libcollections/fmt.rs
+++ b/src/libcollections/fmt.rs
@@ -429,20 +429,20 @@
 //! For example, these:
 //!
 //! ```
-//! // Hello {arg 0 (x)} is {arg 1 (0.01} with precision specified inline (5)}
+//! // Hello {arg 0 (x)} is {arg 1 (0.01) with precision specified inline (5)}
 //! println!("Hello {0} is {1:.5}", "x", 0.01);
 //!
-//! // Hello {arg 1 (x)} is {arg 2 (0.01} with precision specified in arg 0 (5)}
+//! // Hello {arg 1 (x)} is {arg 2 (0.01) with precision specified in arg 0 (5)}
 //! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
 //!
-//! // Hello {arg 0 (x)} is {arg 2 (0.01} with precision specified in arg 1 (5)}
+//! // Hello {arg 0 (x)} is {arg 2 (0.01) with precision specified in arg 1 (5)}
 //! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
 //!
-//! // Hello {next arg (x)} is {second of next two args (0.01} with precision
+//! // Hello {next arg (x)} is {second of next two args (0.01) with precision
 //! //                          specified in first of next two args (5)}
 //! println!("Hello {} is {:.*}",    "x", 5, 0.01);
 //!
-//! // Hello {next arg (x)} is {arg 2 (0.01} with precision
+//! // Hello {next arg (x)} is {arg 2 (0.01) with precision
 //! //                          specified in its predecessor (5)}
 //! println!("Hello {} is {2:.*}",   "x", 5, 0.01);
 //! ```
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index e6cf5aa6683..922e1b0fc5d 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -40,7 +40,7 @@
 #![feature(fmt_internals)]
 #![feature(fmt_radix)]
 #![feature(heap_api)]
-#![feature(iter_arith)]
+#![feature(inclusive_range)]
 #![feature(iter_arith)]
 #![feature(lang_items)]
 #![feature(nonzero)]
diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs
index afcd779ddf1..4e39191b472 100644
--- a/src/libcollections/range.rs
+++ b/src/libcollections/range.rs
@@ -35,6 +35,7 @@ pub trait RangeArgument<T> {
     }
 }
 
+// FIXME add inclusive ranges to RangeArgument
 
 impl<T> RangeArgument<T> for RangeFull {}
 
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index a30ec452e3c..5789cd8edfc 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Unicode string slices
+//! Unicode string slices.
 //!
 //! *[See also the `str` primitive type](../primitive.str.html).*
 
diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs
index 62ae7938e15..cae6520bdb2 100644
--- a/src/libcollections/string.rs
+++ b/src/libcollections/string.rs
@@ -59,7 +59,7 @@ use core::fmt;
 use core::hash;
 use core::iter::FromIterator;
 use core::mem;
-use core::ops::{self, Add};
+use core::ops::{self, Add, Index, IndexMut};
 use core::ptr;
 use core::slice;
 use core::str::pattern::Pattern;
@@ -1606,6 +1606,24 @@ impl ops::Index<ops::RangeFull> for String {
         unsafe { str::from_utf8_unchecked(&self.vec) }
     }
 }
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl ops::Index<ops::RangeInclusive<usize>> for String {
+    type Output = str;
+
+    #[inline]
+    fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
+        Index::index(&**self, index)
+    }
+}
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl ops::Index<ops::RangeToInclusive<usize>> for String {
+    type Output = str;
+
+    #[inline]
+    fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
+        Index::index(&**self, index)
+    }
+}
 
 #[stable(feature = "derefmut_for_string", since = "1.2.0")]
 impl ops::IndexMut<ops::Range<usize>> for String {
@@ -1635,6 +1653,20 @@ impl ops::IndexMut<ops::RangeFull> for String {
         unsafe { mem::transmute(&mut *self.vec) }
     }
 }
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl ops::IndexMut<ops::RangeInclusive<usize>> for String {
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
+        IndexMut::index_mut(&mut **self, index)
+    }
+}
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl ops::IndexMut<ops::RangeToInclusive<usize>> for String {
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
+        IndexMut::index_mut(&mut **self, index)
+    }
+}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Deref for String {
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index efcb5d2ceb3..934a9f3d614 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1226,6 +1226,24 @@ impl<T> ops::Index<ops::RangeFull> for Vec<T> {
         self
     }
 }
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> {
+    type Output = [T];
+
+    #[inline]
+    fn index(&self, index: ops::RangeInclusive<usize>) -> &[T] {
+        Index::index(&**self, index)
+    }
+}
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> {
+    type Output = [T];
+
+    #[inline]
+    fn index(&self, index: ops::RangeToInclusive<usize>) -> &[T] {
+        Index::index(&**self, index)
+    }
+}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> {
@@ -1255,6 +1273,20 @@ impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
         self
     }
 }
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for Vec<T> {
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
+        IndexMut::index_mut(&mut **self, index)
+    }
+}
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for Vec<T> {
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
+        IndexMut::index_mut(&mut **self, index)
+    }
+}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Deref for Vec<T> {
diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs
index eed530d8b61..f52ed8ff43d 100644
--- a/src/libcollectionstest/lib.rs
+++ b/src/libcollectionstest/lib.rs
@@ -23,7 +23,6 @@
 #![feature(iter_arith)]
 #![feature(pattern)]
 #![feature(rand)]
-#![feature(rustc_private)]
 #![feature(set_recovery)]
 #![feature(slice_bytes)]
 #![feature(step_by)]
@@ -33,8 +32,6 @@
 #![feature(unboxed_closures)]
 #![feature(unicode)]
 
-#[macro_use] extern crate log;
-
 extern crate collections;
 extern crate test;
 extern crate rustc_unicode;
diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs
index b84b37dbf75..776d73ef10f 100644
--- a/src/libcollectionstest/str.rs
+++ b/src/libcollectionstest/str.rs
@@ -346,6 +346,26 @@ fn test_slice_fail() {
     &"中华Việt Nam"[0..2];
 }
 
+const LOREM_PARAGRAPH: &'static str = "\
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
+ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
+eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
+sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
+tempus vel, gravida nec quam.";
+
+// check the panic includes the prefix of the sliced string
+#[test]
+#[should_panic(expected="Lorem ipsum dolor sit amet")]
+fn test_slice_fail_truncated_1() {
+    &LOREM_PARAGRAPH[..1024];
+}
+// check the truncation in the panic message
+#[test]
+#[should_panic(expected="luctus, im`[...] do not lie on character boundary")]
+fn test_slice_fail_truncated_2() {
+    &LOREM_PARAGRAPH[..1024];
+}
+
 #[test]
 fn test_slice_from() {
     assert_eq!(&"abcd"[0..], "abcd");
@@ -606,8 +626,6 @@ fn vec_str_conversions() {
     while i < n1 {
         let a: u8 = s1.as_bytes()[i];
         let b: u8 = s2.as_bytes()[i];
-        debug!("{}", a);
-        debug!("{}", b);
         assert_eq!(a, b);
         i += 1;
     }
diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs
index 742205df8d7..95675a2423e 100644
--- a/src/libcollectionstest/vec_deque.rs
+++ b/src/libcollectionstest/vec_deque.rs
@@ -45,10 +45,6 @@ fn test_simple() {
     assert_eq!(d.len(), 3);
     d.push_front(1);
     assert_eq!(d.len(), 4);
-    debug!("{}", d[0]);
-    debug!("{}", d[1]);
-    debug!("{}", d[2]);
-    debug!("{}", d[3]);
     assert_eq!(d[0], 1);
     assert_eq!(d[1], 2);
     assert_eq!(d[2], 3);
diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs
index 769faedf46e..b1f63ad71ca 100644
--- a/src/libcore/clone.rs
+++ b/src/libcore/clone.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! The `Clone` trait for types that cannot be 'implicitly copied'
+//! The `Clone` trait for types that cannot be 'implicitly copied'.
 //!
 //! In Rust, some simple types are "implicitly copyable" and when you
 //! assign them or pass them as arguments, the receiver will get a copy,
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index a3b09e9db42..6cc3b4e01b8 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Utilities for formatting and printing strings
+//! Utilities for formatting and printing strings.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index 37fe4d39db8..fb8eda820f5 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Composable external iteration
+//! Composable external iteration.
 //!
 //! If you've found yourself with a collection of some kind, and needed to
 //! perform an operation on the elements of said collection, you'll quickly run
@@ -306,7 +306,7 @@ use default::Default;
 use marker;
 use mem;
 use num::{Zero, One};
-use ops::{self, Add, Sub, FnMut, Mul, RangeFrom};
+use ops::{self, Add, Sub, FnMut, Mul};
 use option::Option::{self, Some, None};
 use marker::Sized;
 use usize;
@@ -4297,7 +4297,7 @@ step_impl_no_between!(u64 i64);
 ///
 /// The resulting iterator handles overflow by stopping. The `A`
 /// parameter is the type being iterated over, while `R` is the range
-/// type (usually one of `std::ops::{Range, RangeFrom}`.
+/// type (usually one of `std::ops::{Range, RangeFrom, RangeInclusive}`.
 #[derive(Clone)]
 #[unstable(feature = "step_by", reason = "recent addition",
            issue = "27741")]
@@ -4306,7 +4306,7 @@ pub struct StepBy<A, R> {
     range: R,
 }
 
-impl<A: Step> RangeFrom<A> {
+impl<A: Step> ops::RangeFrom<A> {
     /// Creates an iterator starting at the same point, but stepping by
     /// the given amount at each iteration.
     ///
@@ -4366,8 +4366,44 @@ impl<A: Step> ops::Range<A> {
     }
 }
 
+impl<A: Step> ops::RangeInclusive<A> {
+    /// Creates an iterator with the same range, but stepping by the
+    /// given amount at each iteration.
+    ///
+    /// The resulting iterator handles overflow by stopping.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(step_by, inclusive_range_syntax)]
+    ///
+    /// for i in (0...10).step_by(2) {
+    ///     println!("{}", i);
+    /// }
+    /// ```
+    ///
+    /// This prints:
+    ///
+    /// ```text
+    /// 0
+    /// 2
+    /// 4
+    /// 6
+    /// 8
+    /// 10
+    /// ```
+    #[unstable(feature = "step_by", reason = "recent addition",
+               issue = "27741")]
+    pub fn step_by(self, by: A) -> StepBy<A, Self> {
+        StepBy {
+            step_by: by,
+            range: self
+        }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A> Iterator for StepBy<A, RangeFrom<A>> where
+impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
     A: Clone,
     for<'a> &'a A: Add<&'a A, Output = A>
 {
@@ -4386,95 +4422,6 @@ impl<A> Iterator for StepBy<A, RangeFrom<A>> where
     }
 }
 
-/// An iterator over the range [start, stop]
-#[derive(Clone)]
-#[unstable(feature = "range_inclusive",
-           reason = "likely to be replaced by range notation and adapters",
-           issue = "27777")]
-#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
-#[allow(deprecated)]
-pub struct RangeInclusive<A> {
-    range: ops::Range<A>,
-    done: bool,
-}
-
-/// Returns an iterator over the range [start, stop].
-#[inline]
-#[unstable(feature = "range_inclusive",
-           reason = "likely to be replaced by range notation and adapters",
-           issue = "27777")]
-#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
-#[allow(deprecated)]
-pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
-    where A: Step + One + Clone
-{
-    RangeInclusive {
-        range: start..stop,
-        done: false,
-    }
-}
-
-#[unstable(feature = "range_inclusive",
-           reason = "likely to be replaced by range notation and adapters",
-           issue = "27777")]
-#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
-#[allow(deprecated)]
-impl<A> Iterator for RangeInclusive<A> where
-    A: PartialEq + Step + One + Clone,
-    for<'a> &'a A: Add<&'a A, Output = A>
-{
-    type Item = A;
-
-    #[inline]
-    fn next(&mut self) -> Option<A> {
-        self.range.next().or_else(|| {
-            if !self.done && self.range.start == self.range.end {
-                self.done = true;
-                Some(self.range.end.clone())
-            } else {
-                None
-            }
-        })
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (lo, hi) = self.range.size_hint();
-        if self.done {
-            (lo, hi)
-        } else {
-            let lo = lo.saturating_add(1);
-            let hi = hi.and_then(|x| x.checked_add(1));
-            (lo, hi)
-        }
-    }
-}
-
-#[unstable(feature = "range_inclusive",
-           reason = "likely to be replaced by range notation and adapters",
-           issue = "27777")]
-#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
-#[allow(deprecated)]
-impl<A> DoubleEndedIterator for RangeInclusive<A> where
-    A: PartialEq + Step + One + Clone,
-    for<'a> &'a A: Add<&'a A, Output = A>,
-    for<'a> &'a A: Sub<Output=A>
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<A> {
-        if self.range.end > self.range.start {
-            let result = self.range.end.clone();
-            self.range.end = &self.range.end - &A::one();
-            Some(result)
-        } else if !self.done && self.range.start == self.range.end {
-            self.done = true;
-            Some(self.range.end.clone())
-        } else {
-            None
-        }
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
     type Item = A;
@@ -4512,10 +4459,83 @@ impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
     }
 }
 
+#[unstable(feature = "inclusive_range",
+           reason = "recently added, follows RFC",
+           issue = "28237")]
+impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        use ops::RangeInclusive::*;
+
+        // this function has a sort of odd structure due to borrowck issues
+        // we may need to replace self.range, so borrows of start and end need to end early
+
+        let (finishing, n) = match self.range {
+            Empty { .. } => return None, // empty iterators yield no values
+
+            NonEmpty { ref mut start, ref mut end } => {
+                let zero = A::zero();
+                let rev = self.step_by < zero;
+
+                // march start towards (maybe past!) end and yield the old value
+                if (rev && start >= end) ||
+                   (!rev && start <= end)
+                {
+                    match start.step(&self.step_by) {
+                        Some(mut n) => {
+                            mem::swap(start, &mut n);
+                            (None, Some(n)) // yield old value, remain non-empty
+                        },
+                        None => {
+                            let mut n = end.clone();
+                            mem::swap(start, &mut n);
+                            (None, Some(n)) // yield old value, remain non-empty
+                        }
+                    }
+                } else {
+                    // found range in inconsistent state (start at or past end), so become empty
+                    (Some(mem::replace(end, zero)), None)
+                }
+            }
+        };
+
+        // turn into an empty iterator if we've reached the end
+        if let Some(end) = finishing {
+            self.range = Empty { at: end };
+        }
+
+        n
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        use ops::RangeInclusive::*;
+
+        match self.range {
+            Empty { .. } => (0, Some(0)),
+
+            NonEmpty { ref start, ref end } =>
+                match Step::steps_between(start,
+                                          end,
+                                          &self.step_by) {
+                    Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
+                    None       => (0, None)
+                }
+        }
+    }
+}
+
 macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
         impl ExactSizeIterator for ops::Range<$t> { }
+
+        #[unstable(feature = "inclusive_range",
+                   reason = "recently added, follows RFC",
+                   issue = "28237")]
+        impl ExactSizeIterator for ops::RangeInclusive<$t> { }
     )*)
 }
 
@@ -4579,6 +4599,107 @@ impl<A: Step + One> Iterator for ops::RangeFrom<A> where
     }
 }
 
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<A: Step + One> Iterator for ops::RangeInclusive<A> where
+    for<'a> &'a A: Add<&'a A, Output = A>
+{
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        use ops::RangeInclusive::*;
+
+        // this function has a sort of odd structure due to borrowck issues
+        // we may need to replace self, so borrows of self.start and self.end need to end early
+
+        let (finishing, n) = match *self {
+            Empty { .. } => (None, None), // empty iterators yield no values
+
+            NonEmpty { ref mut start, ref mut end } => {
+                if start == end {
+                    (Some(mem::replace(end, A::one())), Some(mem::replace(start, A::one())))
+                } else if start < end {
+                    let one = A::one();
+                    let mut n = &*start + &one;
+                    mem::swap(&mut n, start);
+
+                    // if the iterator is done iterating, it will change from NonEmpty to Empty
+                    // to avoid unnecessary drops or clones, we'll reuse either start or end
+                    // (they are equal now, so it doesn't matter which)
+                    // to pull out end, we need to swap something back in -- use the previously
+                    // created A::one() as a dummy value
+
+                    (if n == *end { Some(mem::replace(end, one)) } else { None },
+                    // ^ are we done yet?
+                    Some(n)) // < the value to output
+                } else {
+                    (Some(mem::replace(start, A::one())), None)
+                }
+            }
+        };
+
+        // turn into an empty iterator if this is the last value
+        if let Some(end) = finishing {
+            *self = Empty { at: end };
+        }
+
+        n
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        use ops::RangeInclusive::*;
+
+        match *self {
+            Empty { .. } => (0, Some(0)),
+
+            NonEmpty { ref start, ref end } =>
+                match Step::steps_between(start, end, &A::one()) {
+                    Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
+                    None => (0, None),
+                }
+        }
+    }
+}
+
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<A: Step + One> DoubleEndedIterator for ops::RangeInclusive<A> where
+    for<'a> &'a A: Add<&'a A, Output = A>,
+    for<'a> &'a A: Sub<&'a A, Output = A>
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        use ops::RangeInclusive::*;
+
+        // see Iterator::next for comments
+
+        let (finishing, n) = match *self {
+            Empty { .. } => return None,
+
+            NonEmpty { ref mut start, ref mut end } => {
+                if start == end {
+                    (Some(mem::replace(start, A::one())), Some(mem::replace(end, A::one())))
+                } else if start < end {
+                    let one = A::one();
+                    let mut n = &*end - &one;
+                    mem::swap(&mut n, end);
+
+                    (if n == *start { Some(mem::replace(start, one)) } else { None },
+                     Some(n))
+                } else {
+                    (Some(mem::replace(end, A::one())), None)
+                }
+            }
+        };
+
+        if let Some(start) = finishing {
+            *self = Empty { at: start };
+        }
+
+        n
+    }
+}
+
 /// An iterator that repeats an element endlessly.
 ///
 /// This `struct` is created by the [`repeat()`] function. See its documentation for more.
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index c36ad592ad3..2c648d1516b 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Basic functions for dealing with memory
+//! Basic functions for dealing with memory.
 //!
 //! This module contains functions for querying the size and alignment of
 //! types, initializing and manipulating memory.
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 0f5584a952f..5d6accc4438 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Overloadable operators
+//! Overloadable operators.
 //!
 //! Implementing these traits allows you to get an effect similar to
 //! overloading operators.
@@ -67,8 +67,11 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use marker::{Sized, Unsize};
+use cmp::PartialOrd;
 use fmt;
+use convert::From;
+use marker::{Sized, Unsize};
+use num::One;
 
 /// The `Drop` trait is used to run some code when a value goes out of scope.
 /// This is sometimes called a 'destructor'.
@@ -1445,7 +1448,7 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
 
 /// An unbounded range.
 #[derive(Copy, Clone, PartialEq, Eq)]
-#[lang = "range_full"]
+#[cfg_attr(stage0, lang = "range_full")] // FIXME remove attribute after next snapshot
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeFull;
 
@@ -1458,7 +1461,7 @@ impl fmt::Debug for RangeFull {
 
 /// A (half-open) range which is bounded at both ends.
 #[derive(Clone, PartialEq, Eq)]
-#[lang = "range"]
+#[cfg_attr(stage0, lang = "range")] // FIXME remove attribute after next snapshot
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Range<Idx> {
     /// The lower bound of the range (inclusive).
@@ -1478,7 +1481,7 @@ impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
 
 /// A range which is only bounded below.
 #[derive(Clone, PartialEq, Eq)]
-#[lang = "range_from"]
+#[cfg_attr(stage0, lang = "range_from")] // FIXME remove attribute after next snapshot
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeFrom<Idx> {
     /// The lower bound of the range (inclusive).
@@ -1495,7 +1498,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
 
 /// A range which is only bounded above.
 #[derive(Copy, Clone, PartialEq, Eq)]
-#[lang = "range_to"]
+#[cfg_attr(stage0, lang = "range_to")] // FIXME remove attribute after next snapshot
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeTo<Idx> {
     /// The upper bound of the range (exclusive).
@@ -1510,6 +1513,90 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeTo<Idx> {
     }
 }
 
+/// An inclusive range which is bounded at both ends.
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+pub enum RangeInclusive<Idx> {
+    /// Empty range (iteration has finished)
+    #[unstable(feature = "inclusive_range",
+               reason = "recently added, follows RFC",
+               issue = "28237")]
+    Empty {
+        /// The point at which iteration finished
+        #[unstable(feature = "inclusive_range",
+                   reason = "recently added, follows RFC",
+                   issue = "28237")]
+        at: Idx
+    },
+    /// Non-empty range (iteration will yield value(s))
+    #[unstable(feature = "inclusive_range",
+               reason = "recently added, follows RFC",
+               issue = "28237")]
+    NonEmpty {
+        /// The lower bound of the range (inclusive).
+        #[unstable(feature = "inclusive_range",
+                   reason = "recently added, follows RFC",
+                   issue = "28237")]
+        start: Idx,
+        /// The upper bound of the range (inclusive).
+        #[unstable(feature = "inclusive_range",
+                   reason = "recently added, follows RFC",
+                   issue = "28237")]
+        end: Idx,
+    },
+}
+
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        use self::RangeInclusive::*;
+
+        match *self {
+            Empty { ref at } => write!(fmt, "[empty range @ {:?}]", at),
+            NonEmpty { ref start, ref end } => write!(fmt, "{:?}...{:?}", start, end),
+        }
+    }
+}
+
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<Idx: PartialOrd + One + Sub<Output=Idx>> From<Range<Idx>> for RangeInclusive<Idx> {
+    fn from(range: Range<Idx>) -> RangeInclusive<Idx> {
+        use self::RangeInclusive::*;
+
+        if range.start < range.end {
+            NonEmpty {
+                start: range.start,
+                end: range.end - Idx::one() // can't underflow because end > start >= MIN
+            }
+        } else {
+            Empty {
+                at: range.start
+            }
+        }
+    }
+}
+
+/// An inclusive range which is only bounded above.
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+pub struct RangeToInclusive<Idx> {
+    /// The upper bound of the range (inclusive)
+    #[unstable(feature = "inclusive_range",
+               reason = "recently added, follows RFC",
+               issue = "28237")]
+    pub end: Idx,
+}
+
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "...{:?}", self.end)
+    }
+}
+
+// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>>
+// because underflow would be possible with (..0).into()
+
 /// The `Deref` trait is used to specify the functionality of dereferencing
 /// operations, like `*v`.
 ///
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index e38cf9af010..56b84fd6a64 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Optional values
+//! Optional values.
 //!
 //! Type `Option` represents an optional value: every `Option`
 //! is either `Some` and contains a value, or `None`, and
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 3cf722668b2..3cbeac450e2 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -10,7 +10,7 @@
 
 // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory
 
-//! Raw, unsafe pointers, `*const T`, and `*mut T`
+//! Raw, unsafe pointers, `*const T`, and `*mut T`.
 //!
 //! *[See also the pointer primitive types](../../std/primitive.pointer.html).*
 
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index f6703d16ad9..09f612c20ec 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Error handling with the `Result` type
+//! Error handling with the `Result` type.
 //!
 //! `Result<T, E>` is the type used for returning and propagating
 //! errors. It is an enum with the variants, `Ok(T)`, representing
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index fb15533f33c..8acd0c8f2cf 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -533,6 +533,8 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
     panic!("slice index starts at {} but ends at {}", index, end);
 }
 
+// FIXME implement indexing with inclusive ranges
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::Range<usize>> for [T] {
     type Output = [T];
@@ -558,7 +560,7 @@ impl<T> ops::Index<ops::RangeTo<usize>> for [T] {
 
     #[inline]
     fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
-        self.index(ops::Range{ start: 0, end: index.end })
+        self.index(0 .. index.end)
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -567,7 +569,7 @@ impl<T> ops::Index<ops::RangeFrom<usize>> for [T] {
 
     #[inline]
     fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
-        self.index(ops::Range{ start: index.start, end: self.len() })
+        self.index(index.start .. self.len())
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -580,6 +582,32 @@ impl<T> ops::Index<RangeFull> for [T] {
     }
 }
 
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] {
+    type Output = [T];
+
+    #[inline]
+    fn index(&self, index: ops::RangeInclusive<usize>) -> &[T] {
+        match index {
+            ops::RangeInclusive::Empty { .. } => &[],
+            ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() =>
+                panic!("attempted to index slice up to maximum usize"),
+            ops::RangeInclusive::NonEmpty { start, end } =>
+                self.index(start .. end+1)
+        }
+    }
+}
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] {
+    type Output = [T];
+
+    #[inline]
+    fn index(&self, index: ops::RangeToInclusive<usize>) -> &[T] {
+        // SNAP 4d3eebf change this to `0...index.end`
+        self.index(ops::RangeInclusive::NonEmpty { start: 0, end: index.end })
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::Range<usize>> for [T] {
     #[inline]
@@ -601,7 +629,7 @@ impl<T> ops::IndexMut<ops::Range<usize>> for [T] {
 impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
-        self.index_mut(ops::Range{ start: 0, end: index.end })
+        self.index_mut(0 .. index.end)
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -609,7 +637,7 @@ impl<T> ops::IndexMut<ops::RangeFrom<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
         let len = self.len();
-        self.index_mut(ops::Range{ start: index.start, end: len })
+        self.index_mut(index.start .. len)
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -620,6 +648,27 @@ impl<T> ops::IndexMut<RangeFull> for [T] {
     }
 }
 
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] {
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
+        match index {
+            ops::RangeInclusive::Empty { .. } => &mut [],
+            ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() =>
+                panic!("attempted to index slice up to maximum usize"),
+            ops::RangeInclusive::NonEmpty { start, end } =>
+                self.index_mut(start .. end+1)
+        }
+    }
+}
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for [T] {
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
+        // SNAP 4d3eebf change this to `0...index.end`
+        self.index_mut(ops::RangeInclusive::NonEmpty { start: 0, end: index.end })
+    }
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Common traits
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 2d898b50e0c..f5abdf65a5b 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -1311,13 +1311,19 @@ mod traits {
         }
     }
 
+    /// Implements substring slicing with syntax `&self[begin .. end]`.
+    ///
     /// Returns a slice of the given string from the byte range
     /// [`begin`..`end`).
     ///
     /// This operation is `O(1)`.
     ///
-    /// Panics when `begin` and `end` do not point to valid characters
-    /// or point beyond the last character of the string.
+    /// # Panics
+    ///
+    /// Panics if `begin` or `end` does not point to the starting
+    /// byte offset of a character (as defined by `is_char_boundary`).
+    /// Requires that `begin <= end` and `end <= len` where `len` is the
+    /// length of the string.
     ///
     /// # Examples
     ///
@@ -1353,8 +1359,20 @@ mod traits {
         }
     }
 
+    /// Implements mutable substring slicing with syntax
+    /// `&mut self[begin .. end]`.
+    ///
     /// Returns a mutable slice of the given string from the byte range
     /// [`begin`..`end`).
+    ///
+    /// This operation is `O(1)`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `begin` or `end` does not point to the starting
+    /// byte offset of a character (as defined by `is_char_boundary`).
+    /// Requires that `begin <= end` and `end <= len` where `len` is the
+    /// length of the string.
     #[stable(feature = "derefmut_for_string", since = "1.2.0")]
     impl ops::IndexMut<ops::Range<usize>> for str {
         #[inline]
@@ -1370,13 +1388,12 @@ mod traits {
         }
     }
 
-    /// Returns a slice of the string from the beginning to byte
-    /// `end`.
+    /// Implements substring slicing with syntax `&self[.. end]`.
     ///
-    /// Equivalent to `self[0 .. end]`.
+    /// Returns a slice of the string from the beginning to byte offset
+    /// `end`.
     ///
-    /// Panics when `end` does not point to a valid character, or is
-    /// out of bounds.
+    /// Equivalent to `&self[0 .. end]`.
     #[stable(feature = "rust1", since = "1.0.0")]
     impl ops::Index<ops::RangeTo<usize>> for str {
         type Output = str;
@@ -1392,8 +1409,12 @@ mod traits {
         }
     }
 
-    /// Returns a mutable slice of the string from the beginning to byte
+    /// Implements mutable substring slicing with syntax `&mut self[.. end]`.
+    ///
+    /// Returns a mutable slice of the string from the beginning to byte offset
     /// `end`.
+    ///
+    /// Equivalent to `&mut self[0 .. end]`.
     #[stable(feature = "derefmut_for_string", since = "1.2.0")]
     impl ops::IndexMut<ops::RangeTo<usize>> for str {
         #[inline]
@@ -1407,12 +1428,12 @@ mod traits {
         }
     }
 
-    /// Returns a slice of the string from `begin` to its end.
+    /// Implements substring slicing with syntax `&self[begin ..]`.
     ///
-    /// Equivalent to `self[begin .. self.len()]`.
+    /// Returns a slice of the string from byte offset `begin`
+    /// to the end of the string.
     ///
-    /// Panics when `begin` does not point to a valid character, or is
-    /// out of bounds.
+    /// Equivalent to `&self[begin .. len]`.
     #[stable(feature = "rust1", since = "1.0.0")]
     impl ops::Index<ops::RangeFrom<usize>> for str {
         type Output = str;
@@ -1428,7 +1449,12 @@ mod traits {
         }
     }
 
-    /// Returns a slice of the string from `begin` to its end.
+    /// Implements mutable substring slicing with syntax `&mut self[begin ..]`.
+    ///
+    /// Returns a mutable slice of the string from byte offset `begin`
+    /// to the end of the string.
+    ///
+    /// Equivalent to `&mut self[begin .. len]`.
     #[stable(feature = "derefmut_for_string", since = "1.2.0")]
     impl ops::IndexMut<ops::RangeFrom<usize>> for str {
         #[inline]
@@ -1443,6 +1469,12 @@ mod traits {
         }
     }
 
+    /// Implements substring slicing with syntax `&self[..]`.
+    ///
+    /// Returns a slice of the whole string. This operation can
+    /// never panic.
+    ///
+    /// Equivalent to `&self[0 .. len]`.
     #[stable(feature = "rust1", since = "1.0.0")]
     impl ops::Index<ops::RangeFull> for str {
         type Output = str;
@@ -1453,6 +1485,12 @@ mod traits {
         }
     }
 
+    /// Implements mutable substring slicing with syntax `&mut self[..]`.
+    ///
+    /// Returns a mutable slice of the whole string. This operation can
+    /// never panic.
+    ///
+    /// Equivalent to `&mut self[0 .. len]`.
     #[stable(feature = "derefmut_for_string", since = "1.2.0")]
     impl ops::IndexMut<ops::RangeFull> for str {
         #[inline]
@@ -1460,6 +1498,62 @@ mod traits {
             self
         }
     }
+
+    #[unstable(feature = "inclusive_range",
+               reason = "recently added, follows RFC",
+               issue = "28237")]
+    impl ops::Index<ops::RangeInclusive<usize>> for str {
+        type Output = str;
+
+        #[inline]
+        fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
+            match index {
+                ops::RangeInclusive::Empty { .. } => "",
+                ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() =>
+                    panic!("attempted to index slice up to maximum usize"),
+                ops::RangeInclusive::NonEmpty { start, end } =>
+                    self.index(start .. end+1)
+            }
+        }
+    }
+    #[unstable(feature = "inclusive_range",
+               reason = "recently added, follows RFC",
+               issue = "28237")]
+    impl ops::Index<ops::RangeToInclusive<usize>> for str {
+        type Output = str;
+
+        #[inline]
+        fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
+            // SNAP 4d3eebf change this to `0...index.end`
+            self.index(ops::RangeInclusive::NonEmpty { start: 0, end: index.end })
+        }
+    }
+
+    #[unstable(feature = "inclusive_range",
+               reason = "recently added, follows RFC",
+               issue = "28237")]
+    impl ops::IndexMut<ops::RangeInclusive<usize>> for str {
+        #[inline]
+        fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
+            match index {
+                ops::RangeInclusive::Empty { .. } => &mut self[0..0], // `&mut ""` doesn't work
+                ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() =>
+                    panic!("attempted to index str up to maximum usize"),
+                    ops::RangeInclusive::NonEmpty { start, end } =>
+                        self.index_mut(start .. end+1)
+            }
+        }
+    }
+    #[unstable(feature = "inclusive_range",
+               reason = "recently added, follows RFC",
+               issue = "28237")]
+    impl ops::IndexMut<ops::RangeToInclusive<usize>> for str {
+        #[inline]
+        fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
+            // SNAP 4d3eebf change this to `0...index.end`
+            self.index_mut(ops::RangeInclusive::NonEmpty { start: 0, end: index.end })
+        }
+    }
 }
 
 /// Methods for string slices
@@ -1589,12 +1683,30 @@ pub trait StrExt {
     fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
 }
 
+// truncate `&str` to length at most equal to `max`
+// return `true` if it were truncated, and the new str.
+fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
+    if max >= s.len() {
+        (false, s)
+    } else {
+        while !s.is_char_boundary(max) {
+            max -= 1;
+        }
+        (true, &s[..max])
+    }
+}
+
 #[inline(never)]
 #[cold]
 fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
-    assert!(begin <= end);
-    panic!("index {} and/or {} in `{}` do not lie on character boundary",
-          begin, end, s);
+    const MAX_DISPLAY_LENGTH: usize = 256;
+    let (truncated, s) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
+    let ellipsis = if truncated { "[...]" } else { "" };
+
+    assert!(begin <= end, "begin <= end ({} <= {}) when slicing `{}`{}",
+            begin, end, s, ellipsis);
+    panic!("index {} and/or {} in `{}`{} do not lie on character boundary",
+          begin, end, s, ellipsis);
 }
 
 #[stable(feature = "core", since = "1.6.0")]
diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index fe059076926..884f4490d9f 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -92,11 +92,6 @@
 #![deny(missing_docs)]
 #![feature(staged_api)]
 #![feature(str_char)]
-#![cfg_attr(test, feature(rustc_private))]
-
-#[cfg(test)]
-#[macro_use]
-extern crate log;
 
 use self::Name::*;
 use self::HasArg::*;
@@ -1544,8 +1539,6 @@ Options:
 
         let generated_usage = usage("Usage: fruits", &optgroups);
 
-        debug!("expected: <<{}>>", expected);
-        debug!("generated: <<{}>>", generated_usage);
         assert_eq!(generated_usage, expected);
     }
 
@@ -1573,8 +1566,6 @@ Options:
 
         let usage = usage("Usage: fruits", &optgroups);
 
-        debug!("expected: <<{}>>", expected);
-        debug!("generated: <<{}>>", usage);
         assert!(usage == expected)
     }
 
@@ -1601,8 +1592,6 @@ Options:
 
         let usage = usage("Usage: fruits", &optgroups);
 
-        debug!("expected: <<{}>>", expected);
-        debug!("generated: <<{}>>", usage);
         assert!(usage == expected)
     }
 
@@ -1617,8 +1606,6 @@ Options:
         let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string();
         let generated_usage = short_usage("fruits", &optgroups);
 
-        debug!("expected: <<{}>>", expected);
-        debug!("generated: <<{}>>", generated_usage);
         assert_eq!(generated_usage, expected);
     }
 
diff --git a/src/liblibc b/src/liblibc
-Subproject 07a92067930670473dc53300dfdda23ff486344
+Subproject 2278a549559c38872b4338cb002ecc2a80d860d
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index 531be63b7bb..e943f861e9d 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -36,16 +36,13 @@
 #![feature(custom_attribute)]
 #![allow(unused_attributes)]
 
-#![cfg_attr(test, feature(test, rand, rustc_private))]
+#![cfg_attr(test, feature(test, rand))]
 
 #![allow(deprecated)]
 
 #[cfg(test)]
 #[macro_use]
 extern crate std;
-#[cfg(test)]
-#[macro_use]
-extern crate log;
 
 use core::f64;
 use core::intrinsics;
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 4bb69a2688a..97a550a4076 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -148,6 +148,12 @@ declare_lint! {
     "uses of #[derive] with raw pointers are rarely correct"
 }
 
+declare_lint! {
+    pub TRANSMUTE_FROM_FN_ITEM_TYPES,
+    Warn,
+    "transmute from function item type to pointer-sized type erroneously allowed"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -177,7 +183,8 @@ impl LintPass for HardwiredLints {
             INVALID_TYPE_PARAM_DEFAULT,
             MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
             CONST_ERR,
-            RAW_POINTER_DERIVE
+            RAW_POINTER_DERIVE,
+            TRANSMUTE_FROM_FN_ITEM_TYPES
         )
     }
 }
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index d492f692703..c11e9dc822e 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -489,9 +489,14 @@ pub trait LintContext: Sized {
 
     fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
         self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls {
-            &(Warn, src) => {
+            &(Warn, _) => {
                 let lint_id = LintId::of(builtin::WARNINGS);
-                (self.lints().get_level_source(lint_id).0, src)
+                let warn_src = self.lints().get_level_source(lint_id);
+                if warn_src.0 != Warn {
+                    warn_src
+                } else {
+                    *ls
+                }
             }
             _ => *ls
         })
@@ -1282,6 +1287,9 @@ pub fn check_crate(tcx: &TyCtxt, access_levels: &AccessLevels) {
     }
 
     *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
+
+    // Put the lint store back in the session.
+    mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
 }
 
 pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index a6fb5c02f54..1fb27261c4d 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -317,12 +317,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.call(expr, pred, &l, Some(&**r).into_iter())
             }
 
-            hir::ExprRange(ref start, ref end) => {
-                let fields = start.as_ref().map(|e| &**e).into_iter()
-                    .chain(end.as_ref().map(|e| &**e));
-                self.straightline(expr, pred, fields)
-            }
-
             hir::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => {
                 self.call(expr, pred, &e, None::<hir::Expr>.iter())
             }
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index be8793bac5d..1f79e76f3ac 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -344,6 +344,10 @@ fn check_arms(cx: &MatchCheckCtxt,
                         hir::MatchSource::Normal => {
                             span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern")
                         },
+
+                        hir::MatchSource::TryDesugar => {
+                            cx.tcx.sess.span_bug(pat.span, "unreachable try pattern")
+                        },
                     }
                 }
                 Useful => (),
@@ -1047,10 +1051,7 @@ fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option<A>
 {
     let pats = Matrix(vec!(vec!(pat)));
     match is_useful(cx, &pats, &[DUMMY_WILD_PAT], ConstructWitness) {
-        UsefulWithWitness(pats) => {
-            assert_eq!(pats.len(), 1);
-            Some(refutable(&pats[0]))
-        },
+        UsefulWithWitness(pats) => Some(refutable(&pats[0])),
         NotUseful => None,
         Useful => unreachable!()
     }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 3af987df3a8..193492ee7e1 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -137,6 +137,7 @@ pub trait CrateStore<'tcx> : Any {
     // item info
     fn stability(&self, def: DefId) -> Option<attr::Stability>;
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
+    fn visibility(&self, def: DefId) -> hir::Visibility;
     fn closure_kind(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
                     -> ty::ClosureKind;
     fn closure_ty(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
@@ -302,6 +303,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     // item info
     fn stability(&self, def: DefId) -> Option<attr::Stability> { unimplemented!() }
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { unimplemented!() }
+    fn visibility(&self, def: DefId) -> hir::Visibility { unimplemented!() }
     fn closure_kind(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
                     -> ty::ClosureKind  { unimplemented!() }
     fn closure_ty(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index e3d05388f52..e6821cf639e 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -44,7 +44,8 @@ enum RootUnsafeContext {
 
 fn type_is_unsafe_function(ty: Ty) -> bool {
     match ty.sty {
-        ty::TyBareFn(_, ref f) => f.unsafety == hir::Unsafety::Unsafe,
+        ty::TyFnDef(_, _, ref f) |
+        ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe,
         _ => false,
     }
 }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 8b042e73e79..a87ce1206b4 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -398,11 +398,6 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
                 }
             }
 
-            hir::ExprRange(ref start, ref end) => {
-                start.as_ref().map(|e| self.consume_expr(&e));
-                end.as_ref().map(|e| self.consume_expr(&e));
-            }
-
             hir::ExprCall(ref callee, ref args) => {    // callee(args)
                 self.walk_callee(expr, &callee);
                 self.consume_exprs(args);
@@ -561,7 +556,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
                callee, callee_ty);
         let call_scope = self.tcx().region_maps.node_extent(call.id);
         match callee_ty.sty {
-            ty::TyBareFn(..) => {
+            ty::TyFnDef(..) | ty::TyFnPtr(_) => {
                 self.consume_expr(callee);
             }
             ty::TyError => { }
diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs
index b64fa688d51..6c0dd9b608d 100644
--- a/src/librustc/middle/infer/freshen.rs
+++ b/src/librustc/middle/infer/freshen.rs
@@ -161,7 +161,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             ty::TySlice(..) |
             ty::TyRawPtr(..) |
             ty::TyRef(..) |
-            ty::TyBareFn(..) |
+            ty::TyFnDef(..) |
+            ty::TyFnPtr(_) |
             ty::TyTrait(..) |
             ty::TyStruct(..) |
             ty::TyClosure(..) |
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index b9a5b32b71d..1e3546269db 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -454,7 +454,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                          -> UnitResult<'tcx>
 {
     debug!("mk_eqty({:?} <: {:?})", a, b);
-    cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
+    cx.eq_types(a_is_expected, origin, a, b)
 }
 
 pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
@@ -466,7 +466,7 @@ pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
 {
     debug!("mk_eq_trait_refs({:?} <: {:?})",
            a, b);
-    cx.commit_if_ok(|_| cx.eq_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
+    cx.eq_trait_refs(a_is_expected, origin, a, b)
 }
 
 pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
@@ -478,7 +478,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
 {
     debug!("mk_sub_poly_trait_refs({:?} <: {:?})",
            a, b);
-    cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
+    cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
 }
 
 fn expected_found<T>(a_is_expected: bool,
@@ -1351,18 +1351,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn report_mismatched_types(&self,
-                                   span: Span,
+                                   origin: TypeOrigin,
                                    expected: Ty<'tcx>,
                                    actual: Ty<'tcx>,
-                                   err: &TypeError<'tcx>) {
+                                   err: TypeError<'tcx>) {
         let trace = TypeTrace {
-            origin: TypeOrigin::Misc(span),
+            origin: origin,
             values: Types(ExpectedFound {
                 expected: expected,
                 found: actual
             })
         };
-        self.report_and_explain_type_error(trace, err);
+        self.report_and_explain_type_error(trace, &err);
     }
 
     pub fn report_conflicting_default_types(&self,
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 7de8904e3f2..fd857513e5b 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -12,7 +12,7 @@ use dep_graph::DepNode;
 use middle::def::Def;
 use middle::def_id::DefId;
 use middle::subst::{Subst, Substs, EnumeratedItems};
-use middle::ty::{TransmuteRestriction, TyCtxt, TyBareFn};
+use middle::ty::{TransmuteRestriction, TyCtxt};
 use middle::ty::{self, Ty, TypeFoldable};
 
 use std::fmt;
@@ -53,7 +53,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
 impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
         let intrinsic = match self.tcx.lookup_item_type(def_id).ty.sty {
-            ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic,
+            ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic,
             _ => return false
         };
         intrinsic && self.tcx.item_name(def_id).as_str() == "transmute"
@@ -238,7 +238,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
                 Def::Fn(did) if self.def_id_is_transmute(did) => {
                     let typ = self.tcx.node_id_to_type(expr.id);
                     match typ.sty {
-                        TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
+                        ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
                             if let ty::FnConverging(to) = bare_fn_ty.sig.0.output {
                                 let from = bare_fn_ty.sig.0.inputs[0];
                                 self.check_transmute(expr.span, from, to, expr.id);
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 6cbb90627ea..c432095ff06 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -32,7 +32,6 @@ use util::nodemap::FnvHashMap;
 
 use syntax::ast;
 use syntax::attr::AttrMetaMethods;
-use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::InternedString;
 use rustc_front::intravisit::Visitor;
 use rustc_front::hir;
@@ -120,9 +119,9 @@ impl LanguageItems {
 
     pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
         let def_id_kinds = [
-            (self.fn_trait(), ty::FnClosureKind),
-            (self.fn_mut_trait(), ty::FnMutClosureKind),
-            (self.fn_once_trait(), ty::FnOnceClosureKind),
+            (self.fn_trait(), ty::ClosureKind::Fn),
+            (self.fn_mut_trait(), ty::ClosureKind::FnMut),
+            (self.fn_once_trait(), ty::ClosureKind::FnOnce),
             ];
 
         for &(opt_def_id, kind) in &def_id_kinds {
@@ -158,7 +157,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
             let item_index = self.item_refs.get(&value[..]).cloned();
 
             if let Some(item_index) = item_index {
-                self.collect_item(item_index, self.ast_map.local_def_id(item.id), item.span)
+                self.collect_item(item_index, self.ast_map.local_def_id(item.id))
             }
         }
     }
@@ -180,15 +179,26 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
     }
 
     pub fn collect_item(&mut self, item_index: usize,
-                        item_def_id: DefId, span: Span) {
+                        item_def_id: DefId) {
         // Check for duplicates.
         match self.items.items[item_index] {
             Some(original_def_id) if original_def_id != item_def_id => {
                 let cstore = &self.session.cstore;
-                span_err!(self.session, span, E0152,
-                          "duplicate entry for `{}`, first definition found in `{}`",
-                          LanguageItems::item_name(item_index),
-                          cstore.crate_name(item_def_id.krate));
+                let span = self.ast_map.span_if_local(item_def_id)
+                                       .expect("we should have found local duplicate earlier");
+                let mut err = struct_span_err!(self.session,
+                                               span,
+                                               E0152,
+                                               "duplicate lang item found: `{}`.",
+                                               LanguageItems::item_name(item_index));
+                if let Some(span) = self.ast_map.span_if_local(original_def_id) {
+                    span_note!(&mut err, span,
+                               "first defined here.");
+                } else {
+                    err.note(&format!("first defined in crate `{}`.",
+                                      cstore.crate_name(original_def_id.krate)));
+                }
+                err.emit();
             }
             _ => {
                 // OK.
@@ -205,17 +215,18 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
 
     pub fn collect_external_language_items(&mut self) {
         let cstore = &self.session.cstore;
+
         for cnum in cstore.crates() {
             for (index, item_index) in cstore.lang_items(cnum) {
                 let def_id = DefId { krate: cnum, index: index };
-                self.collect_item(item_index, def_id, DUMMY_SP);
+                self.collect_item(item_index, def_id);
             }
         }
     }
 
     pub fn collect(&mut self, krate: &hir::Crate) {
-        self.collect_local_language_items(krate);
         self.collect_external_language_items();
+        self.collect_local_language_items(krate);
     }
 }
 
@@ -302,10 +313,6 @@ lets_do_this! {
     ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
     IndexTraitLangItem,              "index",                   index_trait;
     IndexMutTraitLangItem,           "index_mut",               index_mut_trait;
-    RangeStructLangItem,             "range",                   range_struct;
-    RangeFromStructLangItem,         "range_from",              range_from_struct;
-    RangeToStructLangItem,           "range_to",                range_to_struct;
-    RangeFullStructLangItem,         "range_full",              range_full_struct;
 
     UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 81f0cb1fbb2..04240bf2875 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -498,7 +498,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
       hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) |
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
       hir::ExprInlineAsm(..) | hir::ExprBox(..) |
-      hir::ExprRange(..) | hir::ExprType(..) => {
+      hir::ExprType(..) => {
           intravisit::walk_expr(ir, expr);
       }
     }
@@ -1086,11 +1086,17 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           }
 
           hir::ExprAssignOp(_, ref l, ref r) => {
-            // see comment on lvalues in
-            // propagate_through_lvalue_components()
-            let succ = self.write_lvalue(&l, succ, ACC_WRITE|ACC_READ);
-            let succ = self.propagate_through_expr(&r, succ);
-            self.propagate_through_lvalue_components(&l, succ)
+            // an overloaded assign op is like a method call
+            if self.ir.tcx.is_method_call(expr.id) {
+                let succ = self.propagate_through_expr(&l, succ);
+                self.propagate_through_expr(&r, succ)
+            } else {
+                // see comment on lvalues in
+                // propagate_through_lvalue_components()
+                let succ = self.write_lvalue(&l, succ, ACC_WRITE|ACC_READ);
+                let succ = self.propagate_through_expr(&r, succ);
+                self.propagate_through_lvalue_components(&l, succ)
+            }
           }
 
           // Uninteresting cases: just propagate in rev exec order
@@ -1154,11 +1160,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_expr(&l, r_succ)
           }
 
-          hir::ExprRange(ref e1, ref e2) => {
-            let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&e, succ));
-            e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&e, succ))
-          }
-
           hir::ExprBox(ref e) |
           hir::ExprAddrOf(_, ref e) |
           hir::ExprCast(ref e, _) |
@@ -1415,7 +1416,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       }
 
       hir::ExprAssignOp(_, ref l, _) => {
-        this.check_lvalue(&l);
+        if !this.ir.tcx.is_method_call(expr.id) {
+            this.check_lvalue(&l);
+        }
 
         intravisit::walk_expr(this, expr);
       }
@@ -1446,7 +1449,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       hir::ExprBlock(..) | hir::ExprAddrOf(..) |
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
       hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) |
-      hir::ExprRange(..) | hir::ExprType(..) => {
+      hir::ExprType(..) => {
         intravisit::walk_expr(this, expr);
       }
     }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 11ef1dbd705..9fc240fd495 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -526,7 +526,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
           hir::ExprAddrOf(..) | hir::ExprCall(..) |
           hir::ExprAssign(..) | hir::ExprAssignOp(..) |
           hir::ExprClosure(..) | hir::ExprRet(..) |
-          hir::ExprUnary(..) | hir::ExprRange(..) |
+          hir::ExprUnary(..) |
           hir::ExprMethodCall(..) | hir::ExprCast(..) |
           hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprIf(..) |
           hir::ExprBinary(..) | hir::ExprWhile(..) |
@@ -670,13 +670,13 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
         // conceptually a `&mut` or `&` reference, so we have to add a
         // deref.
         let cmt_result = match kind {
-            ty::FnOnceClosureKind => {
+            ty::ClosureKind::FnOnce => {
                 cmt_result
             }
-            ty::FnMutClosureKind => {
+            ty::ClosureKind::FnMut => {
                 self.env_deref(id, span, upvar_id, var_mutbl, ty::MutBorrow, cmt_result)
             }
-            ty::FnClosureKind => {
+            ty::ClosureKind::Fn => {
                 self.env_deref(id, span, upvar_id, var_mutbl, ty::ImmBorrow, cmt_result)
             }
         };
@@ -1630,9 +1630,9 @@ impl fmt::Debug for Upvar {
 impl fmt::Display for Upvar {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let kind = match self.kind {
-            ty::FnClosureKind => "Fn",
-            ty::FnMutClosureKind => "FnMut",
-            ty::FnOnceClosureKind => "FnOnce",
+            ty::ClosureKind::Fn => "Fn",
+            ty::ClosureKind::FnMut => "FnMut",
+            ty::ClosureKind::FnOnce => "FnOnce",
         };
         write!(f, "captured outer variable in an `{}` closure", kind)
     }
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 9cc94402b16..02dfeb80b92 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -148,11 +148,11 @@ impl<'tcx> Substs<'tcx> {
         Substs { types: types, regions: regions }
     }
 
-    pub fn with_method_from(self,
+    pub fn with_method_from(&self,
                             meth_substs: &Substs<'tcx>)
                             -> Substs<'tcx>
     {
-        let Substs { types, regions } = self;
+        let Substs { types, regions } = self.clone();
         let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
         let regions = regions.map(|r| {
             r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace))
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index b0970457892..b79849e87ff 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -301,7 +301,8 @@ fn ty_is_local_constructor<'tcx>(tcx: &TyCtxt<'tcx>,
         ty::TyUint(..) |
         ty::TyFloat(..) |
         ty::TyStr |
-        ty::TyBareFn(..) |
+        ty::TyFnDef(..) |
+        ty::TyFnPtr(_) |
         ty::TyArray(..) |
         ty::TySlice(..) |
         ty::TyRawPtr(..) |
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index f0ff0380aaa..8a2f0c0c093 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -278,7 +278,7 @@ pub enum Vtable<'tcx, N> {
 #[derive(Clone, PartialEq, Eq)]
 pub struct VtableImplData<'tcx, N> {
     pub impl_def_id: DefId,
-    pub substs: subst::Substs<'tcx>,
+    pub substs: &'tcx subst::Substs<'tcx>,
     pub nested: Vec<N>
 }
 
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index b19771420bd..e36307feddb 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -948,7 +948,7 @@ fn confirm_impl_candidate<'cx,'tcx>(
     for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
         if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
             if assoc_ty.name == obligation.predicate.item_name {
-                return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs),
+                return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs),
                         impl_vtable.nested);
             }
         }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 373ec37663f..2ecfa119007 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -1286,7 +1286,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             // provide an impl, but only for suitable `fn` pointers
-            ty::TyBareFn(_, &ty::BareFnTy {
+            ty::TyFnDef(_, _, &ty::BareFnTy {
+                unsafety: hir::Unsafety::Normal,
+                abi: Abi::Rust,
+                sig: ty::Binder(ty::FnSig {
+                    inputs: _,
+                    output: ty::FnConverging(_),
+                    variadic: false
+                })
+            }) |
+            ty::TyFnPtr(&ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -1646,7 +1655,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::TyInt(_) |
             ty::TyBool |
             ty::TyFloat(_) |
-            ty::TyBareFn(..) |
+            ty::TyFnDef(..) |
+            ty::TyFnPtr(_) |
             ty::TyChar => {
                 // safe for everything
                 ok_if(Vec::new())
@@ -1850,7 +1860,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::TyInt(_) |
             ty::TyBool |
             ty::TyFloat(_) |
-            ty::TyBareFn(..) |
+            ty::TyFnDef(..) |
+            ty::TyFnPtr(_) |
             ty::TyStr |
             ty::TyError |
             ty::TyInfer(ty::IntVar(_)) |
@@ -2294,7 +2305,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         impl_obligations.append(&mut substs.obligations);
 
         VtableImplData { impl_def_id: impl_def_id,
-                         substs: substs.value,
+                         substs: self.tcx().mk_substs(substs.value),
                          nested: impl_obligations }
     }
 
diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs
index 453420e2a54..903b7c80baf 100644
--- a/src/librustc/middle/traits/structural_impls.rs
+++ b/src/librustc/middle/traits/structural_impls.rs
@@ -147,9 +147,10 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
 
 impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
     fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let substs = self.substs.fold_with(folder);
         traits::VtableImplData {
             impl_def_id: self.impl_def_id,
-            substs: self.substs.fold_with(folder),
+            substs: folder.tcx().mk_substs(substs),
             nested: self.nested.fold_with(folder),
         }
     }
diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs
index 40581cfa1c5..e4c293a74e8 100644
--- a/src/librustc/middle/ty/adjustment.rs
+++ b/src/librustc/middle/ty/adjustment.rs
@@ -155,8 +155,8 @@ impl<'tcx> ty::TyS<'tcx> {
                 match *adjustment {
                     AdjustReifyFnPointer => {
                         match self.sty {
-                            ty::TyBareFn(Some(_), b) => {
-                                cx.mk_fn(None, b)
+                            ty::TyFnDef(_, _, b) => {
+                                cx.mk_ty(ty::TyFnPtr(b))
                             }
                             _ => {
                                 cx.sess.bug(
@@ -168,7 +168,7 @@ impl<'tcx> ty::TyS<'tcx> {
 
                     AdjustUnsafeFnPointer => {
                         match self.sty {
-                            ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
+                            ty::TyFnPtr(b) => cx.safe_to_unsafe_fn_ty(b),
                             ref b => {
                                 cx.sess.bug(
                                     &format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \
diff --git a/src/librustc/middle/ty/cast.rs b/src/librustc/middle/ty/cast.rs
index 8233b6b2b2b..b25d6e0476d 100644
--- a/src/librustc/middle/ty/cast.rs
+++ b/src/librustc/middle/ty/cast.rs
@@ -69,7 +69,7 @@ impl<'tcx> CastTy<'tcx> {
                 Some(CastTy::Int(IntTy::CEnum)),
             ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)),
             ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)),
-            ty::TyBareFn(..) => Some(CastTy::FnPtr),
+            ty::TyFnPtr(..) => Some(CastTy::FnPtr),
             _ => None,
         }
     }
diff --git a/src/librustc/middle/ty/contents.rs b/src/librustc/middle/ty/contents.rs
index 8dfa0262f2b..47a15a14b41 100644
--- a/src/librustc/middle/ty/contents.rs
+++ b/src/librustc/middle/ty/contents.rs
@@ -187,7 +187,7 @@ impl<'tcx> ty::TyS<'tcx> {
                 // Scalar and unique types are sendable, and durable
                 ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
                 ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
-                ty::TyBareFn(..) | ty::TyChar => {
+                ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => {
                     TC::None
                 }
 
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
index ffc52af19bb..61a7f49f45d 100644
--- a/src/librustc/middle/ty/context.rs
+++ b/src/librustc/middle/ty/context.rs
@@ -41,7 +41,6 @@ use std::borrow::Borrow;
 use std::cell::{Cell, RefCell, Ref};
 use std::hash::{Hash, Hasher};
 use std::rc::Rc;
-use syntax::abi::Abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::parse::token::special_idents;
@@ -734,8 +733,8 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn print_debug_stats(&self) {
         sty_debug_print!(
             self,
-            TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait,
-            TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
+            TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
+            TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
 
         println!("Substs interner: #{}", self.substs_interner.borrow().len());
         println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
@@ -792,12 +791,11 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Create an unsafe fn ty based on a safe fn ty.
     pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
         assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
-        let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy {
+        self.mk_fn_ptr(ty::BareFnTy {
             unsafety: hir::Unsafety::Unsafe,
             abi: bare_fn.abi,
             sig: bare_fn.sig.clone()
-        });
-        self.mk_fn(None, unsafe_fn_ty_a)
+        })
     }
 
     pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
@@ -946,26 +944,14 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_ty(TyBool)
     }
 
-    pub fn mk_fn(&self,
-                 opt_def_id: Option<DefId>,
-                 fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TyBareFn(opt_def_id, fty))
-    }
-
-    pub fn mk_ctor_fn(&self,
-                      def_id: DefId,
-                      input_tys: &[Ty<'tcx>],
-                      output: Ty<'tcx>) -> Ty<'tcx> {
-        let input_args = input_tys.iter().cloned().collect();
-        self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy {
-            unsafety: hir::Unsafety::Normal,
-            abi: Abi::Rust,
-            sig: ty::Binder(ty::FnSig {
-                inputs: input_args,
-                output: ty::FnConverging(output),
-                variadic: false
-            })
-        }))
+    pub fn mk_fn_def(&self, def_id: DefId,
+                     substs: &'tcx Substs<'tcx>,
+                     fty: BareFnTy<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyFnDef(def_id, substs, self.mk_bare_fn(fty)))
+    }
+
+    pub fn mk_fn_ptr(&self, fty: BareFnTy<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyFnPtr(self.mk_bare_fn(fty)))
     }
 
     pub fn mk_trait(&self,
diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs
index 39a5069e129..1033af5f331 100644
--- a/src/librustc/middle/ty/error.rs
+++ b/src/librustc/middle/ty/error.rs
@@ -223,8 +223,8 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::TySlice(_) => "slice".to_string(),
             ty::TyRawPtr(_) => "*-ptr".to_string(),
             ty::TyRef(_, _) => "&-ptr".to_string(),
-            ty::TyBareFn(Some(_), _) => format!("fn item"),
-            ty::TyBareFn(None, _) => "fn pointer".to_string(),
+            ty::TyFnDef(..) => format!("fn item"),
+            ty::TyFnPtr(_) => "fn pointer".to_string(),
             ty::TyTrait(ref inner) => {
                 format!("trait {}", cx.item_path_str(inner.principal_def_id()))
             }
diff --git a/src/librustc/middle/ty/fast_reject.rs b/src/librustc/middle/ty/fast_reject.rs
index a42e5fc2e85..fc4db22a8a6 100644
--- a/src/librustc/middle/ty/fast_reject.rs
+++ b/src/librustc/middle/ty/fast_reject.rs
@@ -83,7 +83,7 @@ pub fn simplify_type(tcx: &TyCtxt,
         ty::TyTuple(ref tys) => {
             Some(TupleSimplifiedType(tys.len()))
         }
-        ty::TyBareFn(_, ref f) => {
+        ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
             Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
         }
         ty::TyProjection(_) | ty::TyParam(_) => {
diff --git a/src/librustc/middle/ty/flags.rs b/src/librustc/middle/ty/flags.rs
index a0b03fe8126..c491bd6ca5e 100644
--- a/src/librustc/middle/ty/flags.rs
+++ b/src/librustc/middle/ty/flags.rs
@@ -134,7 +134,12 @@ impl FlagComputation {
                 self.add_tys(&ts[..]);
             }
 
-            &ty::TyBareFn(_, ref f) => {
+            &ty::TyFnDef(_, substs, ref f) => {
+                self.add_substs(substs);
+                self.add_fn_sig(&f.sig);
+            }
+
+            &ty::TyFnPtr(ref f) => {
                 self.add_fn_sig(&f.sig);
             }
         }
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index 85035b25001..2e38080bfb0 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 pub use self::ImplOrTraitItemId::*;
-pub use self::ClosureKind::*;
 pub use self::Variance::*;
 pub use self::DtorKind::*;
 pub use self::ImplOrTraitItemContainer::*;
@@ -1699,19 +1698,19 @@ pub enum ClosureKind {
     // Warning: Ordering is significant here! The ordering is chosen
     // because the trait Fn is a subtrait of FnMut and so in turn, and
     // hence we order it so that Fn < FnMut < FnOnce.
-    FnClosureKind,
-    FnMutClosureKind,
-    FnOnceClosureKind,
+    Fn,
+    FnMut,
+    FnOnce,
 }
 
 impl ClosureKind {
     pub fn trait_did(&self, cx: &TyCtxt) -> DefId {
         let result = match *self {
-            FnClosureKind => cx.lang_items.require(FnTraitLangItem),
-            FnMutClosureKind => {
+            ClosureKind::Fn => cx.lang_items.require(FnTraitLangItem),
+            ClosureKind::FnMut => {
                 cx.lang_items.require(FnMutTraitLangItem)
             }
-            FnOnceClosureKind => {
+            ClosureKind::FnOnce => {
                 cx.lang_items.require(FnOnceTraitLangItem)
             }
         };
@@ -1725,12 +1724,12 @@ impl ClosureKind {
     /// must also implement `other`.
     pub fn extends(self, other: ty::ClosureKind) -> bool {
         match (self, other) {
-            (FnClosureKind, FnClosureKind) => true,
-            (FnClosureKind, FnMutClosureKind) => true,
-            (FnClosureKind, FnOnceClosureKind) => true,
-            (FnMutClosureKind, FnMutClosureKind) => true,
-            (FnMutClosureKind, FnOnceClosureKind) => true,
-            (FnOnceClosureKind, FnOnceClosureKind) => true,
+            (ClosureKind::Fn, ClosureKind::Fn) => true,
+            (ClosureKind::Fn, ClosureKind::FnMut) => true,
+            (ClosureKind::Fn, ClosureKind::FnOnce) => true,
+            (ClosureKind::FnMut, ClosureKind::FnMut) => true,
+            (ClosureKind::FnMut, ClosureKind::FnOnce) => true,
+            (ClosureKind::FnOnce, ClosureKind::FnOnce) => true,
             _ => false,
         }
     }
@@ -2008,7 +2007,6 @@ impl<'tcx> TyCtxt<'tcx> {
             hir::ExprCall(..) |
             hir::ExprMethodCall(..) |
             hir::ExprStruct(..) |
-            hir::ExprRange(..) |
             hir::ExprTup(..) |
             hir::ExprIf(..) |
             hir::ExprMatch(..) |
diff --git a/src/librustc/middle/ty/outlives.rs b/src/librustc/middle/ty/outlives.rs
index fc20c1bcb85..9439180a6cd 100644
--- a/src/librustc/middle/ty/outlives.rs
+++ b/src/librustc/middle/ty/outlives.rs
@@ -182,7 +182,8 @@ fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
         ty::TyRawPtr(..) |      // ...
         ty::TyRef(..) |         // OutlivesReference
         ty::TyTuple(..) |       // ...
-        ty::TyBareFn(..) |      // OutlivesFunction (*)
+        ty::TyFnDef(..) |       // OutlivesFunction (*)
+        ty::TyFnPtr(_) |        // OutlivesFunction (*)
         ty::TyTrait(..) |       // OutlivesObject, OutlivesFragment (*)
         ty::TyError => {
             // (*) Bare functions and traits are both binders. In the
diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs
index 5d6106a6d77..6da65c85f91 100644
--- a/src/librustc/middle/ty/relate.rs
+++ b/src/librustc/middle/ty/relate.rs
@@ -139,11 +139,11 @@ fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R,
     relate_substs(relation, opt_variances, a_subst, b_subst)
 }
 
-fn relate_substs<'a,'tcx:'a,R>(relation: &mut R,
-                               variances: Option<&ty::ItemVariances>,
-                               a_subst: &Substs<'tcx>,
-                               b_subst: &Substs<'tcx>)
-                               -> RelateResult<'tcx, Substs<'tcx>>
+pub fn relate_substs<'a,'tcx:'a,R>(relation: &mut R,
+                                   variances: Option<&ty::ItemVariances>,
+                                   a_subst: &Substs<'tcx>,
+                                   b_subst: &Substs<'tcx>)
+                                   -> RelateResult<'tcx, Substs<'tcx>>
     where R: TypeRelation<'a,'tcx>
 {
     let mut substs = Substs::empty();
@@ -568,11 +568,19 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R,
             }
         }
 
-        (&ty::TyBareFn(a_opt_def_id, a_fty), &ty::TyBareFn(b_opt_def_id, b_fty))
-            if a_opt_def_id == b_opt_def_id =>
+        (&ty::TyFnDef(a_def_id, a_substs, a_fty),
+         &ty::TyFnDef(b_def_id, b_substs, b_fty))
+            if a_def_id == b_def_id =>
         {
+            let substs = try!(relate_substs(relation, None, a_substs, b_substs));
             let fty = try!(relation.relate(a_fty, b_fty));
-            Ok(tcx.mk_fn(a_opt_def_id, tcx.mk_bare_fn(fty)))
+            Ok(tcx.mk_fn_def(a_def_id, tcx.mk_substs(substs), fty))
+        }
+
+        (&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) =>
+        {
+            let fty = try!(relation.relate(a_fty, b_fty));
+            Ok(tcx.mk_fn_ptr(fty))
         }
 
         (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) =>
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
index 001ea02a27c..3fe9e02a90d 100644
--- a/src/librustc/middle/ty/structural_impls.rs
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -282,9 +282,16 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             }
             ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)),
             ty::TyTuple(ref ts) => ty::TyTuple(ts.fold_with(folder)),
-            ty::TyBareFn(opt_def_id, ref f) => {
+            ty::TyFnDef(def_id, substs, ref f) => {
+                let substs = substs.fold_with(folder);
+                let bfn = f.fold_with(folder);
+                ty::TyFnDef(def_id,
+                            folder.tcx().mk_substs(substs),
+                            folder.tcx().mk_bare_fn(bfn))
+            }
+            ty::TyFnPtr(ref f) => {
                 let bfn = f.fold_with(folder);
-                ty::TyBareFn(opt_def_id, folder.tcx().mk_bare_fn(bfn))
+                ty::TyFnPtr(folder.tcx().mk_bare_fn(bfn))
             }
             ty::TyRef(r, ref tm) => {
                 let r = r.fold_with(folder);
@@ -318,7 +325,10 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor),
             ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor),
             ty::TyTuple(ref ts) => ts.visit_with(visitor),
-            ty::TyBareFn(_opt_def_id, ref f) => f.visit_with(visitor),
+            ty::TyFnDef(_, substs, ref f) => {
+                substs.visit_with(visitor) || f.visit_with(visitor)
+            }
+            ty::TyFnPtr(ref f) => f.visit_with(visitor),
             ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor),
             ty::TyStruct(_did, ref substs) => substs.visit_with(visitor),
             ty::TyClosure(_did, ref substs) => substs.visit_with(visitor),
diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs
index c8f8e073832..2d7b7dc6e9b 100644
--- a/src/librustc/middle/ty/sty.rs
+++ b/src/librustc/middle/ty/sty.rs
@@ -127,14 +127,14 @@ pub enum TypeVariants<'tcx> {
     /// `&a mut T` or `&'a T`.
     TyRef(&'tcx Region, TypeAndMut<'tcx>),
 
-    /// If the def-id is Some(_), then this is the type of a specific
-    /// fn item. Otherwise, if None(_), it is a fn pointer type.
-    ///
-    /// FIXME: Conflating function pointers and the type of a
-    /// function is probably a terrible idea; a function pointer is a
-    /// value with a specific type, but a function can be polymorphic
-    /// or dynamically dispatched.
-    TyBareFn(Option<DefId>, &'tcx BareFnTy<'tcx>),
+    /// The anonymous type of a function declaration/definition. Each
+    /// function has a unique type.
+    TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>),
+
+    /// A pointer to a function.  Written as `fn() -> i32`.
+    /// FIXME: This is currently also used to represent the callee of a method;
+    /// see ty::MethodCallee etc.
+    TyFnPtr(&'tcx BareFnTy<'tcx>),
 
     /// A trait, defined with `trait`.
     TyTrait(Box<TraitTy<'tcx>>),
@@ -1029,7 +1029,7 @@ impl<'tcx> TyS<'tcx> {
         match self.sty {
             TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) |
             TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) |
-            TyBareFn(..) | TyRawPtr(_) => true,
+            TyFnDef(..) | TyFnPtr(_) | TyRawPtr(_) => true,
             _ => false
         }
     }
@@ -1080,20 +1080,6 @@ impl<'tcx> TyS<'tcx> {
         }
     }
 
-    pub fn is_bare_fn(&self) -> bool {
-        match self.sty {
-            TyBareFn(..) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_bare_fn_item(&self) -> bool {
-        match self.sty {
-            TyBareFn(Some(_), _) => true,
-            _ => false
-        }
-    }
-
     pub fn is_fp(&self) -> bool {
         match self.sty {
             TyInfer(FloatVar(_)) | TyFloat(_) => true,
@@ -1154,7 +1140,7 @@ impl<'tcx> TyS<'tcx> {
 
     pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
         match self.sty {
-            TyBareFn(_, ref f) => &f.sig,
+            TyFnDef(_, _, ref f) | TyFnPtr(ref f) => &f.sig,
             _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self)
         }
     }
@@ -1162,7 +1148,7 @@ impl<'tcx> TyS<'tcx> {
     /// Returns the ABI of the given function.
     pub fn fn_abi(&self) -> abi::Abi {
         match self.sty {
-            TyBareFn(_, ref f) => f.abi,
+            TyFnDef(_, _, ref f) | TyFnPtr(ref f) => f.abi,
             _ => panic!("Ty::fn_abi() called on non-fn type"),
         }
     }
@@ -1178,7 +1164,7 @@ impl<'tcx> TyS<'tcx> {
 
     pub fn is_fn(&self) -> bool {
         match self.sty {
-            TyBareFn(..) => true,
+            TyFnDef(..) | TyFnPtr(_) => true,
             _ => false
         }
     }
@@ -1224,7 +1210,8 @@ impl<'tcx> TyS<'tcx> {
             TyProjection(ref data) => {
                 data.trait_ref.substs.regions().as_slice().to_vec()
             }
-            TyBareFn(..) |
+            TyFnDef(..) |
+            TyFnPtr(_) |
             TyBool |
             TyChar |
             TyInt(_) |
diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs
index 7c32d931fff..2b83aaccdc4 100644
--- a/src/librustc/middle/ty/util.rs
+++ b/src/librustc/middle/ty/util.rs
@@ -514,9 +514,12 @@ impl<'tcx> TyCtxt<'tcx> {
                         region(state, *r);
                         mt(state, m);
                     }
-                    TyBareFn(opt_def_id, ref b) => {
+                    TyFnDef(def_id, _, _) => {
                         byte!(14);
-                        hash!(opt_def_id);
+                        hash!(def_id);
+                    }
+                    TyFnPtr(ref b) => {
+                        byte!(15);
                         hash!(b.unsafety);
                         hash!(b.abi);
                         fn_sig(state, &b.sig);
@@ -599,14 +602,14 @@ impl<'tcx> TyCtxt<'tcx> {
 #[derive(Debug)]
 pub struct ImplMethod<'tcx> {
     pub method: Rc<ty::Method<'tcx>>,
-    pub substs: Substs<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
     pub is_provided: bool
 }
 
 impl<'tcx> TyCtxt<'tcx> {
     pub fn get_impl_method(&self,
                            impl_def_id: DefId,
-                           substs: Substs<'tcx>,
+                           substs: &'tcx Substs<'tcx>,
                            name: Name)
                            -> ImplMethod<'tcx>
     {
@@ -633,9 +636,10 @@ impl<'tcx> TyCtxt<'tcx> {
                 if meth.name == name {
                     let impl_to_trait_substs = self
                         .make_substs_for_receiver_types(&trait_ref, meth);
+                    let substs = impl_to_trait_substs.subst(self, substs);
                     return ImplMethod {
                         method: meth.clone(),
-                        substs: impl_to_trait_substs.subst(self, &substs),
+                        substs: self.mk_substs(substs),
                         is_provided: true
                     }
                 }
@@ -677,7 +681,7 @@ impl<'tcx> ty::TyS<'tcx> {
         // Fast-path for primitive types
         let result = match self.sty {
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
-            TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut {
+            TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut {
                 mutbl: hir::MutImmutable, ..
             }) => Some(false),
 
@@ -719,7 +723,7 @@ impl<'tcx> ty::TyS<'tcx> {
         // Fast-path for primitive types
         let result = match self.sty {
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
-            TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) |
+            TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
             TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true),
 
             TyStr | TyTrait(..) | TySlice(_) => Some(false),
diff --git a/src/librustc/middle/ty/walk.rs b/src/librustc/middle/ty/walk.rs
index 81cad448690..b6d93ecf78b 100644
--- a/src/librustc/middle/ty/walk.rs
+++ b/src/librustc/middle/ty/walk.rs
@@ -98,7 +98,11 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
         ty::TyTuple(ref ts) => {
             push_reversed(stack, ts);
         }
-        ty::TyBareFn(_, ref ft) => {
+        ty::TyFnDef(_, substs, ref ft) => {
+            push_reversed(stack, substs.types.as_slice());
+            push_sig_subtypes(stack, &ft.sig);
+        }
+        ty::TyFnPtr(ref ft) => {
             push_sig_subtypes(stack, &ft.sig);
         }
     }
diff --git a/src/librustc/middle/ty/wf.rs b/src/librustc/middle/ty/wf.rs
index c6d1bc8d649..5f81d27a1f6 100644
--- a/src/librustc/middle/ty/wf.rs
+++ b/src/librustc/middle/ty/wf.rs
@@ -354,8 +354,8 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> {
                     // WFedness.)
                 }
 
-                ty::TyBareFn(..) => {
-                    // let the loop iterator into the argument/return
+                ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+                    // let the loop iterate into the argument/return
                     // types appearing in the fn signature
                 }
 
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index ce7b1ceb355..4556611df59 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -861,20 +861,10 @@ impl<'tcx> Debug for TypedConstVal<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
-pub enum ItemKind {
-    Constant,
-    /// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This
-    /// includes functions, constructors, but not methods which have their own ItemKind.
-    Function,
-    Method,
-}
-
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Literal<'tcx> {
     Item {
         def_id: DefId,
-        kind: ItemKind,
         substs: &'tcx Substs<'tcx>,
     },
     Value {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 9c92208191e..8fd784cbde7 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -13,7 +13,7 @@ use middle::def_id::DefId;
 use middle::subst::{self, Subst};
 use middle::ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use middle::ty::{TyBool, TyChar, TyStruct, TyEnum};
-use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn};
+use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
 use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple};
 use middle::ty::TyClosure;
 use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
@@ -812,7 +812,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                 }
                 write!(f, ")")
             }
-            TyBareFn(opt_def_id, ref bare_fn) => {
+            TyFnDef(def_id, substs, ref bare_fn) => {
                 if bare_fn.unsafety == hir::Unsafety::Unsafe {
                     try!(write!(f, "unsafe "));
                 }
@@ -822,13 +822,30 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                 }
 
                 try!(write!(f, "{}", bare_fn.sig.0));
+                try!(ty::tls::with(|tcx| {
+                    write!(f, " {{{}", tcx.item_path_str(def_id))
+                }));
+
+                let tps = substs.types.get_slice(subst::FnSpace);
+                if tps.len() >= 1 {
+                    try!(write!(f, "::<{}", tps[0]));
+                    for &ty in &tps[1..] {
+                        try!(write!(f, ", {}", ty));
+                    }
+                    try!(write!(f, ">"));
+                }
+                write!(f, "}}")
+            }
+            TyFnPtr(ref bare_fn) => {
+                if bare_fn.unsafety == hir::Unsafety::Unsafe {
+                    try!(write!(f, "unsafe "));
+                }
 
-                if let Some(def_id) = opt_def_id {
-                    try!(write!(f, " {{{}}}", ty::tls::with(|tcx| {
-                        tcx.item_path_str(def_id)
-                    })));
+                if bare_fn.abi != Abi::Rust {
+                    try!(write!(f, "extern {} ", bare_fn.abi));
                 }
-                Ok(())
+
+                write!(f, "{}", bare_fn.sig.0)
             }
             TyInfer(infer_ty) => write!(f, "{}", infer_ty),
             TyError => write!(f, "[type error]"),
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index b2911630991..b01b80b8133 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -243,7 +243,6 @@ mod svh_visitor {
         SawExprAssign,
         SawExprAssignOp(hir::BinOp_),
         SawExprIndex,
-        SawExprRange,
         SawExprPath(Option<usize>),
         SawExprAddrOf(hir::Mutability),
         SawExprRet,
@@ -275,7 +274,6 @@ mod svh_visitor {
             ExprField(_, name)       => SawExprField(name.node.as_str()),
             ExprTupField(_, id)      => SawExprTupField(id.node),
             ExprIndex(..)            => SawExprIndex,
-            ExprRange(..)            => SawExprRange,
             ExprPath(ref qself, _)   => SawExprPath(qself.as_ref().map(|q| q.position)),
             ExprAddrOf(m, _)         => SawExprAddrOf(m),
             ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.name.as_str())),
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index ceaa6625fe2..cab8125a61b 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -1009,7 +1009,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                             Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
                             _ => unreachable!()
                         };
-                        if kind == ty::FnClosureKind {
+                        if kind == ty::ClosureKind::Fn {
                             db.span_help(
                                 self.tcx.map.span(upvar_id.closure_expr_id),
                                 "consider changing this closure to take \
diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs
index 7b5dacece8c..3677c8c5e59 100644
--- a/src/librustc_data_structures/bitvec.rs
+++ b/src/librustc_data_structures/bitvec.rs
@@ -10,7 +10,7 @@
 
 /// A very simple BitVector type.
 pub struct BitVector {
-    data: Vec<u64>
+    data: Vec<u64>,
 }
 
 impl BitVector {
@@ -40,7 +40,9 @@ impl BitVector {
         for (i, j) in self.data.iter_mut().zip(&all.data) {
             let value = *i;
             *i = value | *j;
-            if value != *i { changed = true; }
+            if value != *i {
+                changed = true;
+            }
         }
         changed
     }
@@ -56,7 +58,7 @@ impl BitVector {
         BitVectorIter {
             iter: self.data.iter(),
             current: 0,
-            idx: 0
+            idx: 0,
         }
     }
 }
@@ -64,7 +66,7 @@ impl BitVector {
 pub struct BitVectorIter<'a> {
     iter: ::std::slice::Iter<'a, u64>,
     current: u64,
-    idx: usize
+    idx: usize,
 }
 
 impl<'a> Iterator for BitVectorIter<'a> {
@@ -108,7 +110,7 @@ impl BitMatrix {
         let u64s_per_elem = u64s(elements);
         BitMatrix {
             elements: elements,
-            vector: vec![0; elements * u64s_per_elem]
+            vector: vec![0; elements * u64s_per_elem],
         }
     }
 
@@ -123,9 +125,9 @@ impl BitMatrix {
         let (start, _) = self.range(source);
         let (word, mask) = word_mask(target);
         let mut vector = &mut self.vector[..];
-        let v1 = vector[start+word];
+        let v1 = vector[start + word];
         let v2 = v1 | mask;
-        vector[start+word] = v2;
+        vector[start + word] = v2;
         v1 != v2
     }
 
@@ -136,7 +138,7 @@ impl BitMatrix {
     pub fn contains(&self, source: usize, target: usize) -> bool {
         let (start, _) = self.range(source);
         let (word, mask) = word_mask(target);
-        (self.vector[start+word] & mask) != 0
+        (self.vector[start + word] & mask) != 0
     }
 
     /// Returns those indices that are reachable from both `a` and
@@ -150,8 +152,12 @@ impl BitMatrix {
         for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() {
             let mut v = self.vector[i] & self.vector[j];
             for bit in 0..64 {
-                if v == 0 { break; }
-                if v & 0x1 != 0 { result.push(base*64 + bit); }
+                if v == 0 {
+                    break;
+                }
+                if v & 0x1 != 0 {
+                    result.push(base * 64 + bit);
+                }
                 v >>= 1;
             }
         }
@@ -170,9 +176,7 @@ impl BitMatrix {
         let (write_start, write_end) = self.range(write);
         let vector = &mut self.vector[..];
         let mut changed = false;
-        for (read_index, write_index) in
-            (read_start..read_end).zip(write_start..write_end)
-        {
+        for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) {
             let v1 = vector[write_index];
             let v2 = v1 | vector[read_index];
             vector[write_index] = v2;
@@ -204,7 +208,8 @@ fn bitvec_iter_works() {
     bitvec.insert(65);
     bitvec.insert(66);
     bitvec.insert(99);
-    assert_eq!(bitvec.iter().collect::<Vec<_>>(), [1, 10, 19, 62, 63, 64, 65, 66, 99]);
+    assert_eq!(bitvec.iter().collect::<Vec<_>>(),
+               [1, 10, 19, 62, 63, 64, 65, 66, 99]);
 }
 
 #[test]
@@ -217,7 +222,8 @@ fn bitvec_iter_works_2() {
     bitvec.insert(66);
     bitvec.insert(99);
     bitvec.insert(299);
-    assert_eq!(bitvec.iter().collect::<Vec<_>>(), [1, 10, 19, 62, 66, 99, 299]);
+    assert_eq!(bitvec.iter().collect::<Vec<_>>(),
+               [1, 10, 19, 62, 66, 99, 299]);
 
 }
 
diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs
index da5f9f20892..0000c283a7a 100644
--- a/src/librustc_data_structures/fnv.rs
+++ b/src/librustc_data_structures/fnv.rs
@@ -36,7 +36,9 @@ pub struct FnvHasher(u64);
 
 impl Default for FnvHasher {
     #[inline]
-    fn default() -> FnvHasher { FnvHasher(0xcbf29ce484222325) }
+    fn default() -> FnvHasher {
+        FnvHasher(0xcbf29ce484222325)
+    }
 }
 
 impl Hasher for FnvHasher {
@@ -51,5 +53,7 @@ impl Hasher for FnvHasher {
     }
 
     #[inline]
-    fn finish(&self) -> u64 { self.0 }
+    fn finish(&self) -> u64 {
+        self.0
+    }
 }
diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs
index f11856d7513..99a87d1e760 100644
--- a/src/librustc_data_structures/graph/mod.rs
+++ b/src/librustc_data_structures/graph/mod.rs
@@ -38,9 +38,9 @@ use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
 #[cfg(test)]
 mod tests;
 
-pub struct Graph<N,E> {
-    nodes: SnapshotVec<Node<N>> ,
-    edges: SnapshotVec<Edge<E>> ,
+pub struct Graph<N, E> {
+    nodes: SnapshotVec<Node<N>>,
+    edges: SnapshotVec<Edge<E>>,
 }
 
 pub struct Node<N> {
@@ -71,9 +71,13 @@ impl<N> SnapshotVecDelegate for Edge<N> {
 
 impl<E: Debug> Debug for Edge<E> {
     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}",
-               self.next_edge[0], self.next_edge[1], self.source,
-               self.target, self.data)
+        write!(f,
+               "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}",
+               self.next_edge[0],
+               self.next_edge[1],
+               self.source,
+               self.target,
+               self.data)
     }
 }
 
@@ -87,7 +91,9 @@ pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX);
 
 // Use a private field here to guarantee no more instances are created:
 #[derive(Copy, Clone, Debug, PartialEq)]
-pub struct Direction { repr: usize }
+pub struct Direction {
+    repr: usize,
+}
 
 pub const OUTGOING: Direction = Direction { repr: 0 };
 
@@ -95,24 +101,27 @@ pub const INCOMING: Direction = Direction { repr: 1 };
 
 impl NodeIndex {
     /// Returns unique id (unique with respect to the graph holding associated node).
-    pub fn node_id(&self) -> usize { self.0 }
+    pub fn node_id(&self) -> usize {
+        self.0
+    }
 }
 
 impl EdgeIndex {
     /// Returns unique id (unique with respect to the graph holding associated edge).
-    pub fn edge_id(&self) -> usize { self.0 }
+    pub fn edge_id(&self) -> usize {
+        self.0
+    }
 }
 
-impl<N:Debug,E:Debug> Graph<N,E> {
-    pub fn new() -> Graph<N,E> {
+impl<N: Debug, E: Debug> Graph<N, E> {
+    pub fn new() -> Graph<N, E> {
         Graph {
             nodes: SnapshotVec::new(),
             edges: SnapshotVec::new(),
         }
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // Simple accessors
+    // # Simple accessors
 
     #[inline]
     pub fn all_nodes(&self) -> &[Node<N>] {
@@ -134,8 +143,7 @@ impl<N:Debug,E:Debug> Graph<N,E> {
         self.edges.len()
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // Node construction
+    // # Node construction
 
     pub fn next_node_index(&self) -> NodeIndex {
         NodeIndex(self.nodes.len())
@@ -145,7 +153,7 @@ impl<N:Debug,E:Debug> Graph<N,E> {
         let idx = self.next_node_index();
         self.nodes.push(Node {
             first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX],
-            data: data
+            data: data,
         });
         idx
     }
@@ -162,26 +170,20 @@ impl<N:Debug,E:Debug> Graph<N,E> {
         &self.nodes[idx.0]
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // Edge construction and queries
+    // # Edge construction and queries
 
     pub fn next_edge_index(&self) -> EdgeIndex {
         EdgeIndex(self.edges.len())
     }
 
-    pub fn add_edge(&mut self,
-                    source: NodeIndex,
-                    target: NodeIndex,
-                    data: E) -> EdgeIndex {
+    pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex {
         debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data);
 
         let idx = self.next_edge_index();
 
         // read current first of the list of edges from each node
-        let source_first = self.nodes[source.0]
-                                     .first_edge[OUTGOING.repr];
-        let target_first = self.nodes[target.0]
-                                     .first_edge[INCOMING.repr];
+        let source_first = self.nodes[source.0].first_edge[OUTGOING.repr];
+        let target_first = self.nodes[target.0].first_edge[INCOMING.repr];
 
         // create the new edge, with the previous firsts from each node
         // as the next pointers
@@ -189,7 +191,7 @@ impl<N:Debug,E:Debug> Graph<N,E> {
             next_edge: [source_first, target_first],
             source: source,
             target: target,
-            data: data
+            data: data,
         });
 
         // adjust the firsts for each node target be the next object.
@@ -227,46 +229,48 @@ impl<N:Debug,E:Debug> Graph<N,E> {
         self.edges[edge.0].next_edge[dir.repr]
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // Iterating over nodes, edges
+    // # Iterating over nodes, edges
 
-    pub fn each_node<'a, F>(&'a self, mut f: F) -> bool where
-        F: FnMut(NodeIndex, &'a Node<N>) -> bool,
+    pub fn each_node<'a, F>(&'a self, mut f: F) -> bool
+        where F: FnMut(NodeIndex, &'a Node<N>) -> bool
     {
         //! Iterates over all edges defined in the graph.
         self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node))
     }
 
-    pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool where
-        F: FnMut(EdgeIndex, &'a Edge<E>) -> bool,
+    pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool
+        where F: FnMut(EdgeIndex, &'a Edge<E>) -> bool
     {
         //! Iterates over all edges defined in the graph
         self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge))
     }
 
-    pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<N,E> {
+    pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> {
         self.adjacent_edges(source, OUTGOING)
     }
 
-    pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<N,E> {
+    pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> {
         self.adjacent_edges(source, INCOMING)
     }
 
-    pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges<N,E> {
+    pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges<N, E> {
         let first_edge = self.node(source).first_edge[direction.repr];
-        AdjacentEdges { graph: self, direction: direction, next: first_edge }
+        AdjacentEdges {
+            graph: self,
+            direction: direction,
+            next: first_edge,
+        }
     }
 
-    pub fn successor_nodes(&self, source: NodeIndex) -> AdjacentTargets<N,E> {
+    pub fn successor_nodes(&self, source: NodeIndex) -> AdjacentTargets<N, E> {
         self.outgoing_edges(source).targets()
     }
 
-    pub fn predecessor_nodes(&self, target: NodeIndex) -> AdjacentSources<N,E> {
+    pub fn predecessor_nodes(&self, target: NodeIndex) -> AdjacentSources<N, E> {
         self.incoming_edges(target).sources()
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // Fixed-point iteration
+    // # Fixed-point iteration
     //
     // A common use for graphs in our compiler is to perform
     // fixed-point iteration. In this case, each edge represents a
@@ -274,8 +278,8 @@ impl<N:Debug,E:Debug> Graph<N,E> {
     // variables or other bitsets. This method facilitates such a
     // computation.
 
-    pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F) where
-        F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool,
+    pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F)
+        where F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool
     {
         let mut iteration = 0;
         let mut changed = true;
@@ -288,7 +292,7 @@ impl<N:Debug,E:Debug> Graph<N,E> {
         }
     }
 
-    pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E>  {
+    pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> {
         DepthFirstTraversal {
             graph: self,
             stack: vec![start],
@@ -297,28 +301,28 @@ impl<N:Debug,E:Debug> Graph<N,E> {
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// Iterators
+// # Iterators
 
-pub struct AdjacentEdges<'g,N,E>
-    where N:'g, E:'g
+pub struct AdjacentEdges<'g, N, E>
+    where N: 'g,
+          E: 'g
 {
     graph: &'g Graph<N, E>,
     direction: Direction,
     next: EdgeIndex,
 }
 
-impl<'g,N,E> AdjacentEdges<'g,N,E> {
-    fn targets(self) -> AdjacentTargets<'g,N,E> {
+impl<'g, N, E> AdjacentEdges<'g, N, E> {
+    fn targets(self) -> AdjacentTargets<'g, N, E> {
         AdjacentTargets { edges: self }
     }
 
-    fn sources(self) -> AdjacentSources<'g,N,E> {
+    fn sources(self) -> AdjacentSources<'g, N, E> {
         AdjacentSources { edges: self }
     }
 }
 
-impl<'g, N:Debug, E:Debug> Iterator for AdjacentEdges<'g, N, E> {
+impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
     type Item = (EdgeIndex, &'g Edge<E>);
 
     fn next(&mut self) -> Option<(EdgeIndex, &'g Edge<E>)> {
@@ -333,13 +337,14 @@ impl<'g, N:Debug, E:Debug> Iterator for AdjacentEdges<'g, N, E> {
     }
 }
 
-pub struct AdjacentTargets<'g,N:'g,E:'g>
-    where N:'g, E:'g
+pub struct AdjacentTargets<'g, N: 'g, E: 'g>
+    where N: 'g,
+          E: 'g
 {
-    edges: AdjacentEdges<'g,N,E>,
+    edges: AdjacentEdges<'g, N, E>,
 }
 
-impl<'g, N:Debug, E:Debug> Iterator for AdjacentTargets<'g, N, E> {
+impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> {
     type Item = NodeIndex;
 
     fn next(&mut self) -> Option<NodeIndex> {
@@ -347,13 +352,14 @@ impl<'g, N:Debug, E:Debug> Iterator for AdjacentTargets<'g, N, E> {
     }
 }
 
-pub struct AdjacentSources<'g,N:'g,E:'g>
-    where N:'g, E:'g
+pub struct AdjacentSources<'g, N: 'g, E: 'g>
+    where N: 'g,
+          E: 'g
 {
-    edges: AdjacentEdges<'g,N,E>,
+    edges: AdjacentEdges<'g, N, E>,
 }
 
-impl<'g, N:Debug, E:Debug> Iterator for AdjacentSources<'g, N, E> {
+impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> {
     type Item = NodeIndex;
 
     fn next(&mut self) -> Option<NodeIndex> {
@@ -361,13 +367,13 @@ impl<'g, N:Debug, E:Debug> Iterator for AdjacentSources<'g, N, E> {
     }
 }
 
-pub struct DepthFirstTraversal<'g, N:'g, E:'g> {
+pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
     graph: &'g Graph<N, E>,
     stack: Vec<NodeIndex>,
-    visited: BitVector
+    visited: BitVector,
 }
 
-impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> {
+impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
     type Item = NodeIndex;
 
     fn next(&mut self) -> Option<NodeIndex> {
@@ -389,8 +395,8 @@ impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> {
     }
 }
 
-pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F) where
-    F: FnMut(EdgeIndex) -> bool,
+pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F)
+    where F: FnMut(EdgeIndex) -> bool
 {
     let mut i = 0;
     let n = max_edge_index.0;
diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/tests.rs
index 33b2edd2e10..be7f48d27e0 100644
--- a/src/librustc_data_structures/graph/tests.rs
+++ b/src/librustc_data_structures/graph/tests.rs
@@ -64,11 +64,11 @@ fn each_edge() {
     });
 }
 
-fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
-                                                            start_index: NodeIndex,
-                                                            start_data: N,
-                                                            expected_incoming: &[(E,N)],
-                                                            expected_outgoing: &[(E,N)]) {
+fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(graph: &Graph<N, E>,
+                                                                   start_index: NodeIndex,
+                                                                   start_data: N,
+                                                                   expected_incoming: &[(E, N)],
+                                                                   expected_outgoing: &[(E, N)]) {
     assert!(graph.node_data(start_index) == &start_data);
 
     let mut counter = 0;
@@ -76,7 +76,10 @@ fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
         assert!(graph.edge_data(edge_index) == &edge.data);
         assert!(counter < expected_incoming.len());
         debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
-               counter, expected_incoming[counter], edge_index, edge);
+               counter,
+               expected_incoming[counter],
+               edge_index,
+               edge);
         match expected_incoming[counter] {
             (ref e, ref n) => {
                 assert!(e == &edge.data);
@@ -93,7 +96,10 @@ fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
         assert!(graph.edge_data(edge_index) == &edge.data);
         assert!(counter < expected_outgoing.len());
         debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
-               counter, expected_outgoing[counter], edge_index, edge);
+               counter,
+               expected_outgoing[counter],
+               edge_index,
+               edge);
         match expected_outgoing[counter] {
             (ref e, ref n) => {
                 assert!(e == &edge.data);
@@ -109,31 +115,27 @@ fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
 #[test]
 fn each_adjacent_from_a() {
     let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(0), "A",
-                        &[],
-                        &[("AB", "B")]);
+    test_adjacent_edges(&graph, NodeIndex(0), "A", &[], &[("AB", "B")]);
 }
 
 #[test]
 fn each_adjacent_from_b() {
     let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(1), "B",
-                        &[("FB", "F"), ("AB", "A"),],
-                        &[("BD", "D"), ("BC", "C"),]);
+    test_adjacent_edges(&graph,
+                        NodeIndex(1),
+                        "B",
+                        &[("FB", "F"), ("AB", "A")],
+                        &[("BD", "D"), ("BC", "C")]);
 }
 
 #[test]
 fn each_adjacent_from_c() {
     let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(2), "C",
-                        &[("EC", "E"), ("BC", "B")],
-                        &[]);
+    test_adjacent_edges(&graph, NodeIndex(2), "C", &[("EC", "E"), ("BC", "B")], &[]);
 }
 
 #[test]
 fn each_adjacent_from_d() {
     let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(3), "D",
-                        &[("BD", "B")],
-                        &[("DE", "E")]);
+    test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]);
 }
diff --git a/src/librustc_data_structures/ivar.rs b/src/librustc_data_structures/ivar.rs
index dabe1b984df..f842f4a41a1 100644
--- a/src/librustc_data_structures/ivar.rs
+++ b/src/librustc_data_structures/ivar.rs
@@ -26,14 +26,12 @@ use std::cell::Cell;
 /// suffices for the current purposes.
 #[derive(PartialEq)]
 pub struct Ivar<T: Copy> {
-    data: Cell<Option<T>>
+    data: Cell<Option<T>>,
 }
 
 impl<T: Copy> Ivar<T> {
     pub fn new() -> Ivar<T> {
-        Ivar {
-            data: Cell::new(None)
-        }
+        Ivar { data: Cell::new(None) }
     }
 
     pub fn get(&self) -> Option<T> {
@@ -41,8 +39,7 @@ impl<T: Copy> Ivar<T> {
     }
 
     pub fn fulfill(&self, value: T) {
-        assert!(self.data.get().is_none(),
-                "Value already set!");
+        assert!(self.data.get().is_none(), "Value already set!");
         self.data.set(Some(value));
     }
 
@@ -55,11 +52,11 @@ impl<T: Copy> Ivar<T> {
     }
 }
 
-impl<T: Copy+fmt::Debug> fmt::Debug for Ivar<T> {
+impl<T: Copy + fmt::Debug> fmt::Debug for Ivar<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.get() {
             Some(val) => write!(f, "Ivar({:?})", val),
-            None => f.write_str("Ivar(<unfulfilled>)")
+            None => f.write_str("Ivar(<unfulfilled>)"),
         }
     }
 }
@@ -68,7 +65,7 @@ impl<T: Copy> Clone for Ivar<T> {
     fn clone(&self) -> Ivar<T> {
         match self.get() {
             Some(val) => Ivar { data: Cell::new(Some(val)) },
-            None => Ivar::new()
+            None => Ivar::new(),
         }
     }
 }
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index e4b13ff548a..2234325aa01 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -32,7 +32,8 @@
 #![cfg_attr(test, feature(test))]
 
 extern crate core;
-#[macro_use] extern crate log;
+#[macro_use]
+extern crate log;
 extern crate serialize as rustc_serialize; // used by deriving
 
 pub mod bitvec;
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 25a77adba28..4f6d0d7e405 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -28,7 +28,7 @@ use self::tree_index::TreeIndex;
 #[cfg(test)]
 mod test;
 
-pub struct ObligationForest<O,T> {
+pub struct ObligationForest<O, T> {
     /// The list of obligations. In between calls to
     /// `process_obligations`, this list only contains nodes in the
     /// `Pending` or `Success` state (with a non-zero number of
@@ -43,7 +43,7 @@ pub struct ObligationForest<O,T> {
     /// backtrace iterator (which uses `split_at`).
     nodes: Vec<Node<O>>,
     trees: Vec<Tree<T>>,
-    snapshots: Vec<usize>
+    snapshots: Vec<usize>,
 }
 
 pub struct Snapshot {
@@ -67,7 +67,9 @@ struct Node<O> {
 #[derive(Debug)]
 enum NodeState<O> {
     /// Obligation not yet resolved to success or error.
-    Pending { obligation: O },
+    Pending {
+        obligation: O,
+    },
 
     /// Obligation resolved to success; `num_incomplete_children`
     /// indicates the number of children still in an "incomplete"
@@ -77,7 +79,10 @@ enum NodeState<O> {
     ///
     /// Once all children have completed, success nodes are removed
     /// from the vector by the compression step.
-    Success { obligation: O, num_incomplete_children: usize },
+    Success {
+        obligation: O,
+        num_incomplete_children: usize,
+    },
 
     /// This obligation was resolved to an error. Error nodes are
     /// removed from the vector by the compression step.
@@ -85,13 +90,13 @@ enum NodeState<O> {
 }
 
 #[derive(Debug)]
-pub struct Outcome<O,E> {
+pub struct Outcome<O, E> {
     /// Obligations that were completely evaluated, including all
     /// (transitive) subobligations.
     pub completed: Vec<O>,
 
     /// Backtrace of obligations that were found to be in error.
-    pub errors: Vec<Error<O,E>>,
+    pub errors: Vec<Error<O, E>>,
 
     /// If true, then we saw no successful obligations, which means
     /// there is no point in further iteration. This is based on the
@@ -103,7 +108,7 @@ pub struct Outcome<O,E> {
 }
 
 #[derive(Debug, PartialEq, Eq)]
-pub struct Error<O,E> {
+pub struct Error<O, E> {
     pub error: E,
     pub backtrace: Vec<O>,
 }
@@ -113,7 +118,7 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
         ObligationForest {
             trees: vec![],
             nodes: vec![],
-            snapshots: vec![]
+            snapshots: vec![],
         }
     }
 
@@ -148,11 +153,12 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
         // snapshot but pushing trees, all nodes after that should be
         // roots of other trees as well
         let first_root_index = self.trees[trees_len].root.get();
-        debug_assert!(
-            self.nodes[first_root_index..]
-                .iter()
-                .zip(first_root_index..)
-                .all(|(root, root_index)| self.trees[root.tree.get()].root.get() == root_index));
+        debug_assert!(self.nodes[first_root_index..]
+                          .iter()
+                          .zip(first_root_index..)
+                          .all(|(root, root_index)| {
+                              self.trees[root.tree.get()].root.get() == root_index
+                          }));
 
         // Pop off tree/root pairs pushed during snapshot.
         self.trees.truncate(trees_len);
@@ -169,14 +175,17 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
     pub fn push_tree(&mut self, obligation: O, tree_state: T) {
         let index = NodeIndex::new(self.nodes.len());
         let tree = TreeIndex::new(self.trees.len());
-        self.trees.push(Tree { root: index, state: tree_state });
+        self.trees.push(Tree {
+            root: index,
+            state: tree_state,
+        });
         self.nodes.push(Node::new(tree, None, obligation));
     }
 
     /// Convert all remaining obligations to the given error.
     ///
     /// This cannot be done during a snapshot.
-    pub fn to_errors<E:Clone>(&mut self, error: E) -> Vec<Error<O,E>> {
+    pub fn to_errors<E: Clone>(&mut self, error: E) -> Vec<Error<O, E>> {
         assert!(!self.in_snapshot());
         let mut errors = vec![];
         for index in 0..self.nodes.len() {
@@ -184,7 +193,10 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
             self.inherit_error(index);
             if let NodeState::Pending { .. } = self.nodes[index].state {
                 let backtrace = self.backtrace(index);
-                errors.push(Error { error: error.clone(), backtrace: backtrace });
+                errors.push(Error {
+                    error: error.clone(),
+                    backtrace: backtrace,
+                });
             }
         }
         let successful_obligations = self.compress();
@@ -193,21 +205,27 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
     }
 
     /// Returns the set of obligations that are in a pending state.
-    pub fn pending_obligations(&self) -> Vec<O> where O: Clone {
-        self.nodes.iter()
-                  .filter_map(|n| match n.state {
-                      NodeState::Pending { ref obligation } => Some(obligation),
-                      _ => None,
-                  })
-                  .cloned()
-                  .collect()
+    pub fn pending_obligations(&self) -> Vec<O>
+        where O: Clone
+    {
+        self.nodes
+            .iter()
+            .filter_map(|n| {
+                match n.state {
+                    NodeState::Pending { ref obligation } => Some(obligation),
+                    _ => None,
+                }
+            })
+            .cloned()
+            .collect()
     }
 
     /// Process the obligations.
     ///
     /// This CANNOT be unrolled (presently, at least).
-    pub fn process_obligations<E,F>(&mut self, mut action: F) -> Outcome<O,E>
-        where E: Debug, F: FnMut(&mut O, &mut T, Backtrace<O>) -> Result<Option<Vec<O>>, E>
+    pub fn process_obligations<E, F>(&mut self, mut action: F) -> Outcome<O, E>
+        where E: Debug,
+              F: FnMut(&mut O, &mut T, Backtrace<O>) -> Result<Option<Vec<O>>, E>
     {
         debug!("process_obligations(len={})", self.nodes.len());
         assert!(!self.in_snapshot()); // cannot unroll this action
@@ -228,7 +246,8 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
             self.inherit_error(index);
 
             debug!("process_obligations: node {} == {:?}",
-                   index, self.nodes[index].state);
+                   index,
+                   self.nodes[index].state);
 
             let result = {
                 let Node { tree, parent, .. } = self.nodes[index];
@@ -236,14 +255,16 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
                 let backtrace = Backtrace::new(prefix, parent);
                 match suffix[0].state {
                     NodeState::Error |
-                    NodeState::Success { .. } =>
-                        continue,
-                    NodeState::Pending { ref mut obligation } =>
-                        action(obligation, &mut self.trees[tree.get()].state, backtrace),
+                    NodeState::Success { .. } => continue,
+                    NodeState::Pending { ref mut obligation } => {
+                        action(obligation, &mut self.trees[tree.get()].state, backtrace)
+                    }
                 }
             };
 
-            debug!("process_obligations: node {} got result {:?}", index, result);
+            debug!("process_obligations: node {} got result {:?}",
+                   index,
+                   result);
 
             match result {
                 Ok(None) => {
@@ -256,7 +277,10 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
                 }
                 Err(err) => {
                     let backtrace = self.backtrace(index);
-                    errors.push(Error { error: err, backtrace: backtrace });
+                    errors.push(Error {
+                        error: err,
+                        backtrace: backtrace,
+                    });
                 }
             }
         }
@@ -291,20 +315,21 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
             // create child work
             let tree_index = self.nodes[index].tree;
             let node_index = NodeIndex::new(index);
-            self.nodes.extend(
-                children.into_iter()
-                        .map(|o| Node::new(tree_index, Some(node_index), o)));
+            self.nodes.extend(children.into_iter()
+                                      .map(|o| Node::new(tree_index, Some(node_index), o)));
         }
 
         // change state from `Pending` to `Success`, temporarily swapping in `Error`
         let state = mem::replace(&mut self.nodes[index].state, NodeState::Error);
         self.nodes[index].state = match state {
-            NodeState::Pending { obligation } =>
-                NodeState::Success { obligation: obligation,
-                                     num_incomplete_children: num_incomplete_children },
+            NodeState::Pending { obligation } => {
+                NodeState::Success {
+                    obligation: obligation,
+                    num_incomplete_children: num_incomplete_children,
+                }
+            }
             NodeState::Success { .. } |
-            NodeState::Error =>
-                unreachable!()
+            NodeState::Error => unreachable!(),
         };
     }
 
@@ -358,14 +383,19 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
                     // there was an error in the ancestors, it should
                     // have been propagated down and we should never
                     // have tried to process this obligation
-                    panic!("encountered error in node {:?} when collecting stack trace", p);
+                    panic!("encountered error in node {:?} when collecting stack trace",
+                           p);
                 }
             }
 
             // loop to the parent
             match self.nodes[p].parent {
-                Some(q) => { p = q.get(); }
-                None => { return trace; }
+                Some(q) => {
+                    p = q.get();
+                }
+                None => {
+                    return trace;
+                }
             }
         }
     }
@@ -427,18 +457,19 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> {
 
         // Pop off all the nodes we killed and extract the success
         // stories.
-        let successful =
-            (0 .. dead_nodes)
-            .map(|_| self.nodes.pop().unwrap())
-            .flat_map(|node| match node.state {
-                NodeState::Error => None,
-                NodeState::Pending { .. } => unreachable!(),
-                NodeState::Success { obligation, num_incomplete_children } => {
-                    assert_eq!(num_incomplete_children, 0);
-                    Some(obligation)
-                }
-            })
-            .collect();
+        let successful = (0..dead_nodes)
+                             .map(|_| self.nodes.pop().unwrap())
+                             .flat_map(|node| {
+                                 match node.state {
+                                     NodeState::Error => None,
+                                     NodeState::Pending { .. } => unreachable!(),
+                                     NodeState::Success { obligation, num_incomplete_children } => {
+                                         assert_eq!(num_incomplete_children, 0);
+                                         Some(obligation)
+                                     }
+                                 }
+                             })
+                             .collect();
 
         // Adjust the various indices, since we compressed things.
         for tree in &mut self.trees {
@@ -484,7 +515,10 @@ pub struct Backtrace<'b, O: 'b> {
 
 impl<'b, O> Backtrace<'b, O> {
     fn new(nodes: &'b [Node<O>], pointer: Option<NodeIndex>) -> Backtrace<'b, O> {
-        Backtrace { nodes: nodes, pointer: pointer }
+        Backtrace {
+            nodes: nodes,
+            pointer: pointer,
+        }
     }
 }
 
@@ -497,9 +531,7 @@ impl<'b, O> Iterator for Backtrace<'b, O> {
             self.pointer = self.nodes[p.get()].parent;
             match self.nodes[p.get()].state {
                 NodeState::Pending { ref obligation } |
-                NodeState::Success { ref obligation, .. } => {
-                    Some(obligation)
-                }
+                NodeState::Success { ref obligation, .. } => Some(obligation),
                 NodeState::Error => {
                     panic!("Backtrace encountered an error.");
                 }
diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs
index 465cee0b60c..1063bb3611e 100644
--- a/src/librustc_data_structures/obligation_forest/node_index.rs
+++ b/src/librustc_data_structures/obligation_forest/node_index.rs
@@ -13,19 +13,16 @@ use std::u32;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct NodeIndex {
-    index: NonZero<u32>
+    index: NonZero<u32>,
 }
 
 impl NodeIndex {
     pub fn new(value: usize) -> NodeIndex {
         assert!(value < (u32::MAX as usize));
-        unsafe {
-            NodeIndex { index: NonZero::new((value as u32) + 1) }
-        }
+        unsafe { NodeIndex { index: NonZero::new((value as u32) + 1) } }
     }
 
     pub fn get(self) -> usize {
         (*self.index - 1) as usize
     }
 }
-
diff --git a/src/librustc_data_structures/obligation_forest/test.rs b/src/librustc_data_structures/obligation_forest/test.rs
index 9a0a4218d45..a8c24270217 100644
--- a/src/librustc_data_structures/obligation_forest/test.rs
+++ b/src/librustc_data_structures/obligation_forest/test.rs
@@ -21,19 +21,23 @@ fn push_pop() {
     //      A |-> A.1
     //        |-> A.2
     //        |-> A.3
-    let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations(|obligation, tree, _| {
-            assert_eq!(obligation.chars().next(), tree.chars().next());
-            match *obligation {
-                "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])),
-                "B" => Err("B is for broken"),
-                "C" => Ok(Some(vec![])),
-                _ => unreachable!(),
-            }
-        });
+    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation,
+                                                                                 tree,
+                                                                                 _| {
+        assert_eq!(obligation.chars().next(), tree.chars().next());
+        match *obligation {
+            "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])),
+            "B" => Err("B is for broken"),
+            "C" => Ok(Some(vec![])),
+            _ => unreachable!(),
+        }
+    });
     assert_eq!(ok, vec!["C"]);
-    assert_eq!(err, vec![Error {error: "B is for broken",
-                                backtrace: vec!["B"]}]);
+    assert_eq!(err,
+               vec![Error {
+                        error: "B is for broken",
+                        backtrace: vec!["B"],
+                    }]);
 
     // second round: two delays, one success, creating an uneven set of subtasks:
     //      A |-> A.1
@@ -61,33 +65,41 @@ fn push_pop() {
     // propagates to A.3.i, but not D.1 or D.2.
     //      D |-> D.1 |-> D.1.i
     //        |-> D.2 |-> D.2.i
-    let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations(|obligation, tree, _| {
-            assert_eq!(obligation.chars().next(), tree.chars().next());
-            match *obligation {
-                "A.1" => Ok(Some(vec![])),
-                "A.2" => Err("A is for apple"),
-                "D.1" => Ok(Some(vec!["D.1.i"])),
-                "D.2" => Ok(Some(vec!["D.2.i"])),
-                _ => unreachable!(),
-            }
-        });
+    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation,
+                                                                                 tree,
+                                                                                 _| {
+        assert_eq!(obligation.chars().next(), tree.chars().next());
+        match *obligation {
+            "A.1" => Ok(Some(vec![])),
+            "A.2" => Err("A is for apple"),
+            "D.1" => Ok(Some(vec!["D.1.i"])),
+            "D.2" => Ok(Some(vec!["D.2.i"])),
+            _ => unreachable!(),
+        }
+    });
     assert_eq!(ok, vec!["A.1"]);
-    assert_eq!(err, vec![Error { error: "A is for apple",
-                                 backtrace: vec!["A.2", "A"] }]);
+    assert_eq!(err,
+               vec![Error {
+                        error: "A is for apple",
+                        backtrace: vec!["A.2", "A"],
+                    }]);
 
     // fourth round: error in D.1.i that should propagate to D.2.i
-    let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations(|obligation, tree, _| {
-            assert_eq!(obligation.chars().next(), tree.chars().next());
-            match *obligation {
-                "D.1.i" => Err("D is for dumb"),
-                _ => panic!("unexpected obligation {:?}", obligation),
-            }
-        });
+    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation,
+                                                                                 tree,
+                                                                                 _| {
+        assert_eq!(obligation.chars().next(), tree.chars().next());
+        match *obligation {
+            "D.1.i" => Err("D is for dumb"),
+            _ => panic!("unexpected obligation {:?}", obligation),
+        }
+    });
     assert_eq!(ok, Vec::<&'static str>::new());
-    assert_eq!(err, vec![Error { error: "D is for dumb",
-                                 backtrace: vec!["D.1.i", "D.1", "D"] }]);
+    assert_eq!(err,
+               vec![Error {
+                        error: "D is for dumb",
+                        backtrace: vec!["D.1.i", "D.1", "D"],
+                    }]);
 }
 
 // Test that if a tree with grandchildren succeeds, everything is
@@ -104,7 +116,7 @@ fn success_in_grandchildren() {
     forest.push_tree("A", "A");
 
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, _| {
+        forest.process_obligations::<(), _>(|obligation, tree, _| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             match *obligation {
                 "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])),
@@ -115,7 +127,7 @@ fn success_in_grandchildren() {
     assert!(err.is_empty());
 
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, _| {
+        forest.process_obligations::<(), _>(|obligation, tree, _| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             match *obligation {
                 "A.1" => Ok(Some(vec![])),
@@ -128,7 +140,7 @@ fn success_in_grandchildren() {
     assert!(err.is_empty());
 
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, _| {
+        forest.process_obligations::<(), _>(|obligation, tree, _| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             match *obligation {
                 "A.2.i" => Ok(Some(vec!["A.2.i.a"])),
@@ -140,7 +152,7 @@ fn success_in_grandchildren() {
     assert!(err.is_empty());
 
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, _| {
+        forest.process_obligations::<(), _>(|obligation, tree, _| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             match *obligation {
                 "A.2.i.a" => Ok(Some(vec![])),
@@ -150,8 +162,11 @@ fn success_in_grandchildren() {
     assert_eq!(ok, vec!["A.2.i.a", "A.2.i", "A.2", "A"]);
     assert!(err.is_empty());
 
-    let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|_, _, _| unreachable!());
+    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations::<(), _>(|_,
+                                                                                          _,
+                                                                                          _| {
+        unreachable!()
+    });
     assert!(ok.is_empty());
     assert!(err.is_empty());
 }
@@ -163,7 +178,7 @@ fn to_errors_no_throw() {
     let mut forest = ObligationForest::new();
     forest.push_tree("A", "A");
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, _| {
+        forest.process_obligations::<(), _>(|obligation, tree, _| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             match *obligation {
                 "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])),
@@ -183,7 +198,7 @@ fn backtrace() {
     let mut forest = ObligationForest::new();
     forest.push_tree("A", "A");
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| {
+        forest.process_obligations::<(), _>(|obligation, tree, mut backtrace| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             assert!(backtrace.next().is_none());
             match *obligation {
@@ -194,7 +209,7 @@ fn backtrace() {
     assert!(ok.is_empty());
     assert!(err.is_empty());
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| {
+        forest.process_obligations::<(), _>(|obligation, tree, mut backtrace| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             assert!(backtrace.next().unwrap() == &"A");
             assert!(backtrace.next().is_none());
@@ -206,7 +221,7 @@ fn backtrace() {
     assert!(ok.is_empty());
     assert!(err.is_empty());
     let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| {
+        forest.process_obligations::<(), _>(|obligation, tree, mut backtrace| {
             assert_eq!(obligation.chars().next(), tree.chars().next());
             assert!(backtrace.next().unwrap() == &"A.1");
             assert!(backtrace.next().unwrap() == &"A");
diff --git a/src/librustc_data_structures/obligation_forest/tree_index.rs b/src/librustc_data_structures/obligation_forest/tree_index.rs
index a9f5483f45b..499448634ac 100644
--- a/src/librustc_data_structures/obligation_forest/tree_index.rs
+++ b/src/librustc_data_structures/obligation_forest/tree_index.rs
@@ -12,7 +12,7 @@ use std::u32;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct TreeIndex {
-    index: u32
+    index: u32,
 }
 
 impl TreeIndex {
@@ -25,4 +25,3 @@ impl TreeIndex {
         self.index as usize
     }
 }
-
diff --git a/src/librustc_data_structures/snapshot_vec.rs b/src/librustc_data_structures/snapshot_vec.rs
index 5f89856afdb..614e7aae74b 100644
--- a/src/librustc_data_structures/snapshot_vec.rs
+++ b/src/librustc_data_structures/snapshot_vec.rs
@@ -23,7 +23,7 @@ use self::UndoLog::*;
 use std::mem;
 use std::ops;
 
-pub enum UndoLog<D:SnapshotVecDelegate> {
+pub enum UndoLog<D: SnapshotVecDelegate> {
     /// Indicates where a snapshot started.
     OpenSnapshot,
 
@@ -37,10 +37,10 @@ pub enum UndoLog<D:SnapshotVecDelegate> {
     SetElem(usize, D::Value),
 
     /// Extensible set of actions
-    Other(D::Undo)
+    Other(D::Undo),
 }
 
-pub struct SnapshotVec<D:SnapshotVecDelegate> {
+pub struct SnapshotVec<D: SnapshotVecDelegate> {
     values: Vec<D::Value>,
     undo_log: Vec<UndoLog<D>>,
 }
@@ -58,7 +58,7 @@ pub trait SnapshotVecDelegate {
     fn reverse(values: &mut Vec<Self::Value>, action: Self::Undo);
 }
 
-impl<D:SnapshotVecDelegate> SnapshotVec<D> {
+impl<D: SnapshotVecDelegate> SnapshotVec<D> {
     pub fn new() -> SnapshotVec<D> {
         SnapshotVec {
             values: Vec::new(),
@@ -117,9 +117,7 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> {
         Snapshot { length: length }
     }
 
-    pub fn actions_since_snapshot(&self,
-                                  snapshot: &Snapshot)
-                                  -> &[UndoLog<D>] {
+    pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog<D>] {
         &self.undo_log[snapshot.length..]
     }
 
@@ -128,11 +126,10 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> {
         assert!(self.undo_log.len() > snapshot.length);
 
         // Invariant established by start_snapshot():
-        assert!(
-            match self.undo_log[snapshot.length] {
-                OpenSnapshot => true,
-                _ => false
-            });
+        assert!(match self.undo_log[snapshot.length] {
+            OpenSnapshot => true,
+            _ => false,
+        });
     }
 
     pub fn rollback_to(&mut self, snapshot: Snapshot) {
@@ -168,7 +165,10 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> {
         }
 
         let v = self.undo_log.pop().unwrap();
-        assert!(match v { OpenSnapshot => true, _ => false });
+        assert!(match v {
+            OpenSnapshot => true,
+            _ => false,
+        });
         assert!(self.undo_log.len() == snapshot.length);
     }
 
@@ -188,20 +188,28 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> {
     }
 }
 
-impl<D:SnapshotVecDelegate> ops::Deref for SnapshotVec<D> {
+impl<D: SnapshotVecDelegate> ops::Deref for SnapshotVec<D> {
     type Target = [D::Value];
-    fn deref(&self) -> &[D::Value] { &*self.values }
+    fn deref(&self) -> &[D::Value] {
+        &*self.values
+    }
 }
 
-impl<D:SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> {
-    fn deref_mut(&mut self) -> &mut [D::Value] { &mut *self.values }
+impl<D: SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> {
+    fn deref_mut(&mut self) -> &mut [D::Value] {
+        &mut *self.values
+    }
 }
 
-impl<D:SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> {
+impl<D: SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> {
     type Output = D::Value;
-    fn index(&self, index: usize) -> &D::Value { self.get(index) }
+    fn index(&self, index: usize) -> &D::Value {
+        self.get(index)
+    }
 }
 
-impl<D:SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> {
-    fn index_mut(&mut self, index: usize) -> &mut D::Value { self.get_mut(index) }
+impl<D: SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> {
+    fn index_mut(&mut self, index: usize) -> &mut D::Value {
+        self.get_mut(index)
+    }
 }
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index 7ea5cb8721d..c3a2f978e1a 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -14,7 +14,7 @@ use std::fmt::Debug;
 use std::mem;
 
 #[derive(Clone)]
-pub struct TransitiveRelation<T:Debug+PartialEq> {
+pub struct TransitiveRelation<T: Debug + PartialEq> {
     // List of elements. This is used to map from a T to a usize.  We
     // expect domain to be small so just use a linear list versus a
     // hashmap or something.
@@ -33,7 +33,7 @@ pub struct TransitiveRelation<T:Debug+PartialEq> {
     // are added with new elements. Perhaps better would be to ask the
     // user for a batch of edges to minimize this effect, but I
     // already wrote the code this way. :P -nmatsakis
-    closure: RefCell<Option<BitMatrix>>
+    closure: RefCell<Option<BitMatrix>>,
 }
 
 #[derive(Clone, PartialEq, PartialOrd)]
@@ -45,11 +45,13 @@ struct Edge {
     target: Index,
 }
 
-impl<T:Debug+PartialEq> TransitiveRelation<T> {
+impl<T: Debug + PartialEq> TransitiveRelation<T> {
     pub fn new() -> TransitiveRelation<T> {
-        TransitiveRelation { elements: vec![],
-                             edges: vec![],
-                             closure: RefCell::new(None) }
+        TransitiveRelation {
+            elements: vec![],
+            edges: vec![],
+            closure: RefCell::new(None),
+        }
     }
 
     fn index(&self, a: &T) -> Option<Index> {
@@ -74,7 +76,10 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
     pub fn add(&mut self, a: T, b: T) {
         let a = self.add_index(a);
         let b = self.add_index(b);
-        let edge = Edge { source: a, target: b };
+        let edge = Edge {
+            source: a,
+            target: b,
+        };
         if !self.edges.contains(&edge) {
             self.edges.push(edge);
 
@@ -86,10 +91,8 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
     /// Check whether `a < target` (transitively)
     pub fn contains(&self, a: &T, b: &T) -> bool {
         match (self.index(a), self.index(b)) {
-            (Some(a), Some(b)) =>
-                self.with_closure(|closure| closure.contains(a.0, b.0)),
-            (None, _) | (_, None) =>
-                false,
+            (Some(a), Some(b)) => self.with_closure(|closure| closure.contains(a.0, b.0)),
+            (None, _) | (_, None) => false,
         }
     }
 
@@ -156,7 +159,9 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
     pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> {
         let (mut a, mut b) = match (self.index(a), self.index(b)) {
             (Some(a), Some(b)) => (a, b),
-            (None, _) | (_, None) => { return vec![]; }
+            (None, _) | (_, None) => {
+                return vec![];
+            }
         };
 
         // in some cases, there are some arbitrary choices to be made;
@@ -233,7 +238,7 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
                    .collect()
     }
 
-    fn with_closure<OP,R>(&self, op: OP) -> R
+    fn with_closure<OP, R>(&self, op: OP) -> R
         where OP: FnOnce(&BitMatrix) -> R
     {
         let mut closure_cell = self.closure.borrow_mut();
@@ -431,14 +436,15 @@ fn pdub_crisscross() {
     // b -> b1 ---+
 
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "a1");
-    relation.add("a",  "b1");
-    relation.add("b",  "a1");
-    relation.add("b",  "b1");
+    relation.add("a", "a1");
+    relation.add("a", "b1");
+    relation.add("b", "a1");
+    relation.add("b", "b1");
     relation.add("a1", "x");
     relation.add("b1", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
+    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"),
+               vec![&"a1", &"b1"]);
     assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
 }
 
@@ -451,23 +457,25 @@ fn pdub_crisscross_more() {
     // b -> b1 -> b2 ---------+
 
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "a1");
-    relation.add("a",  "b1");
-    relation.add("b",  "a1");
-    relation.add("b",  "b1");
+    relation.add("a", "a1");
+    relation.add("a", "b1");
+    relation.add("b", "a1");
+    relation.add("b", "b1");
 
-    relation.add("a1",  "a2");
-    relation.add("a1",  "b2");
-    relation.add("b1",  "a2");
-    relation.add("b1",  "b2");
+    relation.add("a1", "a2");
+    relation.add("a1", "b2");
+    relation.add("b1", "a2");
+    relation.add("b1", "b2");
 
     relation.add("a2", "a3");
 
     relation.add("a3", "x");
     relation.add("b2", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
-    assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"), vec![&"a2", &"b2"]);
+    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"),
+               vec![&"a1", &"b1"]);
+    assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"),
+               vec![&"a2", &"b2"]);
     assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
 }
 
@@ -479,8 +487,8 @@ fn pdub_lub() {
     // b -> b1 ---+
 
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "a1");
-    relation.add("b",  "b1");
+    relation.add("a", "a1");
+    relation.add("b", "b1");
     relation.add("a1", "x");
     relation.add("b1", "x");
 
@@ -497,9 +505,9 @@ fn mubs_intermediate_node_on_one_side_only() {
 
     // "digraph { a -> c -> d; b -> d; }",
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "c");
-    relation.add("c",  "d");
-    relation.add("b",  "d");
+    relation.add("a", "c");
+    relation.add("c", "d");
+    relation.add("b", "d");
 
     assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"d"]);
 }
@@ -516,11 +524,11 @@ fn mubs_scc_1() {
 
     // "digraph { a -> c -> d; d -> c; a -> d; b -> d; }",
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "c");
-    relation.add("c",  "d");
-    relation.add("d",  "c");
-    relation.add("a",  "d");
-    relation.add("b",  "d");
+    relation.add("a", "c");
+    relation.add("c", "d");
+    relation.add("d", "c");
+    relation.add("a", "d");
+    relation.add("b", "d");
 
     assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
 }
@@ -536,11 +544,11 @@ fn mubs_scc_2() {
 
     // "digraph { a -> c -> d; d -> c; b -> d; b -> c; }",
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "c");
-    relation.add("c",  "d");
-    relation.add("d",  "c");
-    relation.add("b",  "d");
-    relation.add("b",  "c");
+    relation.add("a", "c");
+    relation.add("c", "d");
+    relation.add("d", "c");
+    relation.add("b", "d");
+    relation.add("b", "c");
 
     assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
 }
@@ -556,12 +564,12 @@ fn mubs_scc_3() {
 
     // "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }",
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "c");
-    relation.add("c",  "d");
-    relation.add("d",  "e");
-    relation.add("e",  "c");
-    relation.add("b",  "d");
-    relation.add("b",  "e");
+    relation.add("a", "c");
+    relation.add("c", "d");
+    relation.add("d", "e");
+    relation.add("e", "c");
+    relation.add("b", "d");
+    relation.add("b", "e");
 
     assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
 }
@@ -578,12 +586,12 @@ fn mubs_scc_4() {
 
     // "digraph { a -> c -> d -> e -> c; a -> d; b -> e; }"
     let mut relation = TransitiveRelation::new();
-    relation.add("a",  "c");
-    relation.add("c",  "d");
-    relation.add("d",  "e");
-    relation.add("e",  "c");
-    relation.add("a",  "d");
-    relation.add("b",  "e");
+    relation.add("a", "c");
+    relation.add("c", "d");
+    relation.add("d", "e");
+    relation.add("e", "c");
+    relation.add("a", "d");
+    relation.add("b", "e");
 
     assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
 }
diff --git a/src/librustc_data_structures/tuple_slice.rs b/src/librustc_data_structures/tuple_slice.rs
index f157d82eda1..9a90ab8c09d 100644
--- a/src/librustc_data_structures/tuple_slice.rs
+++ b/src/librustc_data_structures/tuple_slice.rs
@@ -36,13 +36,13 @@ macro_rules! impl_tuple_slice {
     }
 }
 
-impl_tuple_slice!((T,T), 2);
-impl_tuple_slice!((T,T,T), 3);
-impl_tuple_slice!((T,T,T,T), 4);
-impl_tuple_slice!((T,T,T,T,T), 5);
-impl_tuple_slice!((T,T,T,T,T,T), 6);
-impl_tuple_slice!((T,T,T,T,T,T,T), 7);
-impl_tuple_slice!((T,T,T,T,T,T,T,T), 8);
+impl_tuple_slice!((T, T), 2);
+impl_tuple_slice!((T, T, T), 3);
+impl_tuple_slice!((T, T, T, T), 4);
+impl_tuple_slice!((T, T, T, T, T), 5);
+impl_tuple_slice!((T, T, T, T, T, T), 6);
+impl_tuple_slice!((T, T, T, T, T, T, T), 7);
+impl_tuple_slice!((T, T, T, T, T, T, T, T), 8);
 
 #[test]
 fn test_sliced_tuples() {
diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs
index c6da70eef75..7a1ac830b22 100644
--- a/src/librustc_data_structures/unify/mod.rs
+++ b/src/librustc_data_structures/unify/mod.rs
@@ -56,21 +56,21 @@ impl Combine for () {
 /// time of the algorithm under control. For more information, see
 /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
 #[derive(PartialEq,Clone,Debug)]
-pub struct VarValue<K:UnifyKey> {
-    parent: K,       // if equal to self, this is a root
+pub struct VarValue<K: UnifyKey> {
+    parent: K, // if equal to self, this is a root
     value: K::Value, // value assigned (only relevant to root)
-    rank: u32,       // max depth (only relevant to root)
+    rank: u32, // max depth (only relevant to root)
 }
 
 /// Table of unification keys and their values.
-pub struct UnificationTable<K:UnifyKey> {
+pub struct UnificationTable<K: UnifyKey> {
     /// Indicates the current value of each key.
     values: sv::SnapshotVec<Delegate<K>>,
 }
 
 /// At any time, users may snapshot a unification table.  The changes
 /// made during the snapshot may either be *committed* or *rolled back*.
-pub struct Snapshot<K:UnifyKey> {
+pub struct Snapshot<K: UnifyKey> {
     // Link snapshot to the key type `K` of the table.
     marker: marker::PhantomData<K>,
     snapshot: sv::Snapshot,
@@ -79,15 +79,17 @@ pub struct Snapshot<K:UnifyKey> {
 #[derive(Copy, Clone)]
 struct Delegate<K>(PhantomData<K>);
 
-impl<K:UnifyKey> VarValue<K> {
+impl<K: UnifyKey> VarValue<K> {
     fn new_var(key: K, value: K::Value) -> VarValue<K> {
         VarValue::new(key, value, 0)
     }
 
     fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> {
-        VarValue { parent: parent, // this is a root
-                   value: value,
-                   rank: rank }
+        VarValue {
+            parent: parent, // this is a root
+            value: value,
+            rank: rank,
+        }
     }
 
     fn redirect(self, to: K) -> VarValue<K> {
@@ -95,7 +97,11 @@ impl<K:UnifyKey> VarValue<K> {
     }
 
     fn root(self, rank: u32, value: K::Value) -> VarValue<K> {
-        VarValue { rank: rank, value: value, ..self }
+        VarValue {
+            rank: rank,
+            value: value,
+            ..self
+        }
     }
 
     /// Returns the key of this node. Only valid if this is a root
@@ -122,18 +128,18 @@ impl<K:UnifyKey> VarValue<K> {
 // other type parameter U, and we have no way to say
 // Option<U>:LatticeValue.
 
-impl<K:UnifyKey> UnificationTable<K> {
+impl<K: UnifyKey> UnificationTable<K> {
     pub fn new() -> UnificationTable<K> {
-        UnificationTable {
-            values: sv::SnapshotVec::new()
-        }
+        UnificationTable { values: sv::SnapshotVec::new() }
     }
 
     /// Starts a new snapshot. Each snapshot must be either
     /// rolled back or committed in a "LIFO" (stack) order.
     pub fn snapshot(&mut self) -> Snapshot<K> {
-        Snapshot { marker: marker::PhantomData::<K>,
-                   snapshot: self.values.start_snapshot() }
+        Snapshot {
+            marker: marker::PhantomData::<K>,
+            snapshot: self.values.start_snapshot(),
+        }
     }
 
     /// Reverses all changes since the last snapshot. Also
@@ -154,9 +160,7 @@ impl<K:UnifyKey> UnificationTable<K> {
         let len = self.values.len();
         let key: K = UnifyKey::from_index(len as u32);
         self.values.push(VarValue::new_var(key, value));
-        debug!("{}: created new key: {:?}",
-               UnifyKey::tag(None::<K>),
-               key);
+        debug!("{}: created new key: {:?}", UnifyKey::tag(None::<K>), key);
         key
     }
 
@@ -179,9 +183,7 @@ impl<K:UnifyKey> UnificationTable<K> {
                 }
                 root
             }
-            None => {
-                value
-            }
+            None => value,
         }
     }
 
@@ -195,8 +197,7 @@ impl<K:UnifyKey> UnificationTable<K> {
     fn set(&mut self, key: K, new_value: VarValue<K>) {
         assert!(self.is_root(key));
 
-        debug!("Updating variable {:?} to {:?}",
-               key, new_value);
+        debug!("Updating variable {:?} to {:?}", key, new_value);
 
         let index = key.index() as usize;
         self.values.set(index, new_value);
@@ -243,17 +244,16 @@ impl<K:UnifyKey> UnificationTable<K> {
     }
 }
 
-impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
+impl<K: UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
     type Value = VarValue<K>;
     type Undo = ();
 
     fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {}
 }
 
-///////////////////////////////////////////////////////////////////////////
-// Base union-find algorithm, where we are just making sets
+// # Base union-find algorithm, where we are just making sets
 
-impl<'tcx,K:UnifyKey> UnificationTable<K>
+impl<'tcx, K: UnifyKey> UnificationTable<K>
     where K::Value: Combine
 {
     pub fn union(&mut self, a_id: K, b_id: K) {
@@ -280,35 +280,30 @@ impl<'tcx,K:UnifyKey> UnificationTable<K>
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
+// # Non-subtyping unification
+//
 // Code to handle keys which carry a value, like ints,
 // floats---anything that doesn't have a subtyping relationship we
 // need to worry about.
 
-impl<'tcx,K,V> UnificationTable<K>
-    where K: UnifyKey<Value=Option<V>>,
-          V: Clone+PartialEq+Debug,
+impl<'tcx, K, V> UnificationTable<K>
+    where K: UnifyKey<Value = Option<V>>,
+          V: Clone + PartialEq + Debug
 {
-    pub fn unify_var_var(&mut self,
-                         a_id: K,
-                         b_id: K)
-                         -> Result<(),(V,V)>
-    {
+    pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result<(), (V, V)> {
         let node_a = self.get(a_id);
         let node_b = self.get(b_id);
         let a_id = node_a.key();
         let b_id = node_b.key();
 
-        if a_id == b_id { return Ok(()); }
+        if a_id == b_id {
+            return Ok(());
+        }
 
         let combined = {
             match (&node_a.value, &node_b.value) {
-                (&None, &None) => {
-                    None
-                }
-                (&Some(ref v), &None) | (&None, &Some(ref v)) => {
-                    Some(v.clone())
-                }
+                (&None, &None) => None,
+                (&Some(ref v), &None) | (&None, &Some(ref v)) => Some(v.clone()),
                 (&Some(ref v1), &Some(ref v2)) => {
                     if *v1 != *v2 {
                         return Err((v1.clone(), v2.clone()));
@@ -323,11 +318,7 @@ impl<'tcx,K,V> UnificationTable<K>
 
     /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
     /// relationships, if `a_id` already has a value, it must be the same as `b`.
-    pub fn unify_var_value(&mut self,
-                           a_id: K,
-                           b: V)
-                           -> Result<(),(V,V)>
-    {
+    pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), (V, V)> {
         let mut node_a = self.get(a_id);
 
         match node_a.value {
@@ -358,7 +349,13 @@ impl<'tcx,K,V> UnificationTable<K>
     pub fn unsolved_variables(&mut self) -> Vec<K> {
         self.values
             .iter()
-            .filter_map(|vv| if vv.value.is_some() { None } else { Some(vv.key()) })
+            .filter_map(|vv| {
+                if vv.value.is_some() {
+                    None
+                } else {
+                    Some(vv.key())
+                }
+            })
             .collect()
     }
 }
diff --git a/src/librustc_data_structures/unify/tests.rs b/src/librustc_data_structures/unify/tests.rs
index 089e629a569..f29a7132e83 100644
--- a/src/librustc_data_structures/unify/tests.rs
+++ b/src/librustc_data_structures/unify/tests.rs
@@ -19,9 +19,15 @@ struct UnitKey(u32);
 
 impl UnifyKey for UnitKey {
     type Value = ();
-    fn index(&self) -> u32 { self.0 }
-    fn from_index(u: u32) -> UnitKey { UnitKey(u) }
-    fn tag(_: Option<UnitKey>) -> &'static str { "UnitKey" }
+    fn index(&self) -> u32 {
+        self.0
+    }
+    fn from_index(u: u32) -> UnitKey {
+        UnitKey(u)
+    }
+    fn tag(_: Option<UnitKey>) -> &'static str {
+        "UnitKey"
+    }
 }
 
 #[test]
@@ -45,7 +51,7 @@ fn big_array() {
     }
 
     for i in 1..MAX {
-        let l = keys[i-1];
+        let l = keys[i - 1];
         let r = keys[i];
         ut.union(l, r);
     }
@@ -68,7 +74,7 @@ fn big_array_bench(b: &mut Bencher) {
 
     b.iter(|| {
         for i in 1..MAX {
-            let l = keys[i-1];
+            let l = keys[i - 1];
             let r = keys[i];
             ut.union(l, r);
         }
@@ -90,16 +96,16 @@ fn even_odd() {
         keys.push(key);
 
         if i >= 2 {
-            ut.union(key, keys[i-2]);
+            ut.union(key, keys[i - 2]);
         }
     }
 
     for i in 1..MAX {
-        assert!(!ut.unioned(keys[i-1], keys[i]));
+        assert!(!ut.unioned(keys[i - 1], keys[i]));
     }
 
     for i in 2..MAX {
-        assert!(ut.unioned(keys[i-2], keys[i]));
+        assert!(ut.unioned(keys[i - 2], keys[i]));
     }
 }
 
@@ -108,9 +114,15 @@ struct IntKey(u32);
 
 impl UnifyKey for IntKey {
     type Value = Option<i32>;
-    fn index(&self) -> u32 { self.0 }
-    fn from_index(u: u32) -> IntKey { IntKey(u) }
-    fn tag(_: Option<IntKey>) -> &'static str { "IntKey" }
+    fn index(&self) -> u32 {
+        self.0
+    }
+    fn from_index(u: u32) -> IntKey {
+        IntKey(u)
+    }
+    fn tag(_: Option<IntKey>) -> &'static str {
+        "IntKey"
+    }
 }
 
 /// Test unifying a key whose value is `Some(_)`  with a key whose value is `None`.
@@ -191,4 +203,3 @@ fn unify_key_Some_x_val_x() {
     assert!(ut.unify_var_value(k1, 22).is_ok());
     assert_eq!(ut.probe(k1), Some(22));
 }
-
diff --git a/src/librustc_data_structures/veccell/mod.rs b/src/librustc_data_structures/veccell/mod.rs
index 008642d9d65..054eee8829a 100644
--- a/src/librustc_data_structures/veccell/mod.rs
+++ b/src/librustc_data_structures/veccell/mod.rs
@@ -12,11 +12,11 @@ use std::cell::UnsafeCell;
 use std::mem;
 
 pub struct VecCell<T> {
-    data: UnsafeCell<Vec<T>>
+    data: UnsafeCell<Vec<T>>,
 }
 
 impl<T> VecCell<T> {
-    pub fn with_capacity(capacity: usize) -> VecCell<T>{
+    pub fn with_capacity(capacity: usize) -> VecCell<T> {
         VecCell { data: UnsafeCell::new(Vec::with_capacity(capacity)) }
     }
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 9c1be4c9f2f..55ec9d82a2e 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -48,12 +48,10 @@ use std::fs;
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use syntax::ast::{self, NodeIdAssigner};
-use syntax::attr;
-use syntax::attr::AttrMetaMethods;
+use syntax::attr::{self, AttrMetaMethods};
 use syntax::diagnostics;
 use syntax::fold::Folder;
-use syntax::parse;
-use syntax::parse::token;
+use syntax::parse::{self, PResult, token};
 use syntax::util::node_count::NodeCounter;
 use syntax::visit;
 use syntax;
@@ -86,7 +84,13 @@ pub fn compile_input(sess: &Session,
     // possible to keep the peak memory usage low
     let (outputs, trans) = {
         let (outputs, expanded_crate, id) = {
-            let krate = phase_1_parse_input(sess, cfg, input);
+            let krate = match phase_1_parse_input(sess, cfg, input) {
+                Ok(krate) => krate,
+                Err(mut parse_error) => {
+                    parse_error.emit();
+                    return Err(1);
+                }
+            };
 
             controller_entry_point!(after_parse,
                                     sess,
@@ -415,17 +419,20 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> {
     }
 }
 
-pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) -> ast::Crate {
+pub fn phase_1_parse_input<'a>(sess: &'a Session,
+                               cfg: ast::CrateConfig,
+                               input: &Input)
+                               -> PResult<'a, ast::Crate> {
     // These may be left in an incoherent state after a previous compile.
     // `clear_tables` and `get_ident_interner().clear()` can be used to free
     // memory, but they do not restore the initial state.
     syntax::ext::mtwt::reset_tables();
     token::reset_ident_interner();
 
-    let krate = time(sess.time_passes(), "parsing", || {
+    let krate = try!(time(sess.time_passes(), "parsing", || {
         match *input {
             Input::File(ref file) => {
-                parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
+                parse::parse_crate_from_file(file, cfg.clone(), &sess.parse_sess)
             }
             Input::Str(ref src) => {
                 parse::parse_crate_from_source_str(anon_src().to_string(),
@@ -434,7 +441,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
                                                    &sess.parse_sess)
             }
         }
-    });
+    }));
 
     if sess.opts.debugging_opts.ast_json_noexpand {
         println!("{}", json::as_json(&krate));
@@ -449,7 +456,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
         syntax::show_span::run(sess.diagnostic(), s, &krate);
     }
 
-    krate
+    Ok(krate)
 }
 
 fn count_nodes(krate: &ast::Crate) -> usize {
@@ -761,7 +768,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
         freevars,
         export_map,
         trait_map,
-        external_exports,
         glob_map,
     } = time(time_passes,
              "resolution",
@@ -822,9 +828,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
         analysis.access_levels =
             time(time_passes, "privacy checking", || {
-                rustc_privacy::check_crate(tcx,
-                                           &analysis.export_map,
-                                           external_exports)
+                rustc_privacy::check_crate(tcx, &analysis.export_map)
             });
 
         // Do not move this check past lint
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index da565856a9f..d1c287b1e39 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -89,7 +89,7 @@ use std::thread;
 use rustc::session::{early_error, early_warn};
 
 use syntax::ast;
-use syntax::parse;
+use syntax::parse::{self, PResult};
 use syntax::errors;
 use syntax::errors::emitter::Emitter;
 use syntax::diagnostics;
@@ -531,7 +531,19 @@ impl RustcDefaultCalls {
             return Compilation::Continue;
         }
 
-        let attrs = input.map(|input| parse_crate_attrs(sess, input));
+        let attrs = match input {
+            None => None,
+            Some(input) => {
+                let result = parse_crate_attrs(sess, input);
+                match result {
+                    Ok(attrs) => Some(attrs),
+                    Err(mut parse_error) => {
+                        parse_error.emit();
+                        return Compilation::Stop;
+                    }
+                }
+            }
+        };
         for req in &sess.opts.prints {
             match *req {
                 PrintRequest::TargetList => {
@@ -977,8 +989,8 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
     Some(matches)
 }
 
-fn parse_crate_attrs(sess: &Session, input: &Input) -> Vec<ast::Attribute> {
-    let result = match *input {
+fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
+    match *input {
         Input::File(ref ifile) => {
             parse::parse_crate_attrs_from_file(ifile, Vec::new(), &sess.parse_sess)
         }
@@ -988,8 +1000,7 @@ fn parse_crate_attrs(sess: &Session, input: &Input) -> Vec<ast::Attribute> {
                                                      Vec::new(),
                                                      &sess.parse_sess)
         }
-    };
-    result.into_iter().collect()
+    }
 }
 
 /// Run a procedure which will detect panics in the compiler and print nicer
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index eb4668e6abb..9f9824eae35 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -686,7 +686,7 @@ pub fn pretty_print_input(sess: Session,
                           ppm: PpMode,
                           opt_uii: Option<UserIdentifiedItem>,
                           ofile: Option<PathBuf>) {
-    let krate = driver::phase_1_parse_input(&sess, cfg, input);
+    let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, input));
 
     let krate = if let PpmSource(PpmEveryBodyLoops) = ppm {
         let mut fold = ReplaceBodyWithLoop::new();
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index abeaffe80ab..3cab9cfb88c 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -114,7 +114,7 @@ fn test_env<F>(source_string: &str,
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     let krate_config = Vec::new();
     let input = config::Input::Str(source_string.to_string());
-    let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
+    let krate = driver::phase_1_parse_input(&sess, krate_config, &input).unwrap();
     let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None)
                     .expect("phase 2 aborted");
 
@@ -261,16 +261,15 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
 
     pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
         let input_args = input_tys.iter().cloned().collect();
-        self.infcx.tcx.mk_fn(None,
-                             self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
-                                 unsafety: hir::Unsafety::Normal,
-                                 abi: Abi::Rust,
-                                 sig: ty::Binder(ty::FnSig {
-                                     inputs: input_args,
-                                     output: ty::FnConverging(output_ty),
-                                     variadic: false,
-                                 }),
-                             }))
+        self.infcx.tcx.mk_fn_ptr(ty::BareFnTy {
+            unsafety: hir::Unsafety::Normal,
+            abi: Abi::Rust,
+            sig: ty::Binder(ty::FnSig {
+                inputs: input_args,
+                output: ty::FnConverging(output_ty),
+                variadic: false,
+            }),
+        })
     }
 
     pub fn t_nil(&self) -> Ty<'tcx> {
diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs
index 75a1363fcf9..beedb3d70b6 100644
--- a/src/librustc_front/fold.rs
+++ b/src/librustc_front/fold.rs
@@ -1090,10 +1090,6 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
             ExprIndex(el, er) => {
                 ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
             }
-            ExprRange(e1, e2) => {
-                ExprRange(e1.map(|x| folder.fold_expr(x)),
-                          e2.map(|x| folder.fold_expr(x)))
-            }
             ExprPath(qself, path) => {
                 let qself = qself.map(|QSelf { ty, position }| {
                     QSelf {
diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs
index cc562b0f7b2..ece62364376 100644
--- a/src/librustc_front/hir.rs
+++ b/src/librustc_front/hir.rs
@@ -776,8 +776,6 @@ pub enum Expr_ {
     ExprTupField(P<Expr>, Spanned<usize>),
     /// An indexing operation (`foo[2]`)
     ExprIndex(P<Expr>, P<Expr>),
-    /// A range (`1..2`, `1..`, or `..2`)
-    ExprRange(Option<P<Expr>>, Option<P<Expr>>),
 
     /// Variable reference, possibly containing `::` and/or type
     /// parameters, e.g. foo::bar::<baz>.
@@ -837,6 +835,7 @@ pub enum MatchSource {
     },
     WhileLetDesugar,
     ForLoopDesugar,
+    TryDesugar,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
diff --git a/src/librustc_front/intravisit.rs b/src/librustc_front/intravisit.rs
index e6f448654ac..d71e392f521 100644
--- a/src/librustc_front/intravisit.rs
+++ b/src/librustc_front/intravisit.rs
@@ -784,10 +784,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(main_expression);
             visitor.visit_expr(index_expression)
         }
-        ExprRange(ref start, ref end) => {
-            walk_list!(visitor, visit_expr, start);
-            walk_list!(visitor, visit_expr, end);
-        }
         ExprPath(ref maybe_qself, ref path) => {
             if let Some(ref qself) = *maybe_qself {
                 visitor.visit_ty(&qself.ty);
diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs
index 1bfcb298586..291df66755e 100644
--- a/src/librustc_front/lowering.rs
+++ b/src/librustc_front/lowering.rs
@@ -65,6 +65,7 @@ use hir;
 
 use std::collections::BTreeMap;
 use std::collections::HashMap;
+use std::iter;
 use syntax::ast::*;
 use syntax::attr::{ThinAttributes, ThinAttributesExt};
 use syntax::ext::mtwt;
@@ -1217,9 +1218,79 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
             ExprKind::Index(ref el, ref er) => {
                 hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er))
             }
-            ExprKind::Range(ref e1, ref e2) => {
-                hir::ExprRange(e1.as_ref().map(|x| lower_expr(lctx, x)),
-                               e2.as_ref().map(|x| lower_expr(lctx, x)))
+            ExprKind::Range(ref e1, ref e2, lims) => {
+                fn make_struct(lctx: &LoweringContext,
+                               ast_expr: &Expr,
+                               path: &[&str],
+                               fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
+                    let strs = std_path(lctx, &iter::once(&"ops")
+                                                    .chain(path)
+                                                    .map(|s| *s)
+                                                    .collect::<Vec<_>>());
+
+                    let structpath = path_global(ast_expr.span, strs);
+
+                    let hir_expr = if fields.len() == 0 {
+                        expr_path(lctx,
+                                  structpath,
+                                  ast_expr.attrs.clone())
+                    } else {
+                        expr_struct(lctx,
+                                    ast_expr.span,
+                                    structpath,
+                                    fields.into_iter().map(|&(s, e)| {
+                                        field(token::intern(s),
+                                              signal_block_expr(lctx,
+                                                                hir_vec![],
+                                                                lower_expr(lctx, &**e),
+                                                                e.span,
+                                                                hir::PopUnstableBlock,
+                                                                None),
+                                              ast_expr.span)
+                                    }).collect(),
+                                    None,
+                                    ast_expr.attrs.clone())
+                    };
+
+                    signal_block_expr(lctx,
+                                      hir_vec![],
+                                      hir_expr,
+                                      ast_expr.span,
+                                      hir::PushUnstableBlock,
+                                      None)
+                }
+
+                return cache_ids(lctx, e.id, |lctx| {
+                    use syntax::ast::RangeLimits::*;
+
+                    match (e1, e2, lims) {
+                        (&None,         &None,         HalfOpen) =>
+                            make_struct(lctx, e, &["RangeFull"],
+                                                 &[]),
+
+                        (&Some(ref e1), &None,         HalfOpen) =>
+                            make_struct(lctx, e, &["RangeFrom"],
+                                                 &[("start", e1)]),
+
+                        (&None,         &Some(ref e2), HalfOpen) =>
+                            make_struct(lctx, e, &["RangeTo"],
+                                                 &[("end", e2)]),
+
+                        (&Some(ref e1), &Some(ref e2), HalfOpen) =>
+                            make_struct(lctx, e, &["Range"],
+                                                 &[("start", e1), ("end", e2)]),
+
+                        (&None,         &Some(ref e2), Closed)   =>
+                            make_struct(lctx, e, &["RangeToInclusive"],
+                                                 &[("end", e2)]),
+
+                        (&Some(ref e1), &Some(ref e2), Closed)   =>
+                            make_struct(lctx, e, &["RangeInclusive", "NonEmpty"],
+                                                 &[("start", e1), ("end", e2)]),
+
+                        _ => panic!("impossible range in AST"),
+                    }
+                });
             }
             ExprKind::Path(ref qself, ref path) => {
                 let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
@@ -1534,6 +1605,63 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 });
             }
 
+            // Desugar ExprKind::Try
+            // From: `<expr>?`
+            ExprKind::Try(ref sub_expr) => {
+                // to:
+                //
+                // {
+                //     match <expr> {
+                //         Ok(val) => val,
+                //         Err(err) => {
+                //             return Err(From::from(err))
+                //         }
+                //     }
+                // }
+
+                return cache_ids(lctx, e.id, |lctx| {
+                    // expand <expr>
+                    let sub_expr = lower_expr(lctx, sub_expr);
+
+                    // Ok(val) => val
+                    let ok_arm = {
+                        let val_ident = lctx.str_to_ident("val");
+                        let val_pat = pat_ident(lctx, e.span, val_ident);
+                        let val_expr = expr_ident(lctx, e.span, val_ident, None);
+                        let ok_pat = pat_ok(lctx, e.span, val_pat);
+
+                        arm(hir_vec![ok_pat], val_expr)
+                    };
+
+                    // Err(err) => return Err(From::from(err))
+                    let err_arm = {
+                        let err_ident = lctx.str_to_ident("err");
+                        let from_expr = {
+                            let path = std_path(lctx, &["convert", "From", "from"]);
+                            let path = path_global(e.span, path);
+                            let from = expr_path(lctx, path, None);
+                            let err_expr = expr_ident(lctx, e.span, err_ident, None);
+
+                            expr_call(lctx, e.span, from, hir_vec![err_expr], None)
+                        };
+                        let err_expr = {
+                            let path = std_path(lctx, &["result", "Result", "Err"]);
+                            let path = path_global(e.span, path);
+                            let err_ctor = expr_path(lctx, path, None);
+                            expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None)
+                        };
+                        let err_pat = pat_err(lctx, e.span, pat_ident(lctx, e.span, err_ident));
+                        let ret_expr = expr(lctx, e.span,
+                                            hir::Expr_::ExprRet(Some(err_expr)), None);
+
+                        arm(hir_vec![err_pat], ret_expr)
+                    };
+
+                    expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm],
+                               hir::MatchSource::TryDesugar, None)
+                })
+            }
+
             ExprKind::Mac(_) => panic!("Shouldn't exist here"),
         },
         span: e.span,
@@ -1627,6 +1755,17 @@ fn arm(pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
     }
 }
 
+fn field(name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field {
+    hir::Field {
+        name: Spanned {
+            node: name,
+            span: span,
+        },
+        span: span,
+        expr: expr,
+    }
+}
+
 fn expr_break(lctx: &LoweringContext, span: Span,
               attrs: ThinAttributes) -> P<hir::Expr> {
     expr(lctx, span, hir::ExprBreak(None), attrs)
@@ -1676,6 +1815,15 @@ fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: hir::HirVec<P<hir::Expr>>
     expr(lctx, sp, hir::ExprTup(exprs), attrs)
 }
 
+fn expr_struct(lctx: &LoweringContext,
+               sp: Span,
+               path: hir::Path,
+               fields: hir::HirVec<hir::Field>,
+               e: Option<P<hir::Expr>>,
+               attrs: ThinAttributes) -> P<hir::Expr> {
+    expr(lctx, sp, hir::ExprStruct(path, fields, e), attrs)
+}
+
 fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_,
         attrs: ThinAttributes) -> P<hir::Expr> {
     P(hir::Expr {
@@ -1728,6 +1876,18 @@ fn block_all(lctx: &LoweringContext,
     })
 }
 
+fn pat_ok(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
+    let ok = std_path(lctx, &["result", "Result", "Ok"]);
+    let path = path_global(span, ok);
+    pat_enum(lctx, span, path, hir_vec![pat])
+}
+
+fn pat_err(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
+    let err = std_path(lctx, &["result", "Result", "Err"]);
+    let path = path_global(span, err);
+    pat_enum(lctx, span, path, hir_vec![pat])
+}
+
 fn pat_some(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
     let some = std_path(lctx, &["option", "Option", "Some"]);
     let path = path_global(span, some);
diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs
index 49fbcea3dbf..143dfce09b6 100644
--- a/src/librustc_front/print/pprust.rs
+++ b/src/librustc_front/print/pprust.rs
@@ -1449,15 +1449,6 @@ impl<'a> State<'a> {
                 try!(self.print_expr(&index));
                 try!(word(&mut self.s, "]"));
             }
-            hir::ExprRange(ref start, ref end) => {
-                if let &Some(ref e) = start {
-                    try!(self.print_expr(&e));
-                }
-                try!(word(&mut self.s, ".."));
-                if let &Some(ref e) = end {
-                    try!(self.print_expr(&e));
-                }
-            }
             hir::ExprPath(None, ref path) => {
                 try!(self.print_path(path, true, 0))
             }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 86ab8d45e4e..0c906f8eb54 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1065,7 +1065,7 @@ impl LateLintPass for MutableTransmutes {
                 }
                 let typ = cx.tcx.node_id_to_type(expr.id);
                 match typ.sty {
-                    ty::TyBareFn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
+                    ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
                         if let ty::FnConverging(to) = bare_fn.sig.0.output {
                             let from = bare_fn.sig.0.inputs[0];
                             return Some((&from.sty, &to.sty));
@@ -1079,7 +1079,7 @@ impl LateLintPass for MutableTransmutes {
 
         fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
             match cx.tcx.lookup_item_type(def_id).ty.sty {
-                ty::TyBareFn(_, ref bfty) if bfty.abi == RustIntrinsic => (),
+                ty::TyFnDef(_, _, ref bfty) if bfty.abi == RustIntrinsic => (),
                 _ => return false
             }
             cx.tcx.with_path(def_id, |path| match path.last() {
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 1cf0339c086..e47f67dad8f 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -171,6 +171,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
                         master/text/0218-empty-struct-with-braces.md>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES),
+            reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>",
+        },
         ]);
 
     // We have one lint pass defined specially
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index c7cb2d15a09..10535549ceb 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -391,7 +391,7 @@ fn is_repr_nullable_ptr<'tcx>(tcx: &TyCtxt<'tcx>,
 
         if def.variants[data_idx].fields.len() == 1 {
             match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
-                ty::TyBareFn(None, _) => { return true; }
+                ty::TyFnPtr(_) => { return true; }
                 ty::TyRef(..) => { return true; }
                 _ => { }
             }
@@ -556,7 +556,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 self.check_type_for_ffi(cache, ty)
             }
 
-            ty::TyBareFn(None, bare_fn) => {
+            ty::TyFnPtr(bare_fn) => {
                 match bare_fn.abi {
                     Abi::Rust |
                     Abi::RustIntrinsic |
@@ -595,7 +595,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
             ty::TyClosure(..) | ty::TyProjection(..) |
-            ty::TyBareFn(Some(_), _) => {
+            ty::TyFnDef(..) => {
                 panic!("Unexpected type in foreign function")
             }
         }
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index 63db3d3c870..b3f24b8f16b 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -49,6 +49,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::get_deprecation(&cdata, def.index)
     }
 
+    fn visibility(&self, def: DefId) -> hir::Visibility {
+        let cdata = self.get_crate_data(def.krate);
+        decoder::get_visibility(&cdata, def.index)
+    }
+
     fn closure_kind(&self, _tcx: &TyCtxt<'tcx>, def_id: DefId) -> ty::ClosureKind
     {
         assert!(!def_id.is_local());
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index e286e028f33..06f81a17a06 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -472,7 +472,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
                    variant.name,
                    ctor_ty);
             let field_tys = match ctor_ty.sty {
-                ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+                ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
                     ref inputs, ..
                 }), ..}) => {
                     // tuple-struct constructors don't have escaping regions
@@ -545,6 +545,10 @@ pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option<attr::Deprecation> {
     })
 }
 
+pub fn get_visibility(cdata: Cmd, id: DefIndex) -> hir::Visibility {
+    item_visibility(cdata.lookup_item(id))
+}
+
 pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
     let item = cdata.lookup_item(id);
     match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
@@ -988,7 +992,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
             let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
             let ity = tcx.lookup_item_type(def_id).ty;
             let fty = match ity.sty {
-                ty::TyBareFn(_, fty) => fty.clone(),
+                ty::TyFnDef(_, _, fty) => fty.clone(),
                 _ => tcx.sess.bug(&format!(
                     "the type {:?} of the method {:?} is not a function?",
                     ity, name))
@@ -1582,7 +1586,8 @@ pub fn is_extern_item(cdata: Cmd, id: DefIndex, tcx: &TyCtxt) -> bool {
             let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx);
             let no_generics = generics.types.is_empty();
             match ty.sty {
-                ty::TyBareFn(_, fn_ty) if fn_ty.abi != Abi::Rust => return no_generics,
+                ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty)
+                    if fn_ty.abi != Abi::Rust => return no_generics,
                 _ => no_generics,
             }
         },
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index bf5a97232fc..e9b23eb0458 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -380,10 +380,11 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             }
             'F' => {
                 let def_id = self.parse_def();
-                return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty()));
+                let substs = self.tcx.mk_substs(self.parse_substs());
+                return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty());
             }
             'G' => {
-                return tcx.mk_fn(None, tcx.mk_bare_fn(self.parse_bare_fn_ty()));
+                return tcx.mk_fn_ptr(self.parse_bare_fn_ty());
             }
             '#' => {
                 // This is a hacky little caching scheme. The idea is that if we encode
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index 7289cd2b5b3..a6601e591ab 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -135,12 +135,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
         ty::TyStr => {
             write!(w, "v");
         }
-        ty::TyBareFn(Some(def_id), f) => {
+        ty::TyFnDef(def_id, substs, f) => {
             write!(w, "F");
             write!(w, "{}|", (cx.ds)(def_id));
+            enc_substs(w, cx, substs);
             enc_bare_fn_ty(w, cx, f);
         }
-        ty::TyBareFn(None, f) => {
+        ty::TyFnPtr(f) => {
             write!(w, "G");
             enc_bare_fn_ty(w, cx, f);
         }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index ca00b99b108..a7f4a53b022 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -239,7 +239,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
             }
             ExprKind::Call { ty, fun, args } => {
                 let diverges = match ty.sty {
-                    ty::TyBareFn(_, ref f) => f.sig.0.output.diverges(),
+                    ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
+                        f.sig.0.output.diverges()
+                    }
                     _ => false
                 };
                 let fun = unpack!(block = this.as_operand(block, fun));
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 5d040bcb40a..8c435b45dae 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -12,7 +12,6 @@
 //! kind of thing.
 
 use build::Builder;
-use hair::*;
 use rustc::middle::ty::Ty;
 use rustc::mir::repr::*;
 use std::u32;
@@ -59,16 +58,4 @@ impl<'a,'tcx> Builder<'a,'tcx> {
             });
         temp
     }
-
-    pub fn item_ref_operand(&mut self,
-                            span: Span,
-                            item_ref: ItemRef<'tcx>)
-                            -> Operand<'tcx> {
-        let literal = Literal::Item {
-            def_id: item_ref.def_id,
-            kind: item_ref.kind,
-            substs: item_ref.substs,
-        };
-        self.literal_operand(span, item_ref.ty, literal)
-    }
 }
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 6b1b3a33d3d..3d14ad2374b 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -503,7 +503,6 @@ impl<'a,'tcx> Builder<'a,'tcx> {
             ty: self.hir.tcx().lookup_item_type(funcdid).ty,
             literal: Literal::Item {
                 def_id: funcdid,
-                kind: ItemKind::Function,
                 substs: self.hir.tcx().mk_substs(Substs::empty())
             }
         }
@@ -641,7 +640,6 @@ fn build_free<'tcx>(tcx: &TyCtxt<'tcx>,
             ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs),
             literal: Literal::Item {
                 def_id: free_func,
-                kind: ItemKind::Function,
                 substs: substs
             }
         }),
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index ac1cff527fe..cbd6bed81a6 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -22,7 +22,6 @@ use rustc::middle::ty::{self, VariantDef, Ty};
 use rustc::mir::repr::*;
 use rustc_front::hir;
 use rustc_front::util as hir_util;
-use syntax::parse::token;
 use syntax::ptr::P;
 
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
@@ -62,7 +61,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     let method = method_callee(cx, self, ty::MethodCall::expr(self.id));
 
                     let sig = match method.ty.sty {
-                        ty::TyBareFn(_, fn_ty) => &fn_ty.sig,
+                        ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig,
                         _ => cx.tcx.sess.span_bug(self.span, "type of method is not an fn")
                     };
 
@@ -324,38 +323,6 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                 }
             }
 
-            hir::ExprRange(ref start, ref end) => {
-                let range_ty = cx.tcx.expr_ty(self);
-                let (adt_def, substs) = match range_ty.sty {
-                    ty::TyStruct(adt_def, substs) => (adt_def, substs),
-                    _ => {
-                        cx.tcx.sess.span_bug(self.span, "unexpanded ast");
-                    }
-                };
-
-                let field_expr_ref = |s: &'tcx P<hir::Expr>, name: &str| {
-                    let name = token::intern(name);
-                    let index = adt_def.variants[0].index_of_field_named(name).unwrap();
-                    FieldExprRef { name: Field::new(index), expr: s.to_ref() }
-                };
-
-                let start_field = start.as_ref()
-                                       .into_iter()
-                                       .map(|s| field_expr_ref(s, "start"));
-
-                let end_field = end.as_ref()
-                                   .into_iter()
-                                   .map(|e| field_expr_ref(e, "end"));
-
-                ExprKind::Adt {
-                    adt_def: adt_def,
-                    variant_index: 0,
-                    substs: substs,
-                    fields: start_field.chain(end_field).collect(),
-                    base: None,
-                }
-            }
-
             hir::ExprPath(..) => {
                 convert_path_expr(cx, self)
             }
@@ -614,7 +581,6 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
         kind: ExprKind::Literal {
             literal: Literal::Item {
                 def_id: callee.def_id,
-                kind: ItemKind::Method,
                 substs: callee.substs,
             },
         },
@@ -651,14 +617,13 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
     let substs = cx.tcx.mk_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_id, kind) = match def {
+    let def_id = match def {
         // A regular function.
-        Def::Fn(def_id) => (def_id, ItemKind::Function),
-        Def::Method(def_id) => (def_id, ItemKind::Method),
+        Def::Fn(def_id) | Def::Method(def_id) => def_id,
         Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
             // A tuple-struct constructor. Should only be reached if not called in the same
             // expression.
-            ty::TyBareFn(..) => (def_id, ItemKind::Function),
+            ty::TyFnDef(..) => def_id,
             // A unit struct which is used as a value. We return a completely different ExprKind
             // here to account for this special case.
             ty::TyStruct(adt_def, substs) => return ExprKind::Adt {
@@ -673,7 +638,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
         Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
             // A variant constructor. Should only be reached if not called in the same
             // expression.
-            ty::TyBareFn(..) => (variant_id, ItemKind::Function),
+            ty::TyFnDef(..) => variant_id,
             // A unit variant, similar special case to the struct case above.
             ty::TyEnum(adt_def, substs) => {
                 debug_assert!(adt_def.did == enum_id);
@@ -693,7 +658,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
             if let Some(v) = cx.try_const_eval_literal(expr) {
                 return ExprKind::Literal { literal: v };
             } else {
-                (def_id, ItemKind::Constant)
+                def_id
             }
         }
 
@@ -710,7 +675,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
                 &format!("def `{:?}` not yet implemented", def)),
     };
     ExprKind::Literal {
-        literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
+        literal: Literal::Item { def_id: def_id, substs: substs }
     }
 }
 
@@ -758,7 +723,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
             let region = cx.tcx.mk_region(region);
 
             let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) {
-                ty::ClosureKind::FnClosureKind => {
+                ty::ClosureKind::Fn => {
                     let ref_closure_ty =
                         cx.tcx.mk_ref(region,
                                    ty::TypeAndMut { ty: closure_ty,
@@ -777,7 +742,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
                         }
                     }
                 }
-                ty::ClosureKind::FnMutClosureKind => {
+                ty::ClosureKind::FnMut => {
                     let ref_closure_ty =
                         cx.tcx.mk_ref(region,
                                    ty::TypeAndMut { ty: closure_ty,
@@ -796,7 +761,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
                         }
                     }
                 }
-                ty::ClosureKind::FnOnceClosureKind => {
+                ty::ClosureKind::FnOnce => {
                     Expr {
                         ty: closure_ty,
                         temp_lifetime: temp_lifetime,
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 707dd972003..6a22dce7af9 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -14,7 +14,7 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind,
+use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp,
     TypedConstVal};
 use rustc::middle::const_eval::ConstVal;
 use rustc::middle::def_id::DefId;
@@ -29,14 +29,6 @@ use self::cx::Cx;
 pub mod cx;
 
 #[derive(Clone, Debug)]
-pub struct ItemRef<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub kind: ItemKind,
-    pub def_id: DefId,
-    pub substs: &'tcx Substs<'tcx>,
-}
-
-#[derive(Clone, Debug)]
 pub struct Block<'tcx> {
     pub extent: CodeExtent,
     pub span: Span,
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 96828628888..398f38c5ba9 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -252,15 +252,15 @@ fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
     let region = tcx.mk_region(region);
 
     match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
-        ty::ClosureKind::FnClosureKind =>
+        ty::ClosureKind::Fn =>
             tcx.mk_ref(region,
                        ty::TypeAndMut { ty: closure_ty,
                                         mutbl: hir::MutImmutable }),
-        ty::ClosureKind::FnMutClosureKind =>
+        ty::ClosureKind::FnMut =>
             tcx.mk_ref(region,
                        ty::TypeAndMut { ty: closure_ty,
                                         mutbl: hir::MutMutable }),
-        ty::ClosureKind::FnOnceClosureKind =>
+        ty::ClosureKind::FnOnce =>
             closure_ty
     }
 }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index bf22c7b0b8b..e021300f1b3 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -421,7 +421,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 let func_ty = mir.operand_ty(tcx, func);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
                 let func_ty = match func_ty.sty {
-                    ty::TyBareFn(_, func_ty) => func_ty,
+                    ty::TyFnDef(_, _, func_ty) | ty::TyFnPtr(func_ty) => func_ty,
                     _ => {
                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
                         return;
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 3703e602746..3a39a3c6dd1 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -582,7 +582,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
                 }
                 Some(Def::Struct(..)) => {
-                    if let ty::TyBareFn(..) = node_ty.sty {
+                    if let ty::TyFnDef(..) = node_ty.sty {
                         // Count the function pointer.
                         v.add_qualif(ConstQualif::NON_ZERO_SIZED);
                     }
@@ -747,9 +747,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
         hir::ExprAgain(_) |
         hir::ExprRet(_) |
 
-        // Miscellaneous expressions that could be implemented.
-        hir::ExprRange(..) |
-
         // Expressions with side-effects.
         hir::ExprAssign(..) |
         hir::ExprAssignOp(..) |
diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs
index 4a9b9970caf..168ae79ab74 100644
--- a/src/librustc_platform_intrinsics/x86.rs
+++ b/src/librustc_platform_intrinsics/x86.rs
@@ -1108,6 +1108,126 @@ pub fn find<'tcx>(_tcx: &TyCtxt<'tcx>, name: &str) -> Option<Intrinsic> {
             output: v(u(16), 16),
             definition: Named("llvm.x86.avx2.psubus.w")
         },
+        "_fmadd_ps" => Intrinsic {
+            inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)],
+            output: v(f(32), 4),
+            definition: Named("llvm.x86.fma.vfmadd.ps")
+        },
+        "_fmadd_pd" => Intrinsic {
+            inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)],
+            output: v(f(64), 2),
+            definition: Named("llvm.x86.fma.vfmadd.pd")
+        },
+        "256_fmadd_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.fma.vfmadd.ps.256")
+        },
+        "256_fmadd_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.fma.vfmadd.pd.256")
+        },
+        "_fmaddsub_ps" => Intrinsic {
+            inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)],
+            output: v(f(32), 4),
+            definition: Named("llvm.x86.fma.vfmaddsub.ps")
+        },
+        "_fmaddsub_pd" => Intrinsic {
+            inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)],
+            output: v(f(64), 2),
+            definition: Named("llvm.x86.fma.vfmaddsub.pd")
+        },
+        "256_fmaddsub_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.fma.vfmaddsub.ps.256")
+        },
+        "256_fmaddsub_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.fma.vfmaddsub.pd.256")
+        },
+        "_fmsub_ps" => Intrinsic {
+            inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)],
+            output: v(f(32), 4),
+            definition: Named("llvm.x86.fma.vfmsub.ps")
+        },
+        "_fmsub_pd" => Intrinsic {
+            inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)],
+            output: v(f(64), 2),
+            definition: Named("llvm.x86.fma.vfmsub.pd")
+        },
+        "256_fmsub_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.fma.vfmsub.ps.256")
+        },
+        "256_fmsub_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.fma.vfmsub.pd.256")
+        },
+        "_fmsubadd_ps" => Intrinsic {
+            inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)],
+            output: v(f(32), 4),
+            definition: Named("llvm.x86.fma.vfmsubadd.ps")
+        },
+        "_fmsubadd_pd" => Intrinsic {
+            inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)],
+            output: v(f(64), 2),
+            definition: Named("llvm.x86.fma.vfmsubadd.pd")
+        },
+        "256_fmsubadd_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.fma.vfmsubadd.ps.256")
+        },
+        "256_fmsubadd_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.fma.vfmsubadd.pd.256")
+        },
+        "_fnmadd_ps" => Intrinsic {
+            inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)],
+            output: v(f(32), 4),
+            definition: Named("llvm.x86.fma.vfnmadd.ps")
+        },
+        "_fnmadd_pd" => Intrinsic {
+            inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)],
+            output: v(f(64), 2),
+            definition: Named("llvm.x86.fma.vfnmadd.pd")
+        },
+        "256_fnmadd_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.fma.vfnmadd.ps.256")
+        },
+        "256_fnmadd_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.fma.vfnmadd.pd.256")
+        },
+        "_fnmsub_ps" => Intrinsic {
+            inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)],
+            output: v(f(32), 4),
+            definition: Named("llvm.x86.fma.vfnmsub.ps")
+        },
+        "_fnmsub_pd" => Intrinsic {
+            inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)],
+            output: v(f(64), 2),
+            definition: Named("llvm.x86.fma.vfnmsub.pd")
+        },
+        "256_fnmsub_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.fma.vfnmsub.ps.256")
+        },
+        "256_fnmsub_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.fma.vfnmsub.pd.256")
+        },
         _ => return None,
     })
 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 214ac81ee50..79ccc8fb2b2 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -38,10 +38,10 @@ use rustc_front::intravisit::{self, Visitor};
 
 use rustc::dep_graph::DepNode;
 use rustc::lint;
+use rustc::middle::cstore::CrateStore;
 use rustc::middle::def::{self, Def};
 use rustc::middle::def_id::DefId;
 use rustc::middle::privacy::{AccessLevel, AccessLevels};
-use rustc::middle::privacy::ExternalExports;
 use rustc::middle::ty::{self, TyCtxt};
 use rustc::util::nodemap::{NodeMap, NodeSet};
 use rustc::front::map as ast_map;
@@ -476,7 +476,6 @@ struct PrivacyVisitor<'a, 'tcx: 'a> {
     curitem: ast::NodeId,
     in_foreign: bool,
     parents: NodeMap<ast::NodeId>,
-    external_exports: ExternalExports,
 }
 
 #[derive(Debug)]
@@ -498,7 +497,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
         let node_id = if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
             node_id
         } else {
-            if self.external_exports.contains(&did) {
+            if self.tcx.sess.cstore.visibility(did) == hir::Public {
                 debug!("privacy - {:?} was externally exported", did);
                 return Allowable;
             }
@@ -857,7 +856,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                 if let Def::Struct(..) = self.tcx.resolve_expr(expr) {
                     let expr_ty = self.tcx.expr_ty(expr);
                     let def = match expr_ty.sty {
-                        ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+                        ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
                             output: ty::FnConverging(ty), ..
                         }), ..}) => ty,
                         _ => expr_ty
@@ -1567,10 +1566,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
     }
 }
 
-pub fn check_crate(tcx: &TyCtxt,
-                   export_map: &def::ExportMap,
-                   external_exports: ExternalExports)
-                   -> AccessLevels {
+pub fn check_crate(tcx: &TyCtxt, export_map: &def::ExportMap) -> AccessLevels {
     let _task = tcx.dep_graph.in_task(DepNode::Privacy);
 
     let krate = tcx.map.krate();
@@ -1593,7 +1589,6 @@ pub fn check_crate(tcx: &TyCtxt,
         in_foreign: false,
         tcx: tcx,
         parents: visitor.parents,
-        external_exports: external_exports,
     };
     intravisit::walk_crate(&mut visitor, krate);
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index f391597e3b1..ad4bcff1d3d 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -289,7 +289,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                         krate: crate_id,
                         index: CRATE_DEF_INDEX,
                     };
-                    self.external_exports.insert(def_id);
                     let parent_link = ModuleParentLink(parent, name);
                     let def = Def::Mod(def_id);
                     let module = self.new_extern_crate_module(parent_link, def, is_public, item.id);
@@ -495,15 +494,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
             modifiers = modifiers | DefModifiers::IMPORTABLE;
         }
 
-        let is_exported = is_public &&
-                          match new_parent.def_id() {
-            None => true,
-            Some(did) => self.external_exports.contains(&did),
-        };
-        if is_exported {
-            self.external_exports.insert(def.def_id());
-        }
-
         match def {
             Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) | Def::TyAlias(..) => {
                 debug!("(building reduced graph for external crate) building module {} {}",
@@ -552,10 +542,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                            trait_item_name);
 
                     self.trait_item_map.insert((trait_item_name, def_id), trait_item_def.def_id());
-
-                    if is_exported {
-                        self.external_exports.insert(trait_item_def.def_id());
-                    }
                 }
 
                 let parent_link = ModuleParentLink(new_parent, name);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index a205bfb98ac..970f54207ba 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -55,10 +55,9 @@ use rustc::middle::cstore::{CrateStore, DefLike, DlDef};
 use rustc::middle::def::*;
 use rustc::middle::def_id::DefId;
 use rustc::middle::pat_util::pat_bindings;
-use rustc::middle::privacy::ExternalExports;
 use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
 use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap};
-use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
+use rustc::util::nodemap::{NodeMap, FnvHashMap};
 
 use syntax::ast::{self, FloatTy};
 use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
@@ -1093,7 +1092,6 @@ pub struct Resolver<'a, 'tcx: 'a> {
     freevars_seen: NodeMap<NodeMap<usize>>,
     export_map: ExportMap,
     trait_map: TraitMap,
-    external_exports: ExternalExports,
 
     // Whether or not to print error messages. Can be set to true
     // when getting additional info for error message suggestions,
@@ -1184,7 +1182,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             trait_map: NodeMap(),
             used_imports: HashSet::new(),
             used_crates: HashSet::new(),
-            external_exports: DefIdSet(),
 
             emit_errors: true,
             make_glob_map: make_glob_map == MakeGlobMap::Yes,
@@ -3716,7 +3713,6 @@ pub struct CrateMap {
     pub freevars: FreevarMap,
     pub export_map: ExportMap,
     pub trait_map: TraitMap,
-    pub external_exports: ExternalExports,
     pub glob_map: Option<GlobMap>,
 }
 
@@ -3754,7 +3750,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
         freevars: resolver.freevars,
         export_map: resolver.export_map,
         trait_map: resolver.trait_map,
-        external_exports: resolver.external_exports,
         glob_map: if resolver.make_glob_map {
             Some(resolver.glob_map)
         } else {
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index e8368f1bd97..c5508a8268f 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -451,8 +451,8 @@ fn find_discr_field_candidate<'tcx>(tcx: &TyCtxt<'tcx>,
         // Regular thin pointer: &T/&mut T/Box<T>
         ty::TyRef(..) | ty::TyBox(..) => Some(path),
 
-        // Functions are just pointers
-        ty::TyBareFn(..) => Some(path),
+        // Function pointer: `fn() -> i32`
+        ty::TyFnPtr(_) => Some(path),
 
         // Is this the NonZero lang item wrapping a pointer or integer type?
         ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => {
diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs
index 33370abc3fc..98e9a1c98ad 100644
--- a/src/librustc_trans/trans/asm.rs
+++ b/src/librustc_trans/trans/asm.rs
@@ -50,7 +50,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                           expr_ty(bcx, &out.expr),
                                           out_datum,
                                           cleanup::CustomScope(temp_scope),
-                                          callee::DontAutorefArg,
                                           &mut inputs);
             if out.is_rw {
                 ext_inputs.push(*inputs.last().unwrap());
@@ -64,7 +63,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                               expr_ty(bcx, &out.expr),
                                               out_datum,
                                               cleanup::CustomScope(temp_scope),
-                                              callee::DontAutorefArg,
                                               &mut ext_inputs);
                 ext_constraints.push(i.to_string());
             }
@@ -80,7 +78,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                     expr_ty(bcx, &input),
                                     in_datum,
                                     cleanup::CustomScope(temp_scope),
-                                    callee::DontAutorefArg,
                                     &mut inputs);
     }
     inputs.extend_from_slice(&ext_inputs[..]);
diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs
index 8f9648b333b..009d43e813e 100644
--- a/src/librustc_trans/trans/attributes.rs
+++ b/src/librustc_trans/trans/attributes.rs
@@ -131,7 +131,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
 
     let function_type;
     let (fn_sig, abi, env_ty) = match fn_type.sty {
-        ty::TyBareFn(_, ref f) => (&f.sig, f.abi, None),
+        ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None),
         ty::TyClosure(closure_did, ref substs) => {
             let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
             function_type = infcx.closure_type(closure_did, substs);
@@ -162,7 +162,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
                 _ => ccx.sess().bug("expected tuple'd inputs")
             }
         },
-        ty::TyBareFn(..) if abi == Abi::RustCall => {
+        ty::TyFnDef(..) | ty::TyFnPtr(_) if abi == Abi::RustCall => {
             let mut inputs = vec![fn_sig.inputs[0]];
 
             match fn_sig.inputs[1].sty {
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 33d3d66adcd..5088dabfbe7 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -195,16 +195,14 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
 fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 fn_ty: Ty<'tcx>,
                                 name: &str,
-                                did: DefId)
+                                attrs: &[ast::Attribute])
                                 -> ValueRef {
     if let Some(n) = ccx.externs().borrow().get(name) {
         return *n;
     }
 
     let f = declare::declare_rust_fn(ccx, name, fn_ty);
-
-    let attrs = ccx.sess().cstore.item_attrs(did);
-    attributes::from_fn_attrs(ccx, &attrs[..], f);
+    attributes::from_fn_attrs(ccx, &attrs, f);
 
     ccx.externs().borrow_mut().insert(name.to_string(), f);
     f
@@ -216,13 +214,13 @@ pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                        -> Ty<'tcx> {
     let closure_kind = ccx.tcx().closure_kind(closure_id);
     match closure_kind {
-        ty::FnClosureKind => {
+        ty::ClosureKind::Fn => {
             ccx.tcx().mk_imm_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty)
         }
-        ty::FnMutClosureKind => {
+        ty::ClosureKind::FnMut => {
             ccx.tcx().mk_mut_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty)
         }
-        ty::FnOnceClosureKind => fn_ty,
+        ty::ClosureKind::FnOnce => fn_ty,
     }
 }
 
@@ -390,7 +388,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 _ => bcx.sess().bug("compare_scalar_types: must be a comparison operator"),
             }
         }
-        ty::TyBareFn(..) | ty::TyBool | ty::TyUint(_) | ty::TyChar => {
+        ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyBool | ty::TyUint(_) | ty::TyChar => {
             ICmp(bcx,
                  bin_op_to_icmp_predicate(bcx.ccx(), op, false),
                  lhs,
@@ -621,8 +619,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
 pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                                 source: Ty<'tcx>,
                                 target: Ty<'tcx>,
-                                old_info: Option<ValueRef>,
-                                param_substs: &'tcx Substs<'tcx>)
+                                old_info: Option<ValueRef>)
                                 -> ValueRef {
     let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
@@ -641,7 +638,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                 def_id: principal.def_id(),
                 substs: substs,
             });
-            consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
+            consts::ptrcast(meth::get_vtable(ccx, trait_ref),
                             Type::vtable_ptr(ccx))
         }
         _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}",
@@ -668,7 +665,7 @@ pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             assert!(common::type_is_sized(bcx.tcx(), a));
             let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to();
             (PointerCast(bcx, src, ptr_ty),
-             unsized_info(bcx.ccx(), a, b, None, bcx.fcx.param_substs))
+             unsized_info(bcx.ccx(), a, b, None))
         }
         _ => bcx.sess().bug("unsize_thin_ptr: called on bad types"),
     }
@@ -900,29 +897,31 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
     }
 }
 
-pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                     did: DefId,
-                                     t: Ty<'tcx>)
-                                     -> ValueRef {
-    let name = ccx.sess().cstore.item_symbol(did);
-    match t.sty {
-        ty::TyBareFn(_, ref fn_ty) => {
-            match ccx.sess().target.target.adjust_abi(fn_ty.abi) {
-                Abi::Rust | Abi::RustCall => {
-                    get_extern_rust_fn(ccx, t, &name[..], did)
-                }
+pub fn get_extern_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                               def_id: DefId)
+                               -> datum::Datum<'tcx, datum::Rvalue> {
+    let name = ccx.sess().cstore.item_symbol(def_id);
+    let attrs = ccx.sess().cstore.item_attrs(def_id);
+    let ty = ccx.tcx().lookup_item_type(def_id).ty;
+    match ty.sty {
+        ty::TyFnDef(_, _, fty) => {
+            let abi = fty.abi;
+            let fty = infer::normalize_associated_type(ccx.tcx(), fty);
+            let ty = ccx.tcx().mk_fn_ptr(fty);
+            let llfn = match ccx.sess().target.target.adjust_abi(abi) {
                 Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
-                    ccx.sess().bug("unexpected intrinsic in trans_external_path")
+                    ccx.sess().bug("unexpected intrinsic in get_extern_fn")
+                }
+                Abi::Rust | Abi::RustCall => {
+                    get_extern_rust_fn(ccx, ty, &name, &attrs)
                 }
                 _ => {
-                    let attrs = ccx.sess().cstore.item_attrs(did);
-                    foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name, &attrs)
+                    foreign::register_foreign_item_fn(ccx, abi, ty, &name, &attrs)
                 }
-            }
-        }
-        _ => {
-            get_extern_const(ccx, did, t)
+            };
+            datum::immediate_rvalue(llfn, ty)
         }
+        _ => unreachable!("get_extern_fn: expected fn item type, found {}", ty)
     }
 }
 
@@ -2610,7 +2609,7 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                          node_id: ast::NodeId,
                          node_type: Ty<'tcx>)
                          -> ValueRef {
-    if let ty::TyBareFn(_, ref f) = node_type.sty {
+    if let ty::TyFnDef(_, _, ref f) = node_type.sty {
         if f.abi != Abi::Rust && f.abi != Abi::RustCall {
             ccx.sess().span_bug(sp,
                                 &format!("only the `{}` or `{}` calling conventions are valid \
@@ -2685,8 +2684,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) {
                                                                .as_local_node_id(start_def_id) {
                     get_item_val(ccx, start_node_id)
                 } else {
-                    let start_fn_type = ccx.tcx().lookup_item_type(start_def_id).ty;
-                    trans_external_path(ccx, start_def_id, start_fn_type)
+                    get_extern_fn(ccx, start_def_id).val
                 };
                 let args = {
                     let opaque_rust_main =
@@ -2915,7 +2913,7 @@ fn register_method(ccx: &CrateContext,
 
     let sym = exported_name(ccx, id, mty, &attrs);
 
-    if let ty::TyBareFn(_, ref f) = mty.sty {
+    if let ty::TyFnDef(_, _, ref f) = mty.sty {
         let llfn = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
             register_fn(ccx, span, sym, id, mty)
         } else {
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index 5f8e31781f1..05e5ac808d0 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -14,7 +14,6 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-pub use self::AutorefArg::*;
 pub use self::CalleeData::*;
 pub use self::CallArgs::*;
 
@@ -22,7 +21,6 @@ use arena::TypedArena;
 use back::link;
 use llvm::{self, ValueRef, get_params};
 use middle::cstore::LOCAL_CRATE;
-use middle::def::Def;
 use middle::def_id::DefId;
 use middle::infer;
 use middle::subst;
@@ -32,14 +30,13 @@ use trans::adt;
 use trans::base;
 use trans::base::*;
 use trans::build::*;
-use trans::callee;
 use trans::cleanup;
 use trans::cleanup::CleanupMethods;
 use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext,
                     ExprOrMethodCall, FunctionContext, MethodCallKey};
 use trans::consts;
 use trans::datum::*;
-use trans::debuginfo::{DebugLoc, ToDebugLoc};
+use trans::debuginfo::DebugLoc;
 use trans::declare;
 use trans::expr;
 use trans::glue;
@@ -52,177 +49,148 @@ use trans::type_::Type;
 use trans::type_of;
 use trans::Disr;
 use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use middle::ty::MethodCall;
 use rustc_front::hir;
 
 use syntax::abi::Abi;
 use syntax::ast;
+use syntax::codemap::DUMMY_SP;
 use syntax::errors;
 use syntax::ptr::P;
 
-#[derive(Copy, Clone)]
-pub struct MethodData {
-    pub llfn: ValueRef,
-    pub llself: ValueRef,
-}
-
 pub enum CalleeData<'tcx> {
-    // Constructor for enum variant/tuple-like-struct
-    // i.e. Some, Ok
+    /// Constructor for enum variant/tuple-like-struct.
     NamedTupleConstructor(Disr),
 
-    // Represents a (possibly monomorphized) top-level fn item or method
-    // item. Note that this is just the fn-ptr and is not a Rust closure
-    // value (which is a pair).
-    Fn(/* llfn */ ValueRef),
+    /// Function pointer.
+    Fn(ValueRef),
 
-    Intrinsic(ast::NodeId, subst::Substs<'tcx>),
+    Intrinsic(ast::NodeId, &'tcx subst::Substs<'tcx>),
 
-    TraitItem(MethodData)
+    /// Trait object found in the vtable at that index.
+    Virtual(usize)
 }
 
-pub struct Callee<'blk, 'tcx: 'blk> {
-    pub bcx: Block<'blk, 'tcx>,
+pub struct Callee<'tcx> {
     pub data: CalleeData<'tcx>,
     pub ty: Ty<'tcx>
 }
 
-fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
-                     -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_callee");
-    debug!("callee::trans(expr={:?})", expr);
-
-    // pick out special kinds of expressions that can be called:
-    match expr.node {
-        hir::ExprPath(..) => {
-            return trans_def(bcx, bcx.def(expr.id), expr);
+impl<'tcx> Callee<'tcx> {
+    /// Function pointer.
+    pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
+        Callee {
+            data: Fn(datum.val),
+            ty: datum.ty
         }
-        _ => {}
     }
 
-    // any other expressions are closures:
-    return datum_callee(bcx, expr);
-
-    fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
-                                -> Callee<'blk, 'tcx> {
-        let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
-        match datum.ty.sty {
-            ty::TyBareFn(..) => {
-                Callee {
-                    bcx: bcx,
-                    ty: datum.ty,
-                    data: Fn(datum.to_llscalarish(bcx))
-                }
-            }
-            _ => {
-                bcx.tcx().sess.span_bug(
-                    expr.span,
-                    &format!("type of callee is neither bare-fn nor closure: {}",
-                             datum.ty));
-            }
-        }
+    /// Trait or impl method call.
+    pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
+                             method_call: ty::MethodCall)
+                             -> Callee<'tcx> {
+        let method = bcx.tcx().tables.borrow().method_map[&method_call];
+        Callee::method(bcx, method)
     }
 
-    fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>)
-                             -> Callee<'blk, 'tcx> {
-        Callee {
-            bcx: bcx,
-            data: Fn(datum.val),
-            ty: datum.ty
-        }
+    /// Trait or impl method.
+    pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
+                        method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
+        let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs));
+        let ty = bcx.fcx.monomorphize(&method.ty);
+        Callee::def(bcx.ccx(), method.def_id, substs, ty)
     }
 
-    fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             def: Def,
-                             ref_expr: &hir::Expr)
-                             -> Callee<'blk, 'tcx> {
-        debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
-        let expr_ty = common::node_id_type(bcx, ref_expr.id);
-        match def {
-            Def::Fn(did) if {
-                let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
-                let maybe_ast_node = maybe_def_id.and_then(|def_id| {
-                    let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
-                    bcx.tcx().map.find(node_id)
-                });
-                match maybe_ast_node {
-                    Some(hir_map::NodeStructCtor(_)) => true,
-                    _ => false
-                }
-            } => {
-                Callee {
-                    bcx: bcx,
+    /// Function or method definition.
+    pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
+                   def_id: DefId,
+                   substs: &'tcx subst::Substs<'tcx>,
+                   ty: Ty<'tcx>)
+                   -> Callee<'tcx> {
+        let tcx = ccx.tcx();
+
+        if substs.self_ty().is_some() {
+            // Only trait methods can have a Self parameter.
+            let method_item = tcx.impl_or_trait_item(def_id);
+            let trait_id = method_item.container().id();
+            let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
+            let vtbl = common::fulfill_obligation(ccx, DUMMY_SP, trait_ref);
+            return meth::callee_for_trait_impl(ccx, def_id, substs,
+                                               trait_id, ty, vtbl);
+        }
+
+        let maybe_node_id = inline::get_local_instance(ccx, def_id)
+            .and_then(|def_id| tcx.map.as_local_node_id(def_id));
+        let maybe_ast_node = maybe_node_id.and_then(|node_id| {
+            tcx.map.find(node_id)
+        });
+        match maybe_ast_node {
+            Some(hir_map::NodeStructCtor(_)) => {
+                return Callee {
                     data: NamedTupleConstructor(Disr(0)),
-                    ty: expr_ty
-                }
-            }
-            Def::Fn(did) if match expr_ty.sty {
-                ty::TyBareFn(_, ref f) => f.abi == Abi::RustIntrinsic ||
-                                          f.abi == Abi::PlatformIntrinsic,
-                _ => false
-            } => {
-                let substs = common::node_id_substs(bcx.ccx(),
-                                                    ExprId(ref_expr.id),
-                                                    bcx.fcx.param_substs);
-                let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
-                let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
-                Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
-            }
-            Def::Fn(did) => {
-                fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
-                                            bcx.fcx.param_substs))
-            }
-            Def::Method(meth_did) => {
-                let method_item = bcx.tcx().impl_or_trait_item(meth_did);
-                let fn_datum = match method_item.container() {
-                    ty::ImplContainer(_) => {
-                        trans_fn_ref(bcx.ccx(), meth_did,
-                                     ExprId(ref_expr.id),
-                                     bcx.fcx.param_substs)
-                    }
-                    ty::TraitContainer(trait_did) => {
-                        meth::trans_static_method_callee(bcx.ccx(),
-                                                         meth_did,
-                                                         trait_did,
-                                                         ref_expr.id,
-                                                         bcx.fcx.param_substs)
-                    }
+                    ty: ty
                 };
-                fn_callee(bcx, fn_datum)
             }
-            Def::Variant(tid, vid) => {
-                let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
+            Some(hir_map::NodeVariant(_)) => {
+                let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
                 assert_eq!(vinfo.kind(), ty::VariantKind::Tuple);
 
-                Callee {
-                    bcx: bcx,
+                return Callee {
                     data: NamedTupleConstructor(Disr::from(vinfo.disr_val)),
-                    ty: expr_ty
-                }
+                    ty: ty
+                };
             }
-            Def::Struct(..) => {
-                Callee {
-                    bcx: bcx,
-                    data: NamedTupleConstructor(Disr(0)),
-                    ty: expr_ty
+            Some(hir_map::NodeForeignItem(fi)) => {
+                let abi = tcx.map.get_foreign_abi(fi.id);
+                if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
+                    return Callee {
+                        data: Intrinsic(fi.id, substs),
+                        ty: ty
+                    };
                 }
             }
-            Def::Static(..) |
-            Def::Const(..) |
-            Def::AssociatedConst(..) |
-            Def::Local(..) |
-            Def::Upvar(..) => {
-                datum_callee(bcx, ref_expr)
-            }
-            Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) |
-            Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) |
-            Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) |
-            Def::SelfTy(..) | Def::Err => {
-                bcx.tcx().sess.span_bug(
-                    ref_expr.span,
-                    &format!("cannot translate def {:?} \
-                             to a callable thing!", def));
+            _ => {}
+        }
+        Callee::ptr(trans_fn_ref_with_substs(ccx, def_id, Some(ty), substs))
+    }
+
+    /// This behemoth of a function translates function calls. Unfortunately, in
+    /// order to generate more efficient LLVM output at -O0, it has quite a complex
+    /// signature (refactoring this into two functions seems like a good idea).
+    ///
+    /// In particular, for lang items, it is invoked with a dest of None, and in
+    /// that case the return value contains the result of the fn. The lang item must
+    /// not return a structural type or else all heck breaks loose.
+    ///
+    /// For non-lang items, `dest` is always Some, and hence the result is written
+    /// into memory somewhere. Nonetheless we return the actual return value of the
+    /// function.
+    pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
+                          debug_loc: DebugLoc,
+                          args: CallArgs<'a, 'tcx>,
+                          dest: Option<expr::Dest>)
+                          -> Result<'blk, 'tcx> {
+        trans_call_inner(bcx, debug_loc, self, args, dest)
+    }
+
+    /// Turn the callee into a function pointer.
+    pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
+                     -> Datum<'tcx, Rvalue> {
+        match self.data {
+            Fn(llfn) => {
+                let fn_ptr_ty = match self.ty.sty {
+                    ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
+                    _ => self.ty
+                };
+                immediate_rvalue(llfn, fn_ptr_ty)
             }
+            Virtual(idx) => meth::trans_object_shim(ccx, self.ty, idx),
+            NamedTupleConstructor(_) => match self.ty.sty {
+                ty::TyFnDef(def_id, substs, _) => {
+                    return trans_fn_ref_with_substs(ccx, def_id, Some(self.ty), substs);
+                }
+                _ => unreachable!("expected fn item type, found {}", self.ty)
+            },
+            Intrinsic(..) => unreachable!("intrinsic {} getting reified", self.ty)
         }
     }
 }
@@ -241,7 +209,17 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            def_id,
            node,
            substs);
-    trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
+    let ref_ty = match node {
+        ExprId(0) => return trans_fn_ref_with_substs(ccx, def_id, None, substs),
+        ExprId(id) => ccx.tcx().node_id_to_type(id),
+        MethodCallKey(method_call) => {
+            ccx.tcx().tables.borrow().method_map[&method_call].ty
+        }
+    };
+    let ref_ty = monomorphize::apply_param_substs(ccx.tcx(),
+                                                  param_substs,
+                                                  &ref_ty);
+    trans_fn_ref_with_substs(ccx, def_id, Some(ref_ty), substs)
 }
 
 /// Translates an adapter that implements the `Fn` trait for a fn
@@ -270,8 +248,8 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 
     // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
     let is_by_ref = match closure_kind {
-        ty::FnClosureKind | ty::FnMutClosureKind => true,
-        ty::FnOnceClosureKind => false,
+        ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true,
+        ty::ClosureKind::FnOnce => false,
     };
     let bare_fn_ty_maybe_ref = if is_by_ref {
         tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty)
@@ -290,33 +268,33 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
-    let (opt_def_id, sig) =
-        match bare_fn_ty.sty {
-            ty::TyBareFn(opt_def_id,
-                           &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
-                                           abi: Abi::Rust,
-                                           ref sig }) => {
-                (opt_def_id, sig)
-            }
+    let sig = match bare_fn_ty.sty {
+        ty::TyFnDef(_, _,
+                    &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
+                                    abi: Abi::Rust,
+                                    ref sig }) |
+        ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
+                                    abi: Abi::Rust,
+                                    ref sig }) => sig,
 
-            _ => {
-                tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
-                                      bare_fn_ty));
-            }
-        };
+        _ => {
+            tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
+                                    bare_fn_ty));
+        }
+    };
     let sig = tcx.erase_late_bound_regions(sig);
     let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
     let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
-    let tuple_fn_ty = tcx.mk_fn(opt_def_id,
-        tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: hir::Unsafety::Normal,
-            abi: Abi::RustCall,
-            sig: ty::Binder(ty::FnSig {
-                inputs: vec![bare_fn_ty_maybe_ref,
-                             tuple_input_ty],
-                output: sig.output,
-                variadic: false
-            })}));
+    let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
+        unsafety: hir::Unsafety::Normal,
+        abi: Abi::RustCall,
+        sig: ty::Binder(ty::FnSig {
+            inputs: vec![bare_fn_ty_maybe_ref,
+                         tuple_input_ty],
+            output: sig.output,
+            variadic: false
+        })
+    });
     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
 
     //
@@ -341,11 +319,18 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     let llargs = get_params(fcx.llfn);
 
     let self_idx = fcx.arg_offset();
-    // the first argument (`self`) will be ptr to the fn pointer
-    let llfnpointer = if is_by_ref {
-        Load(bcx, llargs[self_idx])
-    } else {
-        llargs[self_idx]
+    let llfnpointer = match bare_fn_ty.sty {
+        ty::TyFnDef(def_id, substs, _) => {
+            // Function definitions have to be turned into a pointer.
+            Callee::def(ccx, def_id, substs, bare_fn_ty).reify(ccx).val
+        }
+
+        // the first argument (`self`) will be ptr to the fn pointer
+        _ => if is_by_ref {
+            Load(bcx, llargs[self_idx])
+        } else {
+            llargs[self_idx]
+        }
     };
 
     assert!(!fcx.needs_ret_allocas);
@@ -354,13 +339,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
         expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
     );
 
-    bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
-        Callee {
-            bcx: bcx,
-            data: Fn(llfnpointer),
-            ty: bare_fn_ty
-        }
-    }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
+    let callee = Callee {
+        data: Fn(llfnpointer),
+        ty: bare_fn_ty
+    };
+    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
 
     finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
 
@@ -379,30 +362,25 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 /// - `node`: node id of the reference to the fn/method, if applicable.
 ///   This parameter may be zero; but, if so, the resulting value may not
 ///   have the right type, so it must be cast before being used.
-/// - `param_substs`: if the `node` is in a polymorphic function, these
-///   are the substitutions required to monomorphize its type
+/// - `ref_ty`: monotype of the reference to the fn/method, if applicable.
+///   This parameter may be None; but, if so, the resulting value may not
+///   have the right type, so it must be cast before being used.
 /// - `substs`: values for each of the fn/method's parameters
 pub fn trans_fn_ref_with_substs<'a, 'tcx>(
     ccx: &CrateContext<'a, 'tcx>,
     def_id: DefId,
-    node: ExprOrMethodCall,
-    param_substs: &'tcx subst::Substs<'tcx>,
-    substs: subst::Substs<'tcx>)
+    ref_ty: Option<Ty<'tcx>>,
+    substs: &'tcx subst::Substs<'tcx>)
     -> Datum<'tcx, Rvalue>
 {
     let _icx = push_ctxt("trans_fn_ref_with_substs");
     let tcx = ccx.tcx();
 
-    debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
-            param_substs={:?}, substs={:?})",
-           def_id,
-           node,
-           param_substs,
-           substs);
+    debug!("trans_fn_ref_with_substs(def_id={:?}, ref_ty={:?}, substs={:?})",
+           def_id, ref_ty, substs);
 
     assert!(!substs.types.needs_infer());
     assert!(!substs.types.has_escaping_regions());
-    let substs = substs.erase_regions();
 
     // Check whether this fn has an inlined copy and, if so, redirect
     // def_id to the local id of the inlined copy.
@@ -437,48 +415,45 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
         // Should be either intra-crate or inlined.
         assert_eq!(def_id.krate, LOCAL_CRATE);
 
-        let opt_ref_id = match node {
-            ExprId(id) => if id != 0 { Some(id) } else { None },
-            MethodCallKey(_) => None,
+        let substs = tcx.mk_substs(substs.clone().erase_regions());
+        let (mut val, fn_ty, must_cast) =
+            monomorphize::monomorphic_fn(ccx, def_id, substs);
+        let fn_ty = ref_ty.unwrap_or(fn_ty);
+        let fn_ptr_ty = match fn_ty.sty {
+            ty::TyFnDef(_, _, fty) => {
+                // Create a fn pointer with the substituted signature.
+                tcx.mk_ty(ty::TyFnPtr(fty))
+            }
+            _ => unreachable!("expected fn item type, found {}", fn_ty)
         };
-
-        let substs = tcx.mk_substs(substs);
-        let (val, fn_ty, must_cast) =
-            monomorphize::monomorphic_fn(ccx, def_id, substs, opt_ref_id);
-        if must_cast && node != ExprId(0) {
-            // Monotype of the REFERENCE to the function (type params
-            // are subst'd)
-            let ref_ty = match node {
-                ExprId(id) => tcx.node_id_to_type(id),
-                MethodCallKey(method_call) => {
-                    tcx.tables.borrow().method_map[&method_call].ty
-                }
-            };
-            let ref_ty = monomorphize::apply_param_substs(tcx,
-                                                          param_substs,
-                                                          &ref_ty);
-            let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to();
+        if must_cast && ref_ty.is_some() {
+            let llptrty = type_of::type_of(ccx, fn_ptr_ty);
             if llptrty != common::val_ty(val) {
-                let val = consts::ptrcast(val, llptrty);
-                return Datum::new(val, ref_ty, Rvalue::new(ByValue));
+                val = consts::ptrcast(val, llptrty);
             }
         }
-        return Datum::new(val, fn_ty, Rvalue::new(ByValue));
+        return immediate_rvalue(val, fn_ptr_ty);
     }
 
-    // Type scheme of the function item (may have type params)
-    let fn_type_scheme = tcx.lookup_item_type(def_id);
-    let fn_type = infer::normalize_associated_type(tcx, &fn_type_scheme.ty);
-
     // Find the actual function pointer.
-    let mut val = {
-        if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
-            // Internal reference.
-            get_item_val(ccx, node_id)
-        } else {
-            // External reference.
-            trans_external_path(ccx, def_id, fn_type)
-        }
+    let local_node = ccx.tcx().map.as_local_node_id(def_id);
+    let mut datum = if let Some(node_id) = local_node {
+        // Type scheme of the function item (may have type params)
+        let fn_type_scheme = tcx.lookup_item_type(def_id);
+        let fn_type = match fn_type_scheme.ty.sty {
+            ty::TyFnDef(_, _, fty) => {
+                // Create a fn pointer with the normalized signature.
+                tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty))
+            }
+            _ => unreachable!("expected fn item type, found {}",
+                              fn_type_scheme.ty)
+        };
+
+        // Internal reference.
+        immediate_rvalue(get_item_val(ccx, node_id), fn_type)
+    } else {
+        // External reference.
+        get_extern_fn(ccx, def_id)
     };
 
     // This is subtle and surprising, but sometimes we have to bitcast
@@ -504,93 +479,36 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
     // This can occur on either a crate-local or crate-external
     // reference. It also occurs when testing libcore and in some
     // other weird situations. Annoying.
-    let llty = type_of::type_of_fn_from_ty(ccx, fn_type);
-    let llptrty = llty.ptr_to();
-    if common::val_ty(val) != llptrty {
+    let llptrty = type_of::type_of(ccx, datum.ty);
+    if common::val_ty(datum.val) != llptrty {
         debug!("trans_fn_ref_with_substs(): casting pointer!");
-        val = consts::ptrcast(val, llptrty);
+        datum.val = consts::ptrcast(datum.val, llptrty);
     } else {
         debug!("trans_fn_ref_with_substs(): not casting pointer!");
     }
 
-    Datum::new(val, fn_type, Rvalue::new(ByValue))
+    datum
 }
 
 // ______________________________________________________________________
 // Translating calls
 
-pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  call_expr: &hir::Expr,
-                                  f: &hir::Expr,
-                                  args: CallArgs<'a, 'tcx>,
-                                  dest: expr::Dest)
-                                  -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_call");
-    trans_call_inner(bcx,
-                     call_expr.debug_loc(),
-                     |bcx, _| trans(bcx, f),
-                     args,
-                     Some(dest)).bcx
-}
-
-pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                         call_expr: &hir::Expr,
-                                         rcvr: &hir::Expr,
-                                         args: CallArgs<'a, 'tcx>,
-                                         dest: expr::Dest)
-                                         -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_method_call");
-    debug!("trans_method_call(call_expr={:?})", call_expr);
-    let method_call = MethodCall::expr(call_expr.id);
-    trans_call_inner(
-        bcx,
-        call_expr.debug_loc(),
-        |cx, arg_cleanup_scope| {
-            meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
-        },
-        args,
-        Some(dest)).bcx
-}
-
 pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    did: DefId,
                                    args: &[ValueRef],
                                    dest: Option<expr::Dest>,
                                    debug_loc: DebugLoc)
                                    -> Result<'blk, 'tcx> {
-    callee::trans_call_inner(bcx, debug_loc, |bcx, _| {
-        let datum = trans_fn_ref_with_substs(bcx.ccx(),
-                                             did,
-                                             ExprId(0),
-                                             bcx.fcx.param_substs,
-                                             subst::Substs::trans_empty());
-        Callee {
-            bcx: bcx,
-            data: Fn(datum.val),
-            ty: datum.ty
-        }
-    }, ArgVals(args), dest)
+    let datum = trans_fn_ref(bcx.ccx(), did, ExprId(0), bcx.fcx.param_substs);
+    Callee::ptr(datum).call(bcx, debug_loc, ArgVals(args), dest)
 }
 
-/// This behemoth of a function translates function calls. Unfortunately, in
-/// order to generate more efficient LLVM output at -O0, it has quite a complex
-/// signature (refactoring this into two functions seems like a good idea).
-///
-/// In particular, for lang items, it is invoked with a dest of None, and in
-/// that case the return value contains the result of the fn. The lang item must
-/// not return a structural type or else all heck breaks loose.
-///
-/// For non-lang items, `dest` is always Some, and hence the result is written
-/// into memory somewhere. Nonetheless we return the actual return value of the
-/// function.
-pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                           debug_loc: DebugLoc,
-                                           get_callee: F,
-                                           args: CallArgs<'a, 'tcx>,
-                                           dest: Option<expr::Dest>)
-                                           -> Result<'blk, 'tcx> where
-    F: FnOnce(Block<'blk, 'tcx>, cleanup::ScopeId) -> Callee<'blk, 'tcx>,
-{
+fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
+                                    debug_loc: DebugLoc,
+                                    callee: Callee<'tcx>,
+                                    args: CallArgs<'a, 'tcx>,
+                                    dest: Option<expr::Dest>)
+                                    -> Result<'blk, 'tcx> {
     // Introduce a temporary cleanup scope that will contain cleanups
     // for the arguments while they are being evaluated. The purpose
     // this cleanup is to ensure that, should a panic occur while
@@ -600,27 +518,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
     // scope will ever execute.
     let fcx = bcx.fcx;
     let ccx = fcx.ccx;
-    let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
-
-    let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
-    let mut bcx = callee.bcx;
 
     let (abi, ret_ty) = match callee.ty.sty {
-        ty::TyBareFn(_, ref f) => {
+        ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
             let sig = bcx.tcx().erase_late_bound_regions(&f.sig);
             let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
             (f.abi, sig.output)
         }
-        _ => panic!("expected bare rust fn or closure in trans_call_inner")
+        _ => panic!("expected fn item or ptr in Callee::call")
     };
 
-    let (llfn, llself) = match callee.data {
-        Fn(llfn) => {
-            (llfn, None)
-        }
-        TraitItem(d) => {
-            (d.llfn, Some(d.llself))
-        }
+    match callee.data {
         Intrinsic(node, substs) => {
             assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
             assert!(dest.is_some());
@@ -632,14 +540,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                 }
             };
 
+            let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
             return intrinsic::trans_intrinsic_call(bcx, node, callee.ty,
                                                    arg_cleanup_scope, args,
-                                                   dest.unwrap(), substs,
+                                                   dest.unwrap(),
+                                                   substs,
                                                    call_info);
         }
         NamedTupleConstructor(disr) => {
             assert!(dest.is_some());
-            fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
 
             return base::trans_named_tuple_constructor(bcx,
                                                        callee.ty,
@@ -648,7 +557,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                                                        dest.unwrap(),
                                                        debug_loc);
         }
-    };
+        _ => {}
+    }
 
     // Intrinsics should not become actual functions.
     // We trans them in place in `trans_intrinsic_call`
@@ -688,6 +598,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
     };
 
+    let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
+
     // The code below invokes the function, using either the Rust
     // conventions (if it is a rust fn) or the native conventions
     // (otherwise).  The important part is that, when all is said
@@ -711,10 +623,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
             }
         }
 
-        // Push a trait object's self.
-        if let Some(llself) = llself {
-            llargs.push(llself);
-        }
+        let arg_start = llargs.len();
 
         // Push the arguments.
         bcx = trans_args(bcx,
@@ -722,16 +631,25 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                          callee.ty,
                          &mut llargs,
                          cleanup::CustomScope(arg_cleanup_scope),
-                         llself.is_some(),
                          abi);
 
         fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
 
+        let datum = match callee.data {
+            Fn(f) => immediate_rvalue(f, callee.ty),
+            Virtual(idx) => {
+                // The data and vtable pointers were split by trans_arg_datum.
+                let vtable = llargs.remove(arg_start + 1);
+                meth::get_virtual_method(bcx, vtable, idx, callee.ty)
+            }
+            _ => unreachable!()
+        };
+
         // Invoke the actual rust fn and update bcx/llresult.
         let (llret, b) = base::invoke(bcx,
-                                      llfn,
+                                      datum.val,
                                       &llargs[..],
-                                      callee.ty,
+                                      datum.ty,
                                       debug_loc);
         bcx = b;
         llresult = llret;
@@ -754,16 +672,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         assert!(dest.is_some());
 
         let mut llargs = Vec::new();
-        let arg_tys = match args {
-            ArgExprs(a) => a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect(),
-            _ => panic!("expected arg exprs.")
+        let (llfn, arg_tys) = match (callee.data, &args) {
+            (Fn(f), &ArgExprs(a)) => {
+                (f, a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect())
+            }
+            _ => panic!("expected fn ptr and arg exprs.")
         };
         bcx = trans_args(bcx,
                          args,
                          callee.ty,
                          &mut llargs,
                          cleanup::CustomScope(arg_cleanup_scope),
-                         false,
                          abi);
         fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
 
@@ -800,23 +719,22 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
 }
 
 pub enum CallArgs<'a, 'tcx> {
-    // Supply value of arguments as a list of expressions that must be
-    // translated. This is used in the common case of `foo(bar, qux)`.
+    /// Supply value of arguments as a list of expressions that must be
+    /// translated. This is used in the common case of `foo(bar, qux)`.
     ArgExprs(&'a [P<hir::Expr>]),
 
-    // Supply value of arguments as a list of LLVM value refs; frequently
-    // used with lang items and so forth, when the argument is an internal
-    // value.
+    /// Supply value of arguments as a list of LLVM value refs; frequently
+    /// used with lang items and so forth, when the argument is an internal
+    /// value.
     ArgVals(&'a [ValueRef]),
 
-    // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
-    // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
-    // the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
-    // arguments should be auto-referenced
-    ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
+    /// For overloaded operators: `(lhs, Option(rhs))`.
+    /// `lhs` is the left-hand-side and `rhs` is the datum
+    /// of the right-hand-side argument (if any).
+    ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>),
 
-    // Supply value of arguments as a list of expressions that must be
-    // translated, for overloaded call operators.
+    /// Supply value of arguments as a list of expressions that must be
+    /// translated, for overloaded call operators.
     ArgOverloadedCall(Vec<&'a hir::Expr>),
 }
 
@@ -825,8 +743,7 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
                              arg_exprs: &[P<hir::Expr>],
                              fn_ty: Ty<'tcx>,
                              llargs: &mut Vec<ValueRef>,
-                             arg_cleanup_scope: cleanup::ScopeId,
-                             ignore_self: bool)
+                             arg_cleanup_scope: cleanup::ScopeId)
                              -> Block<'blk, 'tcx>
 {
     let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
@@ -834,15 +751,12 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
     let args = sig.inputs;
 
     // Translate the `self` argument first.
-    if !ignore_self {
-        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
-        bcx = trans_arg_datum(bcx,
-                              args[0],
-                              arg_datum,
-                              arg_cleanup_scope,
-                              DontAutorefArg,
-                              llargs);
-    }
+    let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
+    bcx = trans_arg_datum(bcx,
+                          args[0],
+                          arg_datum,
+                          arg_cleanup_scope,
+                          llargs);
 
     // Now untuple the rest of the arguments.
     let tuple_expr = &arg_exprs[1];
@@ -870,7 +784,6 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
                                       field_type,
                                       arg_datum,
                                       arg_cleanup_scope,
-                                      DontAutorefArg,
                                       llargs);
             }
         }
@@ -888,23 +801,19 @@ fn trans_overloaded_call_args<'blk, 'tcx>(
                               arg_exprs: Vec<&hir::Expr>,
                               fn_ty: Ty<'tcx>,
                               llargs: &mut Vec<ValueRef>,
-                              arg_cleanup_scope: cleanup::ScopeId,
-                              ignore_self: bool)
+                              arg_cleanup_scope: cleanup::ScopeId)
                               -> Block<'blk, 'tcx> {
     // Translate the `self` argument first.
     let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
     let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
     let arg_tys = sig.inputs;
 
-    if !ignore_self {
-        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
-        bcx = trans_arg_datum(bcx,
-                              arg_tys[0],
-                              arg_datum,
-                              arg_cleanup_scope,
-                              DontAutorefArg,
-                              llargs);
-    }
+    let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
+    bcx = trans_arg_datum(bcx,
+                          arg_tys[0],
+                          arg_datum,
+                          arg_cleanup_scope,
+                          llargs);
 
     // Now untuple the rest of the arguments.
     let tuple_type = arg_tys[1];
@@ -917,7 +826,6 @@ fn trans_overloaded_call_args<'blk, 'tcx>(
                                       field_type,
                                       arg_datum,
                                       arg_cleanup_scope,
-                                      DontAutorefArg,
                                       llargs);
             }
         }
@@ -935,7 +843,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                   fn_ty: Ty<'tcx>,
                                   llargs: &mut Vec<ValueRef>,
                                   arg_cleanup_scope: cleanup::ScopeId,
-                                  ignore_self: bool,
                                   abi: Abi)
                                   -> Block<'blk, 'tcx> {
     debug!("trans_args(abi={})", abi);
@@ -960,15 +867,11 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                                  arg_exprs,
                                                  fn_ty,
                                                  llargs,
-                                                 arg_cleanup_scope,
-                                                 ignore_self)
+                                                 arg_cleanup_scope)
             }
 
             let num_formal_args = arg_tys.len();
             for (i, arg_expr) in arg_exprs.iter().enumerate() {
-                if i == 0 && ignore_self {
-                    continue;
-                }
                 let arg_ty = if i >= num_formal_args {
                     assert!(variadic);
                     common::expr_ty_adjusted(cx, &arg_expr)
@@ -979,7 +882,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
                 bcx = trans_arg_datum(bcx, arg_ty, arg_datum,
                                       arg_cleanup_scope,
-                                      DontAutorefArg,
                                       llargs);
             }
         }
@@ -988,22 +890,19 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                               arg_exprs,
                                               fn_ty,
                                               llargs,
-                                              arg_cleanup_scope,
-                                              ignore_self)
+                                              arg_cleanup_scope)
         }
-        ArgOverloadedOp(lhs, rhs, autoref) => {
+        ArgOverloadedOp(lhs, rhs) => {
             assert!(!variadic);
 
             bcx = trans_arg_datum(bcx, arg_tys[0], lhs,
                                   arg_cleanup_scope,
-                                  DontAutorefArg,
                                   llargs);
 
-            if let Some((rhs, rhs_id)) = rhs {
+            if let Some(rhs) = rhs {
                 assert_eq!(arg_tys.len(), 2);
                 bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
                                       arg_cleanup_scope,
-                                      if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg },
                                       llargs);
             } else {
                 assert_eq!(arg_tys.len(), 1);
@@ -1017,17 +916,10 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
     bcx
 }
 
-#[derive(Copy, Clone)]
-pub enum AutorefArg {
-    DontAutorefArg,
-    DoAutorefArg(ast::NodeId)
-}
-
 pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    formal_arg_ty: Ty<'tcx>,
                                    arg_datum: Datum<'tcx, Expr>,
                                    arg_cleanup_scope: cleanup::ScopeId,
-                                   autoref_arg: AutorefArg,
                                    llargs: &mut Vec<ValueRef>)
                                    -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_arg_datum");
@@ -1041,37 +933,25 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     debug!("   arg datum: {}", arg_datum.to_string(bcx.ccx()));
 
-    let mut val;
-    // FIXME(#3548) use the adjustments table
-    match autoref_arg {
-        DoAutorefArg(arg_id) => {
-            // We will pass argument by reference
-            // We want an lvalue, so that we can pass by reference and
-            let arg_datum = unpack_datum!(
-                bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
-            val = arg_datum.val;
-        }
-        DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
-                !bcx.fcx.type_needs_drop(arg_datum_ty) => {
-            val = arg_datum.val
-        }
-        DontAutorefArg => {
-            // Make this an rvalue, since we are going to be
-            // passing ownership.
-            let arg_datum = unpack_datum!(
-                bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
-
-            // Now that arg_datum is owned, get it into the appropriate
-            // mode (ref vs value).
-            let arg_datum = unpack_datum!(
-                bcx, arg_datum.to_appropriate_datum(bcx));
-
-            // Technically, ownership of val passes to the callee.
-            // However, we must cleanup should we panic before the
-            // callee is actually invoked.
-            val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope);
-        }
-    }
+    let mut val = if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
+                     !bcx.fcx.type_needs_drop(arg_datum_ty) {
+        arg_datum.val
+    } else {
+        // Make this an rvalue, since we are going to be
+        // passing ownership.
+        let arg_datum = unpack_datum!(
+            bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
+
+        // Now that arg_datum is owned, get it into the appropriate
+        // mode (ref vs value).
+        let arg_datum = unpack_datum!(
+            bcx, arg_datum.to_appropriate_datum(bcx));
+
+        // Technically, ownership of val passes to the callee.
+        // However, we must cleanup should we panic before the
+        // callee is actually invoked.
+        arg_datum.add_clean(bcx.fcx, arg_cleanup_scope)
+    };
 
     if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty {
         // this could happen due to e.g. subtyping
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index b1db196ecef..95ca250e844 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -17,7 +17,7 @@ use trans::adt;
 use trans::attributes;
 use trans::base::*;
 use trans::build::*;
-use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData};
+use trans::callee::{self, ArgVals, Callee};
 use trans::cleanup::{CleanupMethods, CustomScope, ScopeId};
 use trans::common::*;
 use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue};
@@ -49,7 +49,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let closure_ty = node_id_type(bcx, bcx.fcx.id);
     let self_type = self_type_for_closure(bcx.ccx(), closure_def_id, closure_ty);
     let kind = kind_for_closure(bcx.ccx(), closure_def_id);
-    let llenv = if kind == ty::FnOnceClosureKind &&
+    let llenv = if kind == ty::ClosureKind::FnOnce &&
             !arg_is_indirect(bcx.ccx(), self_type) {
         let datum = rvalue_scratch_datum(bcx,
                                          self_type,
@@ -85,7 +85,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let node_id = freevar.def.var_id();
         bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr);
 
-        if kind == ty::FnOnceClosureKind && !captured_by_ref {
+        if kind == ty::ClosureKind::FnOnce && !captured_by_ref {
             let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id);
             bcx.fcx.schedule_drop_mem(arg_scope_id,
                                       upvar_ptr,
@@ -271,24 +271,8 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
 
     // If the closure is a Fn closure, but a FnOnce is needed (etc),
     // then adapt the self type
-    let closure_kind = ccx.tcx().closure_kind(closure_def_id);
-    trans_closure_adapter_shim(ccx,
-                               closure_def_id,
-                               substs,
-                               closure_kind,
-                               trait_closure_kind,
-                               llfn)
-}
+    let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
 
-fn trans_closure_adapter_shim<'a, 'tcx>(
-    ccx: &'a CrateContext<'a, 'tcx>,
-    closure_def_id: DefId,
-    substs: ty::ClosureSubsts<'tcx>,
-    llfn_closure_kind: ty::ClosureKind,
-    trait_closure_kind: ty::ClosureKind,
-    llfn: ValueRef)
-    -> ValueRef
-{
     let _icx = push_ctxt("trans_closure_adapter_shim");
     let tcx = ccx.tcx();
 
@@ -300,20 +284,20 @@ fn trans_closure_adapter_shim<'a, 'tcx>(
            ccx.tn().val_to_string(llfn));
 
     match (llfn_closure_kind, trait_closure_kind) {
-        (ty::FnClosureKind, ty::FnClosureKind) |
-        (ty::FnMutClosureKind, ty::FnMutClosureKind) |
-        (ty::FnOnceClosureKind, ty::FnOnceClosureKind) => {
+        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
+        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
             // No adapter needed.
             llfn
         }
-        (ty::FnClosureKind, ty::FnMutClosureKind) => {
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
             // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
             // `fn(&mut self, ...)`. In fact, at trans time, these are
             // basically the same thing, so we can just return llfn.
             llfn
         }
-        (ty::FnClosureKind, ty::FnOnceClosureKind) |
-        (ty::FnMutClosureKind, ty::FnOnceClosureKind) => {
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
             // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
             // self, ...)`.  We want a `fn(self, ...)`. We can produce
             // this by doing something like:
@@ -355,28 +339,31 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     // Make a version with the type of by-ref closure.
     let ty::ClosureTy { unsafety, abi, mut sig } = infcx.closure_type(closure_def_id, &substs);
     sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
-    let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety,
-                                                               abi: abi,
-                                                               sig: sig.clone() });
-    let llref_fn_ty = tcx.mk_fn(None, llref_bare_fn_ty);
+    let llref_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
+        unsafety: unsafety,
+        abi: abi,
+        sig: sig.clone()
+    });
     debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
            llref_fn_ty);
 
+    let ret_ty = tcx.erase_late_bound_regions(&sig.output());
+    let ret_ty = infer::normalize_associated_type(ccx.tcx(), &ret_ty);
+
     // Make a version of the closure type with the same arguments, but
     // with argument #0 being by value.
     assert_eq!(abi, RustCall);
     sig.0.inputs[0] = closure_ty;
-    let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety,
-                                                                abi: abi,
-                                                                sig: sig });
-    let llonce_fn_ty = tcx.mk_fn(None, llonce_bare_fn_ty);
+    let llonce_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
+        unsafety: unsafety,
+        abi: abi,
+        sig: sig
+    });
 
     // Create the by-value helper.
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
     let lloncefn = declare::define_internal_rust_fn(ccx, &function_name,
                                                     llonce_fn_ty);
-    let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig);
-    let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
 
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
     block_arena = TypedArena::new();
@@ -384,13 +371,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
                       lloncefn,
                       ast::DUMMY_NODE_ID,
                       false,
-                      sig.output,
+                      ret_ty,
                       substs.func_substs,
                       None,
                       &block_arena);
-    let mut bcx = init_function(&fcx, false, sig.output);
+    let mut bcx = init_function(&fcx, false, ret_ty);
 
-    let llargs = get_params(fcx.llfn);
+    let mut llargs = get_params(fcx.llfn);
 
     // the first argument (`self`) will be the (by value) closure env.
     let self_scope = fcx.push_custom_cleanup_scope();
@@ -405,25 +392,21 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     debug!("trans_fn_once_adapter_shim: env_datum={}",
            bcx.val_to_string(env_datum.val));
+    llargs[self_idx] = env_datum.val;
 
     let dest =
         fcx.llretslotptr.get().map(
-            |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
-
-    let callee_data = TraitItem(MethodData { llfn: llreffn,
-                                             llself: env_datum.val });
+            |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot")));
 
-    bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
-        Callee {
-            bcx: bcx,
-            data: callee_data,
-            ty: llref_fn_ty
-        }
-    }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
+    let callee = Callee {
+        data: callee::Fn(llreffn),
+        ty: llref_fn_ty
+    };
+    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
 
     fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
 
-    finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
+    finish_fn(&fcx, bcx, ret_ty, DebugLoc::None);
 
     lloncefn
 }
diff --git a/src/librustc_trans/trans/collector.rs b/src/librustc_trans/trans/collector.rs
index b5b0f0a82d4..abfd127f388 100644
--- a/src/librustc_trans/trans/collector.rs
+++ b/src/librustc_trans/trans/collector.rs
@@ -542,14 +542,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         debug!("visiting operand {:?}", *operand);
 
         let callee = match *operand {
-            mir::Operand::Constant(mir::Constant {
-                literal: mir::Literal::Item {
-                    def_id,
-                    kind,
-                    substs
-                },
-                ..
-            }) if is_function_or_method(kind) => Some((def_id, substs)),
+            mir::Operand::Constant(mir::Constant { ty: &ty::TyS {
+                sty: ty::TyFnDef(def_id, substs, _), ..
+            }, .. }) => Some((def_id, substs)),
             _ => None
         };
 
@@ -588,25 +583,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
         self.super_operand(operand);
 
-        fn is_function_or_method(item_kind: mir::ItemKind) -> bool {
-            match item_kind {
-                mir::ItemKind::Constant => false,
-                mir::ItemKind::Function |
-                mir::ItemKind::Method   => true
-            }
-        }
-
         fn can_result_in_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                               def_id: DefId)
                                               -> bool {
             if !match ccx.tcx().lookup_item_type(def_id).ty.sty {
-                ty::TyBareFn(Some(def_id), _) => {
-                    // Some constructors also have type TyBareFn but they are
+                ty::TyFnDef(def_id, _, _) => {
+                    // Some constructors also have type TyFnDef but they are
                     // always instantiated inline and don't result in
-                    // translation item.
+                    // translation item. Same for FFI functions.
                     match ccx.tcx().map.get_if_local(def_id) {
                         Some(hir_map::NodeVariant(_))    |
-                        Some(hir_map::NodeStructCtor(_)) => false,
+                        Some(hir_map::NodeStructCtor(_)) |
+                        Some(hir_map::NodeForeignItem(_)) => false,
                         Some(_) => true,
                         None => {
                             ccx.sess().cstore.variant_kind(def_id).is_none()
@@ -689,7 +677,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         if can_have_local_instance(ccx, destructor_did) {
             let trans_item = create_fn_trans_item(ccx,
                                                   destructor_did,
-                                                  ccx.tcx().mk_substs(substs),
+                                                  substs,
                                                   &Substs::trans_empty());
             output.push(trans_item);
         }
@@ -697,17 +685,18 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     // Finally add the types of nested values
     match ty.sty {
-        ty::TyBool       |
-        ty::TyChar       |
-        ty::TyInt(_)     |
-        ty::TyUint(_)    |
-        ty::TyStr        |
-        ty::TyFloat(_)   |
-        ty::TyRawPtr(_)  |
-        ty::TyRef(..)    |
-        ty::TyBareFn(..) |
-        ty::TySlice(_)   |
-        ty::TyTrait(_)   => {
+        ty::TyBool      |
+        ty::TyChar      |
+        ty::TyInt(_)    |
+        ty::TyUint(_)   |
+        ty::TyStr       |
+        ty::TyFloat(_)  |
+        ty::TyRawPtr(_) |
+        ty::TyRef(..)   |
+        ty::TyFnDef(..) |
+        ty::TyFnPtr(_)  |
+        ty::TySlice(_)  |
+        ty::TyTrait(_)  => {
             /* nothing to do */
         }
         ty::TyStruct(ref adt_def, substs) |
@@ -831,9 +820,9 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         {
             let callee_substs = impl_substs.with_method_from(&rcvr_substs);
             let impl_method = tcx.get_impl_method(impl_did,
-                                                  callee_substs,
+                                                  tcx.mk_substs(callee_substs),
                                                   trait_method.name);
-            Some((impl_method.method.def_id, tcx.mk_substs(impl_method.substs)))
+            Some((impl_method.method.def_id, impl_method.substs))
         }
         // If we have a closure or a function pointer, we will also encounter
         // the concrete closure/function somewhere else (during closure or fn
@@ -991,10 +980,9 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                         // create translation items
                         .filter_map(|impl_method| {
                             if can_have_local_instance(ccx, impl_method.method.def_id) {
-                                let substs = ccx.tcx().mk_substs(impl_method.substs);
                                 Some(create_fn_trans_item(ccx,
                                                           impl_method.method.def_id,
-                                                          substs,
+                                                          impl_method.substs,
                                                           &Substs::trans_empty()))
                             } else {
                                 None
@@ -1173,12 +1161,12 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     // The substitutions we have are on the impl, so we grab
                     // the method type from the impl to substitute into.
                     let mth = tcx.get_impl_method(impl_def_id,
-                                                  callee_substs.clone(),
+                                                  callee_substs,
                                                   default_impl.name);
 
                     assert!(mth.is_provided);
 
-                    let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
+                    let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
                     if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
                         continue;
                     }
@@ -1289,7 +1277,8 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                              &trait_data.bounds.projection_bounds,
                              output);
         },
-        ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
+        ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+        ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
             if unsafety == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
             }
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 3ba27a4b787..34ef4f4acec 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -1228,7 +1228,7 @@ pub enum ExprOrMethodCall {
 pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 node: ExprOrMethodCall,
                                 param_substs: &subst::Substs<'tcx>)
-                                -> subst::Substs<'tcx> {
+                                -> &'tcx subst::Substs<'tcx> {
     let tcx = ccx.tcx();
 
     let substs = match node {
@@ -1245,9 +1245,9 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                               node, substs));
     }
 
-    monomorphize::apply_param_substs(tcx,
-                                     param_substs,
-                                     &substs.erase_regions())
+    ccx.tcx().mk_substs(monomorphize::apply_param_substs(tcx,
+                                                         param_substs,
+                                                         &substs.erase_regions()))
 }
 
 pub fn langcall(bcx: Block,
@@ -1277,7 +1277,7 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty,
            inlined_vid);
     let adt_def = match ctor_ty.sty {
-        ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+        ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
             output: ty::FnConverging(ty), ..
         }), ..}) => ty,
         _ => ctor_ty
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 20da1583496..6c47cab64ef 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -28,6 +28,7 @@ use middle::def::Def;
 use middle::def_id::DefId;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
 use trans::base::{self, push_ctxt};
+use trans::callee::Callee;
 use trans::collector::{self, TransItem};
 use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
 use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
@@ -211,7 +212,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let arg_ids = args.iter().map(|arg| arg.pat.id);
     let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
 
-    let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs));
+    let substs = node_id_substs(ccx, node, param_substs);
     match fn_like.body().expr {
         Some(ref expr) => {
             const_expr(ccx, &expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res)
@@ -355,8 +356,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
     match opt_adj {
         Some(AdjustReifyFnPointer) => {
-            // FIXME(#19925) once fn item types are
-            // zero-sized, we'll need to do something here
+            match ety.sty {
+                ty::TyFnDef(def_id, substs, _) => {
+                    let datum = Callee::def(cx, def_id, substs, ety).reify(cx);
+                    llconst = datum.val;
+                    ety_adjusted = datum.ty;
+                }
+                _ => {
+                    unreachable!("{} cannot be reified to a fn ptr", ety)
+                }
+            }
         }
         Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => {
             // purely a type-level thing
@@ -413,8 +422,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     .expect("consts: unsizing got non-pointer target type").ty;
                 let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
                 let base = ptrcast(base, ptr_ty);
-                let info = base::unsized_info(cx, pointee_ty, unsized_ty,
-                                              old_info, param_substs);
+                let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info);
 
                 if old_info.is_none() {
                     let prev_const = cx.const_unsized().borrow_mut()
@@ -894,9 +902,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                         cx.sess().span_bug(e.span, "const fn argument not found")
                     }
                 }
-                Def::Fn(..) | Def::Method(..) => {
-                    expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
-                }
+                Def::Fn(..) | Def::Method(..) => C_nil(cx),
                 Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                     load_const(cx, try!(get_const_val(cx, def_id, e, param_substs)),
                                ety)
@@ -908,23 +914,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                             let repr = adt::represent_type(cx, ety);
                             adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[])
                         }
-                        ty::VariantKind::Tuple => {
-                            expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
-                        }
+                        ty::VariantKind::Tuple => C_nil(cx),
                         ty::VariantKind::Struct => {
                             cx.sess().span_bug(e.span, "path-expr refers to a dict variant!")
                         }
                     }
                 }
-                Def::Struct(..) => {
-                    if let ty::TyBareFn(..) = ety.sty {
-                        // Tuple struct.
-                        expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
-                    } else {
-                        // Unit struct.
-                        C_null(type_of::type_of(cx, ety))
-                    }
-                }
+                // Unit struct or ctor.
+                Def::Struct(..) => C_null(type_of::type_of(cx, ety)),
                 _ => {
                     cx.sess().span_bug(e.span, "expected a const, fn, struct, \
                                                 or variant def")
diff --git a/src/librustc_trans/trans/debuginfo/create_scope_map.rs b/src/librustc_trans/trans/debuginfo/create_scope_map.rs
index 73fdbd54b29..4ba103c0c0d 100644
--- a/src/librustc_trans/trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/trans/debuginfo/create_scope_map.rs
@@ -346,11 +346,6 @@ fn walk_expr(cx: &CrateContext,
             walk_expr(cx, &rhs, scope_stack, scope_map);
         }
 
-        hir::ExprRange(ref start, ref end) => {
-            start.as_ref().map(|e| walk_expr(cx, &e, scope_stack, scope_map));
-            end.as_ref().map(|e| walk_expr(cx, &e, scope_stack, scope_map));
-        }
-
         hir::ExprVec(ref init_expressions) |
         hir::ExprTup(ref init_expressions) => {
             for ie in init_expressions {
diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs
index 330d4077c41..0cd1f4e7fbf 100644
--- a/src/librustc_trans/trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/trans/debuginfo/metadata.rs
@@ -253,7 +253,8 @@ impl<'tcx> TypeMap<'tcx> {
                                        principal.substs,
                                        &mut unique_type_id);
             },
-            ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
+            ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+            ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
                 if unsafety == hir::Unsafety::Unsafe {
                     unique_type_id.push_str("unsafe ");
                 }
@@ -765,7 +766,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
-        ty::TyBareFn(_, ref barefnty) => {
+        ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => {
             let fn_metadata = subroutine_type_metadata(cx,
                                                        unique_type_id,
                                                        &barefnty.sig,
diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs
index 11dd631bee1..15275a46e9b 100644
--- a/src/librustc_trans/trans/debuginfo/mod.rs
+++ b/src/librustc_trans/trans/debuginfo/mod.rs
@@ -430,7 +430,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         let fn_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &fn_type);
 
         let (sig, abi) = match fn_type.sty {
-            ty::TyBareFn(_, ref barefnty) => {
+            ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => {
                 let sig = cx.tcx().erase_late_bound_regions(&barefnty.sig);
                 let sig = infer::normalize_associated_type(cx.tcx(), &sig);
                 (sig, barefnty.abi)
diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs
index f243b1e3bfa..cc9067677b2 100644
--- a/src/librustc_trans/trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/trans/debuginfo/type_names.rs
@@ -101,7 +101,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             push_item_name(cx, principal.def_id, false, output);
             push_type_params(cx, principal.substs, output);
         },
-        ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
+        ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+        ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
             if unsafety == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
             }
diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs
index 75b60be02f7..38e456c0688 100644
--- a/src/librustc_trans/trans/declare.rs
+++ b/src/librustc_trans/trans/declare.rs
@@ -106,7 +106,8 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
 
     let function_type; // placeholder so that the memory ownership works out ok
     let (sig, abi, env) = match fn_type.sty {
-        ty::TyBareFn(_, ref f) => {
+        ty::TyFnDef(_, _, f) |
+        ty::TyFnPtr(f) => {
             (&f.sig, f.abi, None)
         }
         ty::TyClosure(closure_did, ref substs) => {
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 591d8a9f76c..ae03f58bce0 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -56,9 +56,10 @@ use llvm::{self, ValueRef, TypeKind};
 use middle::const_qualif::ConstQualif;
 use middle::def::Def;
 use middle::subst::Substs;
-use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
+use trans::{_match, adt, asm, base, closure, consts, controlflow};
 use trans::base::*;
 use trans::build::*;
+use trans::callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp};
 use trans::cleanup::{self, CleanupMethods, DropHintMethods};
 use trans::common::*;
 use trans::datum::*;
@@ -66,7 +67,6 @@ use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
 use trans::declare;
 use trans::glue;
 use trans::machine;
-use trans::meth;
 use trans::tvec;
 use trans::type_of;
 use trans::Disr;
@@ -85,8 +85,6 @@ use rustc_front::hir;
 
 use syntax::{ast, codemap};
 use syntax::parse::token::InternedString;
-use syntax::ptr::P;
-use syntax::parse::token;
 use std::mem;
 
 // Destinations
@@ -350,11 +348,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 
     match adjustment {
-        AdjustReifyFnPointer => {
-            // FIXME(#19925) once fn item types are
-            // zero-sized, we'll need to return true here
-            false
-        }
+        AdjustReifyFnPointer => true,
         AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
             // purely a type-level thing
             false
@@ -389,8 +383,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
            adjustment);
     match adjustment {
         AdjustReifyFnPointer => {
-            // FIXME(#19925) once fn item types are
-            // zero-sized, we'll need to do something here
+            match datum.ty.sty {
+                ty::TyFnDef(def_id, substs, _) => {
+                    datum = Callee::def(bcx.ccx(), def_id, substs, datum.ty)
+                        .reify(bcx.ccx()).to_expr_datum();
+                }
+                _ => {
+                    unreachable!("{} cannot be reified to a fn ptr", datum.ty)
+                }
+            }
         }
         AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
             // purely a type-level thing
@@ -493,8 +494,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 (val, None)
             };
 
-            let info = unsized_info(bcx.ccx(), inner_source, inner_target,
-                                    old_info, bcx.fcx.param_substs);
+            let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info);
 
             // Compute the base pointer. This doesn't change the pointer value,
             // but merely its type.
@@ -786,15 +786,10 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let index_expr_debug_loc = index_expr.debug_loc();
 
     // Check for overloaded index.
-    let method_ty = ccx.tcx()
-                       .tables
-                       .borrow()
-                       .method_map
-                       .get(&method_call)
-                       .map(|method| method.ty);
-    let elt_datum = match method_ty {
-        Some(method_ty) => {
-            let method_ty = monomorphize_type(bcx, method_ty);
+    let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
+    let elt_datum = match method {
+        Some(method) => {
+            let method_ty = monomorphize_type(bcx, method.ty);
 
             let base_datum = unpack_datum!(bcx, trans(bcx, base));
 
@@ -812,19 +807,16 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 Some(elt_tm) => elt_tm.ty,
             };
 
-            // Overloaded. Evaluate `trans_overloaded_op`, which will
-            // invoke the user's index() method, which basically yields
-            // a `&T` pointer.  We can then proceed down the normal
-            // path (below) to dereference that `&T`.
+            // Overloaded. Invoke the index() method, which basically
+            // yields a `&T` pointer.  We can then proceed down the
+            // normal path (below) to dereference that `&T`.
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt");
-            unpack_result!(bcx,
-                           trans_overloaded_op(bcx,
-                                               index_expr,
-                                               method_call,
-                                               base_datum,
-                                               Some((ix_datum, idx.id)),
-                                               Some(SaveIn(scratch.val)),
-                                               false));
+
+            bcx = Callee::method(bcx, method)
+                .call(bcx, index_expr_debug_loc,
+                      ArgOverloadedOp(base_datum, Some(ix_datum)),
+                      Some(SaveIn(scratch.val))).bcx;
+
             let datum = scratch.to_expr_datum();
             let lval = Lvalue::new("expr::trans_index overload");
             if type_is_sized(bcx.tcx(), elt_ty) {
@@ -900,24 +892,18 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let _icx = push_ctxt("trans_def_lvalue");
     match def {
-        Def::Fn(..) | Def::Method(..) |
-        Def::Struct(..) | Def::Variant(..) => {
-            let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
-                                                bcx.fcx.param_substs);
-            DatumBlock::new(bcx, datum.to_expr_datum())
-        }
         Def::Static(did, _) => {
             let const_ty = expr_ty(bcx, ref_expr);
             let val = get_static_val(bcx.ccx(), did, const_ty);
             let lval = Lvalue::new("expr::trans_def");
             DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
         }
-        Def::Const(_) | Def::AssociatedConst(_) => {
-            bcx.sess().span_bug(ref_expr.span,
-                "constant expression should not reach expr::trans_def")
+        Def::Local(..) | Def::Upvar(..) => {
+            DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
         }
         _ => {
-            DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
+            bcx.sess().span_bug(ref_expr.span,
+                &format!("{:?} should not reach expr::trans_def", def))
         }
     }
 }
@@ -1025,17 +1011,18 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             }
         }
         hir::ExprAssignOp(op, ref dst, ref src) => {
-            let has_method_map = bcx.tcx()
-                                    .tables
-                                    .borrow()
-                                    .method_map
-                                    .contains_key(&MethodCall::expr(expr.id));
+            let method = bcx.tcx().tables
+                                  .borrow()
+                                  .method_map
+                                  .get(&MethodCall::expr(expr.id)).cloned();
 
-            if has_method_map {
+            if let Some(method) = method {
                 let dst = unpack_datum!(bcx, trans(bcx, &dst));
                 let src_datum = unpack_datum!(bcx, trans(bcx, &src));
-                trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
-                                    Some((src_datum, src.id)), None, false).bcx
+
+                Callee::method(bcx, method)
+                    .call(bcx, expr.debug_loc(),
+                          ArgOverloadedOp(dst, Some(src_datum)), None).bcx
             } else {
                 trans_assign_op(bcx, expr, op, &dst, &src)
             }
@@ -1059,10 +1046,12 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                            -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
     let mut bcx = bcx;
-    let tcx = bcx.tcx();
 
     debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
 
+    // Entry into the method table if this is an overloaded call/op.
+    let method_call = MethodCall::expr(expr.id);
+
     match expr.node {
         hir::ExprType(ref e, _) => {
             trans_into(bcx, &e, dest)
@@ -1088,59 +1077,6 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                          node_id_type(bcx, expr.id),
                          dest)
         }
-        hir::ExprRange(ref start, ref end) => {
-            // FIXME it is just not right that we are synthesising ast nodes in
-            // trans. Shudder.
-            fn make_field(field_name: &str, expr: P<hir::Expr>) -> hir::Field {
-                hir::Field {
-                    name: codemap::dummy_spanned(token::intern(field_name)),
-                    expr: expr,
-                    span: codemap::DUMMY_SP,
-                }
-            }
-
-            // A range just desugars into a struct.
-            // Note that the type of the start and end may not be the same, but
-            // they should only differ in their lifetime, which should not matter
-            // in trans.
-            let (did, fields, ty_params) = match (start, end) {
-                (&Some(ref start), &Some(ref end)) => {
-                    // Desugar to Range
-                    let fields = vec![make_field("start", start.clone()),
-                                      make_field("end", end.clone())];
-                    (tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)])
-                }
-                (&Some(ref start), &None) => {
-                    // Desugar to RangeFrom
-                    let fields = vec![make_field("start", start.clone())];
-                    (tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)])
-                }
-                (&None, &Some(ref end)) => {
-                    // Desugar to RangeTo
-                    let fields = vec![make_field("end", end.clone())];
-                    (tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)])
-                }
-                _ => {
-                    // Desugar to RangeFull
-                    (tcx.lang_items.range_full_struct(), vec![], vec![])
-                }
-            };
-
-            if let Some(did) = did {
-                let substs = Substs::new_type(ty_params, vec![]);
-                trans_struct(bcx,
-                             &fields,
-                             None,
-                             expr.span,
-                             expr.id,
-                             tcx.mk_struct(tcx.lookup_adt_def(did),
-                                           tcx.mk_substs(substs)),
-                             dest)
-            } else {
-                tcx.sess.span_bug(expr.span,
-                                  "No lang item for ranges (how did we get this far?)")
-            }
-        }
         hir::ExprTup(ref args) => {
             let numbered_fields: Vec<(usize, &hir::Expr)> =
                 args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
@@ -1199,47 +1135,54 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                         &expr.attrs).unwrap_or(bcx)
         }
         hir::ExprCall(ref f, ref args) => {
-            if bcx.tcx().is_method_call(expr.id) {
-                trans_overloaded_call(bcx,
-                                      expr,
-                                      &f,
-                                      &args[..],
-                                      Some(dest))
+            let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned();
+            let (callee, args) = if let Some(method) = method {
+                let mut all_args = vec![&**f];
+                all_args.extend(args.iter().map(|e| &**e));
+
+                (Callee::method(bcx, method), ArgOverloadedCall(all_args))
             } else {
-                callee::trans_call(bcx,
-                                   expr,
-                                   &f,
-                                   callee::ArgExprs(&args[..]),
-                                   dest)
-            }
+                let f = unpack_datum!(bcx, trans(bcx, f));
+                (match f.ty.sty {
+                    ty::TyFnDef(def_id, substs, _) => {
+                        Callee::def(bcx.ccx(), def_id, substs, f.ty)
+                    }
+                    ty::TyFnPtr(_) => {
+                        let f = unpack_datum!(bcx,
+                            f.to_rvalue_datum(bcx, "callee"));
+                        Callee::ptr(f)
+                    }
+                    _ => {
+                        bcx.tcx().sess.span_bug(expr.span,
+                            &format!("type of callee is not a fn: {}", f.ty));
+                    }
+                }, ArgExprs(&args))
+            };
+            callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx
         }
         hir::ExprMethodCall(_, _, ref args) => {
-            callee::trans_method_call(bcx,
-                                      expr,
-                                      &args[0],
-                                      callee::ArgExprs(&args[..]),
-                                      dest)
+            Callee::method_call(bcx, method_call)
+                .call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx
         }
-        hir::ExprBinary(op, ref lhs, ref rhs) => {
+        hir::ExprBinary(op, ref lhs, ref rhs_expr) => {
             // if not overloaded, would be RvalueDatumExpr
             let lhs = unpack_datum!(bcx, trans(bcx, &lhs));
-            let rhs_datum = unpack_datum!(bcx, trans(bcx, &rhs));
-            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
-                                Some((rhs_datum, rhs.id)), Some(dest),
-                                !rustc_front::util::is_by_value_binop(op.node)).bcx
+            let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr));
+            if !rustc_front::util::is_by_value_binop(op.node) {
+                rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr));
+            }
+
+            Callee::method_call(bcx, method_call)
+                .call(bcx, expr.debug_loc(),
+                      ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx
         }
-        hir::ExprUnary(op, ref subexpr) => {
+        hir::ExprUnary(_, ref subexpr) => {
             // if not overloaded, would be RvalueDatumExpr
             let arg = unpack_datum!(bcx, trans(bcx, &subexpr));
-            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
-                                arg, None, Some(dest), !rustc_front::util::is_by_value_unop(op)).bcx
-        }
-        hir::ExprIndex(ref base, ref idx) => {
-            // if not overloaded, would be RvalueDatumExpr
-            let base = unpack_datum!(bcx, trans(bcx, &base));
-            let idx_datum = unpack_datum!(bcx, trans(bcx, &idx));
-            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
-                                Some((idx_datum, idx.id)), Some(dest), true).bcx
+
+            Callee::method_call(bcx, method_call)
+                .call(bcx, expr.debug_loc(),
+                      ArgOverloadedOp(arg, None), Some(dest)).bcx
         }
         hir::ExprCast(..) => {
             // Trait casts used to come this way, now they should be coercions.
@@ -1273,26 +1216,22 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         Ignore => { return bcx; }
     };
 
+    let ty = expr_ty(bcx, ref_expr);
+    if let ty::TyFnDef(..) = ty.sty {
+        // Zero-sized function or ctor.
+        return bcx;
+    }
+
     match def {
         Def::Variant(tid, vid) => {
             let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
-            if let ty::VariantKind::Tuple = variant.kind() {
-                // N-ary variant.
-                let llfn = callee::trans_fn_ref(bcx.ccx(), vid,
-                                                ExprId(ref_expr.id),
-                                                bcx.fcx.param_substs).val;
-                Store(bcx, llfn, lldest);
-                return bcx;
-            } else {
-                // Nullary variant.
-                let ty = expr_ty(bcx, ref_expr);
-                let repr = adt::represent_type(bcx.ccx(), ty);
-                adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
-                return bcx;
-            }
+            // Nullary variant.
+            let ty = expr_ty(bcx, ref_expr);
+            let repr = adt::represent_type(bcx.ccx(), ty);
+            adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
+            bcx
         }
         Def::Struct(..) => {
-            let ty = expr_ty(bcx, ref_expr);
             match ty.sty {
                 ty::TyStruct(def, _) if def.has_dtor() => {
                     let repr = adt::represent_type(bcx.ccx(), ty);
@@ -1310,41 +1249,6 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
-pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                         ref_expr: &hir::Expr,
-                                         def: Def,
-                                         param_substs: &'tcx Substs<'tcx>)
-                                         -> Datum<'tcx, Rvalue> {
-    let _icx = push_ctxt("trans_def_datum_unadjusted");
-
-    match def {
-        Def::Fn(did) |
-        Def::Struct(did) | Def::Variant(_, did) => {
-            callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
-        }
-        Def::Method(method_did) => {
-            match ccx.tcx().impl_or_trait_item(method_did).container() {
-                ty::ImplContainer(_) => {
-                    callee::trans_fn_ref(ccx, method_did,
-                                         ExprId(ref_expr.id),
-                                         param_substs)
-                }
-                ty::TraitContainer(trait_did) => {
-                    meth::trans_static_method_callee(ccx, method_did,
-                                                     trait_did, ref_expr.id,
-                                                     param_substs)
-                }
-            }
-        }
-        _ => {
-            ccx.tcx().sess.span_bug(ref_expr.span, &format!(
-                    "trans_def_fn_unadjusted invoked on: {:?} for {:?}",
-                    def,
-                    ref_expr));
-        }
-    }
-}
-
 /// Translates a reference to a local variable or argument. This always results in an lvalue datum.
 pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    def: Def)
@@ -1953,51 +1857,6 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
-fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   expr: &hir::Expr,
-                                   method_call: MethodCall,
-                                   lhs: Datum<'tcx, Expr>,
-                                   rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>,
-                                   dest: Option<Dest>,
-                                   autoref: bool)
-                                   -> Result<'blk, 'tcx> {
-    callee::trans_call_inner(bcx,
-                             expr.debug_loc(),
-                             |bcx, arg_cleanup_scope| {
-                                meth::trans_method_callee(bcx,
-                                                          method_call,
-                                                          None,
-                                                          arg_cleanup_scope)
-                             },
-                             callee::ArgOverloadedOp(lhs, rhs, autoref),
-                             dest)
-}
-
-fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                         expr: &hir::Expr,
-                                         callee: &'a hir::Expr,
-                                         args: &'a [P<hir::Expr>],
-                                         dest: Option<Dest>)
-                                         -> Block<'blk, 'tcx> {
-    debug!("trans_overloaded_call {}", expr.id);
-    let method_call = MethodCall::expr(expr.id);
-    let mut all_args = vec!(callee);
-    all_args.extend(args.iter().map(|e| &**e));
-    unpack_result!(bcx,
-                   callee::trans_call_inner(bcx,
-                                            expr.debug_loc(),
-                                            |bcx, arg_cleanup_scope| {
-                                                meth::trans_method_callee(
-                                                    bcx,
-                                                    method_call,
-                                                    None,
-                                                    arg_cleanup_scope)
-                                            },
-                                            callee::ArgOverloadedCall(all_args),
-                                            dest));
-    bcx
-}
-
 pub fn cast_is_noop<'tcx>(tcx: &TyCtxt<'tcx>,
                           expr: &hir::Expr,
                           t_in: Ty<'tcx>,
@@ -2234,18 +2093,12 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let mut bcx = bcx;
 
     // Check for overloaded deref.
-    let method_ty = ccx.tcx()
-                       .tables
-                       .borrow()
-                       .method_map
-                       .get(&method_call).map(|method| method.ty);
-
-    let datum = match method_ty {
-        Some(method_ty) => {
-            let method_ty = monomorphize_type(bcx, method_ty);
-
-            // Overloaded. Evaluate `trans_overloaded_op`, which will
-            // invoke the user's deref() method, which basically
+    let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
+    let datum = match method {
+        Some(method) => {
+            let method_ty = monomorphize_type(bcx, method.ty);
+
+            // Overloaded. Invoke the deref() method, which basically
             // converts from the `Smaht<T>` pointer that we have into
             // a `&T` pointer.  We can then proceed down the normal
             // path (below) to dereference that `&T`.
@@ -2260,9 +2113,10 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
 
-            unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
-                                                    datum, None, Some(SaveIn(scratch.val)),
-                                                    false));
+            bcx = Callee::method(bcx, method)
+                .call(bcx, expr.debug_loc(),
+                      ArgOverloadedOp(datum, None),
+                      Some(SaveIn(scratch.val))).bcx;
             scratch.to_expr_datum()
         }
         None => {
@@ -2579,18 +2433,13 @@ fn expr_kind(tcx: &TyCtxt, expr: &hir::Expr) -> ExprKind {
     match expr.node {
         hir::ExprPath(..) => {
             match tcx.resolve_expr(expr) {
-                Def::Struct(..) | Def::Variant(..) => {
-                    if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty {
-                        // ctor function
-                        ExprKind::RvalueDatum
-                    } else {
-                        ExprKind::RvalueDps
-                    }
+                // Put functions and ctors with the ADTs, as they
+                // are zero-sized, so DPS is the cheapest option.
+                Def::Struct(..) | Def::Variant(..) |
+                Def::Fn(..) | Def::Method(..) => {
+                    ExprKind::RvalueDps
                 }
 
-                // Fn pointers are just scalar values.
-                Def::Fn(..) | Def::Method(..) => ExprKind::RvalueDatum,
-
                 // Note: there is actually a good case to be made that
                 // DefArg's, particularly those of immediate type, ought to
                 // considered rvalues.
@@ -2625,7 +2474,6 @@ fn expr_kind(tcx: &TyCtxt, expr: &hir::Expr) -> ExprKind {
         hir::ExprCall(..) |
         hir::ExprMethodCall(..) |
         hir::ExprStruct(..) |
-        hir::ExprRange(..) |
         hir::ExprTup(..) |
         hir::ExprIf(..) |
         hir::ExprMatch(..) |
diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs
index 2a2178dd63b..cace98a230f 100644
--- a/src/librustc_trans/trans/foreign.rs
+++ b/src/librustc_trans/trans/foreign.rs
@@ -262,7 +262,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
            ccx.tn().val_to_string(llretptr));
 
     let (fn_abi, fn_sig) = match callee_ty.sty {
-        ty::TyBareFn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
+        ty::TyFnDef(_, _, ref fn_ty) |
+        ty::TyFnPtr(ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
         _ => ccx.sess().bug("trans_native_call called on non-function type")
     };
     let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
@@ -501,7 +502,8 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &hir::ForeignMod) {
                 abi => {
                     let ty = ccx.tcx().node_id_to_type(foreign_item.id);
                     match ty.sty {
-                        ty::TyBareFn(_, bft) => gate_simd_ffi(ccx.tcx(), &decl, bft),
+                        ty::TyFnDef(_, _, bft) |
+                        ty::TyFnPtr(bft) => gate_simd_ffi(ccx.tcx(), &decl, bft),
                         _ => ccx.tcx().sess.span_bug(foreign_item.span,
                                                      "foreign fn's sty isn't a bare_fn_ty?")
                     }
@@ -552,7 +554,7 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let tys = foreign_types_for_fn_ty(ccx, t);
     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
     let cconv = match t.sty {
-        ty::TyBareFn(_, ref fn_ty) => {
+        ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => {
             llvm_calling_convention(ccx, fn_ty.abi)
         }
         _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
@@ -574,7 +576,7 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
 
     let t = ccx.tcx().node_id_to_type(node_id);
     let cconv = match t.sty {
-        ty::TyBareFn(_, ref fn_ty) => {
+        ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => {
             llvm_calling_convention(ccx, fn_ty.abi)
         }
         _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
@@ -634,7 +636,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // Compute the type that the function would have if it were just a
         // normal Rust function. This will be the type of the wrappee fn.
         match t.sty {
-            ty::TyBareFn(_, ref f) => {
+            ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f)=> {
                 assert!(f.abi != Abi::Rust);
                 assert!(f.abi != Abi::RustIntrinsic);
                 assert!(f.abi != Abi::PlatformIntrinsic);
@@ -957,7 +959,7 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                      ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
     let fn_sig = match ty.sty {
-        ty::TyBareFn(_, ref fn_ty) => &fn_ty.sig,
+        ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => &fn_ty.sig,
         _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
     };
     let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs
index 0b2ab58a835..d5f8cff4956 100644
--- a/src/librustc_trans/trans/glue.rs
+++ b/src/librustc_trans/trans/glue.rs
@@ -356,27 +356,18 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         &unsized_args
     };
 
-    bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
-        let trait_ref = ty::Binder(ty::TraitRef {
-            def_id: tcx.lang_items.drop_trait().unwrap(),
-            substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
-        });
-        let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
-            traits::VtableImpl(data) => data,
-            _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t))
-        };
-        let dtor_did = def.destructor().unwrap();
-        let datum = callee::trans_fn_ref_with_substs(bcx.ccx(),
-                                                     dtor_did,
-                                                     ExprId(0),
-                                                     bcx.fcx.param_substs,
-                                                     vtbl.substs);
-        callee::Callee {
-            bcx: bcx,
-            data: callee::Fn(datum.val),
-            ty: datum.ty
-        }
-    }, callee::ArgVals(args), Some(expr::Ignore)).bcx;
+    let trait_ref = ty::Binder(ty::TraitRef {
+        def_id: tcx.lang_items.drop_trait().unwrap(),
+        substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
+    });
+    let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
+        traits::VtableImpl(data) => data,
+        _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t))
+    };
+    let dtor_did = def.destructor().unwrap();
+    bcx = callee::Callee::ptr(callee::trans_fn_ref_with_substs(
+            bcx.ccx(), dtor_did, None, vtbl.substs))
+        .call(bcx, DebugLoc::None, callee::ArgVals(args), Some(expr::Ignore)).bcx;
 
     bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
 }
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index b7b520f6c82..96c1d6a4d69 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -22,7 +22,7 @@ use trans::adt;
 use trans::attributes;
 use trans::base::*;
 use trans::build::*;
-use trans::callee;
+use trans::callee::{self, Callee};
 use trans::cleanup;
 use trans::cleanup::CleanupMethods;
 use trans::common::*;
@@ -45,6 +45,7 @@ use syntax::ast;
 use syntax::ptr::P;
 use syntax::parse::token;
 
+use rustc::lint;
 use rustc::session::Session;
 use syntax::codemap::Span;
 
@@ -125,29 +126,41 @@ pub fn check_intrinsics(ccx: &CrateContext) {
                                                transmute_restriction.substituted_to);
         let from_type_size = machine::llbitsize_of_real(ccx, llfromtype);
         let to_type_size = machine::llbitsize_of_real(ccx, lltotype);
+
+        if let ty::TyFnDef(..) = transmute_restriction.substituted_from.sty {
+            if to_type_size == machine::llbitsize_of_real(ccx, ccx.int_type()) {
+                // FIXME #19925 Remove this warning after a release cycle.
+                lint::raw_emit_lint(&ccx.tcx().sess,
+                                    &ccx.tcx().sess.lint_store.borrow(),
+                                    lint::builtin::TRANSMUTE_FROM_FN_ITEM_TYPES,
+                                    (lint::Warn, lint::LintSource::Default),
+                                    Some(transmute_restriction.span),
+                                    &format!("`{}` is now zero-sized and has to be cast \
+                                              to a pointer before transmuting to `{}`",
+                                             transmute_restriction.substituted_from,
+                                             transmute_restriction.substituted_to));
+                continue;
+            }
+        }
         if from_type_size != to_type_size {
             last_failing_id = Some(transmute_restriction.id);
 
             if transmute_restriction.original_from != transmute_restriction.substituted_from {
                 span_transmute_size_error(ccx.sess(), transmute_restriction.span,
                     &format!("transmute called with differently sized types: \
-                              {} (could be {} bit{}) to {} (could be {} bit{})",
+                              {} (could be {} bits) to {} (could be {} bits)",
                              transmute_restriction.original_from,
-                             from_type_size as usize,
-                             if from_type_size == 1 {""} else {"s"},
+                             from_type_size,
                              transmute_restriction.original_to,
-                             to_type_size as usize,
-                             if to_type_size == 1 {""} else {"s"}));
+                             to_type_size));
             } else {
                 span_transmute_size_error(ccx.sess(), transmute_restriction.span,
                     &format!("transmute called with differently sized types: \
-                              {} ({} bit{}) to {} ({} bit{})",
+                              {} ({} bits) to {} ({} bits)",
                              transmute_restriction.original_from,
-                             from_type_size as usize,
-                             if from_type_size == 1 {""} else {"s"},
+                             from_type_size,
                              transmute_restriction.original_to,
-                             to_type_size as usize,
-                             if to_type_size == 1 {""} else {"s"}));
+                             to_type_size));
             }
         }
     }
@@ -163,7 +176,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                             cleanup_scope: cleanup::CustomScopeIndex,
                                             args: callee::CallArgs<'a, 'tcx>,
                                             dest: expr::Dest,
-                                            substs: subst::Substs<'tcx>,
+                                            substs: &'tcx subst::Substs<'tcx>,
                                             call_info: NodeIdAndSpan)
                                             -> Result<'blk, 'tcx> {
     let fcx = bcx.fcx;
@@ -179,6 +192,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let foreign_item = tcx.map.expect_foreign_item(node);
     let name = foreign_item.name.as_str();
 
+    let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
+
     // For `transmute` we can just trans the input expr directly into dest
     if name == "transmute" {
         let llret_ty = type_of::type_of(ccx, ret_ty.unwrap());
@@ -194,6 +209,27 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 let in_type_size = machine::llbitsize_of_real(ccx, llintype);
                 let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
 
+                if let ty::TyFnDef(def_id, substs, _) = in_type.sty {
+                    if out_type_size != 0 {
+                        // FIXME #19925 Remove this hack after a release cycle.
+                        let _ = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
+                        let llfn = Callee::def(ccx, def_id, substs, in_type).reify(ccx).val;
+                        let llfnty = val_ty(llfn);
+                        let llresult = match dest {
+                            expr::SaveIn(d) => d,
+                            expr::Ignore => alloc_ty(bcx, out_type, "ret")
+                        };
+                        Store(bcx, llfn, PointerCast(bcx, llresult, llfnty.ptr_to()));
+                        if dest == expr::Ignore {
+                            bcx = glue::drop_ty(bcx, llresult, out_type,
+                                                call_debug_location);
+                        }
+                        fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
+                        fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
+                        return Result::new(bcx, llresult);
+                    }
+                }
+
                 // This should be caught by the intrinsicck pass
                 assert_eq!(in_type_size, out_type_size);
 
@@ -311,8 +347,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
     }
 
-    let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
-
     // For `try` we need some custom control flow
     if &name[..] == "try" {
         if let callee::ArgExprs(ref exprs) = args {
@@ -364,7 +398,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                              callee_ty,
                              &mut llargs,
                              cleanup::CustomScope(cleanup_scope),
-                             false,
                              Abi::RustIntrinsic);
 
     fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
@@ -1264,7 +1297,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
     // Define the type up front for the signature of the rust_try function.
     let tcx = ccx.tcx();
     let i8p = tcx.mk_mut_ptr(tcx.types.i8);
-    let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
+    let fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: Abi::Rust,
         sig: ty::Binder(ty::FnSig {
@@ -1273,9 +1306,8 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
             variadic: false,
         }),
     });
-    let fn_ty = tcx.mk_fn(None, fn_ty);
     let output = ty::FnOutput::FnConverging(tcx.types.i32);
-    let try_fn_ty  = tcx.mk_bare_fn(ty::BareFnTy {
+    let try_fn_ty  = ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: Abi::Rust,
         sig: ty::Binder(ty::FnSig {
@@ -1283,8 +1315,8 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
             output: output,
             variadic: false,
         }),
-    });
-    let rust_try = gen_fn(fcx, "__rust_try", tcx.mk_fn(None, try_fn_ty), output,
+    };
+    let rust_try = gen_fn(fcx, "__rust_try", tcx.mk_fn_ptr(try_fn_ty), output,
                           trans);
     *ccx.rust_try_fn().borrow_mut() = Some(rust_try);
     return rust_try
@@ -1353,7 +1385,7 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
         // going on here, all I can say is that there's a few tests cases in
         // LLVM's test suite which follow this pattern of instructions, so we
         // just do the same.
-        let filter_fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
+        let filter_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
             unsafety: hir::Unsafety::Unsafe,
             abi: Abi::Rust,
             sig: ty::Binder(ty::FnSig {
@@ -1362,7 +1394,6 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
                 variadic: false,
             }),
         });
-        let filter_fn_ty = tcx.mk_fn(None, filter_fn_ty);
         gen_fn(fcx, "__rustc_try_filter", filter_fn_ty, output, &mut |bcx| {
             let ebp = Call(bcx, frameaddress, &[C_i32(ccx, 1)], None, dloc);
             let exn = InBoundsGEP(bcx, ebp, &[C_i32(ccx, -20)]);
@@ -1373,7 +1404,7 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
         // Conveniently on x86_64 the EXCEPTION_POINTERS handle and base pointer
         // are passed in as arguments to the filter function, so we just pass
         // those along.
-        let filter_fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
+        let filter_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
             unsafety: hir::Unsafety::Unsafe,
             abi: Abi::Rust,
             sig: ty::Binder(ty::FnSig {
@@ -1382,7 +1413,6 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
                 variadic: false,
             }),
         });
-        let filter_fn_ty = tcx.mk_fn(None, filter_fn_ty);
         gen_fn(fcx, "__rustc_try_filter", filter_fn_ty, output, &mut |bcx| {
             let exn = llvm::get_param(bcx.fcx.llfn, 0);
             let rbp = llvm::get_param(bcx.fcx.llfn, 1);
@@ -1400,7 +1430,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
 fn generic_simd_intrinsic<'blk, 'tcx, 'a>
     (bcx: Block<'blk, 'tcx>,
      name: &str,
-     substs: subst::Substs<'tcx>,
+     substs: &'tcx subst::Substs<'tcx>,
      callee_ty: Ty<'tcx>,
      args: Option<&[P<hir::Expr>]>,
      llargs: &[ValueRef],
@@ -1508,11 +1538,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
             None => bcx.sess().span_bug(call_info.span,
                                         "intrinsic call with unexpected argument shape"),
         };
-        let vector = match consts::const_expr(
-            bcx.ccx(),
-            vector,
-            tcx.mk_substs(substs),
-            None,
+        let vector = match consts::const_expr(bcx.ccx(), vector, substs, None,
             consts::TrueConst::Yes, // this should probably help simd error reporting
         ) {
             Ok((vector, _)) => vector,
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 221d17e6641..78b86dafa18 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -18,9 +18,8 @@ use middle::subst;
 use middle::traits;
 use trans::base::*;
 use trans::build::*;
-use trans::callee::*;
-use trans::callee;
-use trans::cleanup;
+use trans::callee::{Callee, Virtual, ArgVals,
+                    trans_fn_pointer_shim, trans_fn_ref_with_substs};
 use trans::closure;
 use trans::common::*;
 use trans::consts;
@@ -30,11 +29,9 @@ use trans::declare;
 use trans::expr;
 use trans::glue;
 use trans::machine;
-use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of::*;
 use middle::ty::{self, Ty, TyCtxt};
-use middle::ty::MethodCall;
 
 use syntax::ast;
 use syntax::attr;
@@ -92,264 +89,99 @@ pub fn trans_impl(ccx: &CrateContext,
     }
 }
 
-pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                       method_call: MethodCall,
-                                       self_expr: Option<&hir::Expr>,
-                                       arg_cleanup_scope: cleanup::ScopeId)
-                                       -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_method_callee");
-
-    let method = bcx.tcx().tables.borrow().method_map[&method_call];
-
-    match bcx.tcx().impl_or_trait_item(method.def_id).container() {
-        ty::ImplContainer(_) => {
-            debug!("trans_method_callee: static, {:?}", method.def_id);
-            let datum = callee::trans_fn_ref(bcx.ccx(),
-                                             method.def_id,
-                                             MethodCallKey(method_call),
-                                             bcx.fcx.param_substs);
-            Callee {
-                bcx: bcx,
-                data: Fn(datum.val),
-                ty: datum.ty
-            }
-        }
-
-        ty::TraitContainer(trait_def_id) => {
-            let trait_ref = method.substs.to_trait_ref(bcx.tcx(), trait_def_id);
-            let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref));
-            let span = bcx.tcx().map.span(method_call.expr_id);
-            debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
-                   method_call,
-                   trait_ref,
-                   trait_ref.0.def_id,
-                   trait_ref.0.substs);
-            let origin = fulfill_obligation(bcx.ccx(), span, trait_ref);
-            debug!("origin = {:?}", origin);
-            trans_monomorphized_callee(bcx,
-                                       method_call,
-                                       self_expr,
-                                       trait_def_id,
-                                       method.def_id,
-                                       method.ty,
-                                       origin,
-                                       arg_cleanup_scope)
-        }
-    }
-}
-
-pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                            method_id: DefId,
-                                            trait_id: DefId,
-                                            expr_id: ast::NodeId,
-                                            param_substs: &'tcx subst::Substs<'tcx>)
-                                            -> Datum<'tcx, Rvalue>
-{
-    let _icx = push_ctxt("meth::trans_static_method_callee");
-    let tcx = ccx.tcx();
-
-    debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \
-            expr_id={})",
-           method_id,
-           tcx.item_path_str(trait_id),
-           expr_id);
-
-    let mname = tcx.item_name(method_id);
-
-    debug!("trans_static_method_callee: method_id={:?}, expr_id={}, \
-            name={}", method_id, expr_id, mname);
-
-    // Find the substitutions for the fn itself. This includes
-    // type parameters that belong to the trait but also some that
-    // belong to the method:
-    let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
-    debug!("rcvr_substs={:?}", rcvr_substs);
-    let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
-    let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
-
-    // Now that we know which impl is being used, we can dispatch to
-    // the actual function:
-    match vtbl {
-        traits::VtableImpl(traits::VtableImplData {
-            impl_def_id: impl_did,
-            substs: impl_substs,
-            nested: _ }) =>
-        {
-            let callee_substs = impl_substs.with_method_from(&rcvr_substs);
-            let mth = tcx.get_impl_method(impl_did, callee_substs, mname);
-            trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id),
-                                     param_substs,
-                                     mth.substs)
-        }
-        traits::VtableObject(ref data) => {
-            let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
-            trans_object_shim(ccx,
-                              data.upcast_trait_ref.clone(),
-                              method_id,
-                              idx)
-        }
-        _ => {
-            // FIXME(#20847): handle at least VtableFnPointer
-            tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
-                                 vtbl));
-        }
-    }
-}
-
-fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                          method_call: MethodCall,
-                                          self_expr: Option<&hir::Expr>,
-                                          trait_id: DefId,
-                                          method_id: DefId,
-                                          method_ty: Ty<'tcx>,
-                                          vtable: traits::Vtable<'tcx, ()>,
-                                          arg_cleanup_scope: cleanup::ScopeId)
-                                          -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_monomorphized_callee");
+/// Compute the appropriate callee, give na method's ID, trait ID,
+/// substitutions and a Vtable for that trait.
+pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                       method_id: DefId,
+                                       substs: &'tcx subst::Substs<'tcx>,
+                                       trait_id: DefId,
+                                       method_ty: Ty<'tcx>,
+                                       vtable: traits::Vtable<'tcx, ()>)
+                                       -> Callee<'tcx> {
+    let _icx = push_ctxt("meth::callee_for_trait_impl");
     match vtable {
         traits::VtableImpl(vtable_impl) => {
-            let ccx = bcx.ccx();
             let impl_did = vtable_impl.impl_def_id;
-            let mname = match ccx.tcx().impl_or_trait_item(method_id) {
-                ty::MethodTraitItem(method) => method.name,
-                _ => {
-                    bcx.tcx().sess.bug("can't monomorphize a non-method trait \
-                                        item")
-                }
-            };
+            let mname = ccx.tcx().item_name(method_id);
             // create a concatenated set of substitutions which includes
             // those from the impl and those from the method:
-            let meth_substs = node_id_substs(ccx,
-                                             MethodCallKey(method_call),
-                                             bcx.fcx.param_substs);
-            let impl_substs = vtable_impl.substs.with_method_from(&meth_substs);
-            let mth = bcx.tcx().get_impl_method(impl_did, impl_substs, mname);
-            // translate the function
-            let datum = trans_fn_ref_with_substs(bcx.ccx(),
-                                                 mth.method.def_id,
-                                                 MethodCallKey(method_call),
-                                                 bcx.fcx.param_substs,
-                                                 mth.substs);
-
-            Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
+            let impl_substs = vtable_impl.substs.with_method_from(&substs);
+            let substs = ccx.tcx().mk_substs(impl_substs);
+            let mth = ccx.tcx().get_impl_method(impl_did, substs, mname);
+
+            // Translate the function, bypassing Callee::def.
+            // That is because default methods have the same ID as the
+            // trait method used to look up the impl method that ended
+            // up here, so calling Callee::def would infinitely recurse.
+            Callee::ptr(trans_fn_ref_with_substs(ccx, mth.method.def_id,
+                                                 Some(method_ty), mth.substs))
         }
         traits::VtableClosure(vtable_closure) => {
             // The substitutions should have no type parameters remaining
             // after passing through fulfill_obligation
-            let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
-            let llfn = closure::trans_closure_method(bcx.ccx(),
+            let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+            let llfn = closure::trans_closure_method(ccx,
                                                      vtable_closure.closure_def_id,
                                                      vtable_closure.substs,
                                                      trait_closure_kind);
-            Callee {
-                bcx: bcx,
-                data: Fn(llfn),
-                ty: monomorphize_type(bcx, method_ty)
-            }
+            let fn_ptr_ty = match method_ty.sty {
+                ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
+                _ => unreachable!("expected fn item type, found {}",
+                                  method_ty)
+            };
+            Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
         }
         traits::VtableFnPointer(fn_ty) => {
-            let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
-            let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
-            Callee {
-                bcx: bcx,
-                data: Fn(llfn),
-                ty: monomorphize_type(bcx, method_ty)
-            }
+            let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+            let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
+            let fn_ptr_ty = match method_ty.sty {
+                ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
+                _ => unreachable!("expected fn item type, found {}",
+                                  method_ty)
+            };
+            Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
         }
         traits::VtableObject(ref data) => {
-            let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id);
-            if let Some(self_expr) = self_expr {
-                if let ty::TyBareFn(_, ref fty) = monomorphize_type(bcx, method_ty).sty {
-                    let ty = bcx.tcx().mk_fn(None, opaque_method_ty(bcx.tcx(), fty));
-                    return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope);
-                }
+            Callee {
+                data: Virtual(traits::get_vtable_index_of_object_method(
+                    ccx.tcx(), data, method_id)),
+                ty: method_ty
             }
-            let datum = trans_object_shim(bcx.ccx(),
-                                          data.upcast_trait_ref.clone(),
-                                          method_id,
-                                          idx);
-            Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
         }
         traits::VtableBuiltin(..) |
         traits::VtableDefaultImpl(..) |
         traits::VtableParam(..) => {
-            bcx.sess().bug(
+            ccx.sess().bug(
                 &format!("resolved vtable bad vtable {:?} in trans",
                         vtable));
         }
     }
 }
 
-/// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type).
-/// In this case, we must pull the fn pointer out of the vtable that is packaged up with the
-/// object. Objects are represented as a pair, so we first evaluate the self expression and then
-/// extract the self data and vtable out of the pair.
-fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  opaque_fn_ty: Ty<'tcx>,
-                                  vtable_index: usize,
-                                  self_expr: &hir::Expr,
-                                  arg_cleanup_scope: cleanup::ScopeId)
-                                  -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_trait_callee");
-    let mut bcx = bcx;
-
-    // Translate self_datum and take ownership of the value by
-    // converting to an rvalue.
-    let self_datum = unpack_datum!(
-        bcx, expr::trans(bcx, self_expr));
-
-    let llval = if bcx.fcx.type_needs_drop(self_datum.ty) {
-        let self_datum = unpack_datum!(
-            bcx, self_datum.to_rvalue_datum(bcx, "trait_callee"));
-
-        // Convert to by-ref since `trans_trait_callee_from_llval` wants it
-        // that way.
-        let self_datum = unpack_datum!(
-            bcx, self_datum.to_ref_datum(bcx));
-
-        // Arrange cleanup in case something should go wrong before the
-        // actual call occurs.
-        self_datum.add_clean(bcx.fcx, arg_cleanup_scope)
-    } else {
-        // We don't have to do anything about cleanups for &Trait and &mut Trait.
-        assert!(self_datum.kind.is_by_ref());
-        self_datum.val
-    };
-
-    let llself = Load(bcx, expr::get_dataptr(bcx, llval));
-    let llvtable = Load(bcx, expr::get_meta(bcx, llval));
-    trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable)
-}
-
-/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
-/// pair.
-fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                             opaque_fn_ty: Ty<'tcx>,
-                                             vtable_index: usize,
-                                             llself: ValueRef,
-                                             llvtable: ValueRef)
-                                             -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_trait_callee");
+/// Extracts a method from a trait object's vtable, at the
+/// specified index, and casts it to the given type.
+pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                      llvtable: ValueRef,
+                                      vtable_index: usize,
+                                      method_ty: Ty<'tcx>)
+                                      -> Datum<'tcx, Rvalue> {
+    let _icx = push_ctxt("meth::get_virtual_method");
     let ccx = bcx.ccx();
 
     // Load the data pointer from the object.
-    debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})",
-           opaque_fn_ty,
+    debug!("get_virtual_method(callee_ty={}, vtable_index={}, llvtable={})",
+           method_ty,
            vtable_index,
-           bcx.val_to_string(llself),
            bcx.val_to_string(llvtable));
 
-    // Replace the self type (&Self or Box<Self>) with an opaque pointer.
     let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
-    let llcallee_ty = type_of_fn_from_ty(ccx, opaque_fn_ty);
 
-    Callee {
-        bcx: bcx,
-        data: TraitItem(MethodData {
-            llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()),
-            llself: PointerCast(bcx, llself, Type::i8p(ccx)),
-        }),
-        ty: opaque_fn_ty
+    // Replace the self type (&Self or Box<Self>) with an opaque pointer.
+    if let ty::TyFnDef(_, _, fty) = method_ty.sty {
+        let opaque_ty = opaque_method_ty(ccx.tcx(), fty);
+        immediate_rvalue(PointerCast(bcx, mptr, type_of(ccx, opaque_ty)), opaque_ty)
+    } else {
+        immediate_rvalue(mptr, method_ty)
     }
 }
 
@@ -374,46 +206,29 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 ///
 /// In fact, all virtual calls can be thought of as normal trait calls
 /// that go through this shim function.
-pub fn trans_object_shim<'a, 'tcx>(
-    ccx: &'a CrateContext<'a, 'tcx>,
-    upcast_trait_ref: ty::PolyTraitRef<'tcx>,
-    method_id: DefId,
-    vtable_index: usize)
-    -> Datum<'tcx, Rvalue>
-{
+pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
+                                   method_ty: Ty<'tcx>,
+                                   vtable_index: usize)
+                                   -> Datum<'tcx, Rvalue> {
     let _icx = push_ctxt("trans_object_shim");
     let tcx = ccx.tcx();
 
-    debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})",
-           upcast_trait_ref,
-           method_id);
+    debug!("trans_object_shim(vtable_index={}, method_ty={:?})",
+           vtable_index,
+           method_ty);
 
-    // Upcast to the trait in question and extract out the substitutions.
-    let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref);
-    let object_substs = upcast_trait_ref.substs.clone().erase_regions();
-    debug!("trans_object_shim: object_substs={:?}", object_substs);
+    let ret_ty = tcx.erase_late_bound_regions(&method_ty.fn_ret());
+    let ret_ty = infer::normalize_associated_type(tcx, &ret_ty);
 
-    // Lookup the type of this method as declared in the trait and apply substitutions.
-    let method_ty = match tcx.impl_or_trait_item(method_id) {
-        ty::MethodTraitItem(method) => method,
-        _ => {
-            tcx.sess.bug("can't create a method shim for a non-method item")
-        }
+    let shim_fn_ty = match method_ty.sty {
+        ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
+        _ => unreachable!("expected fn item type, found {}", method_ty)
     };
-    let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
-    let fty = tcx.mk_bare_fn(fty);
-    let method_ty = opaque_method_ty(tcx, fty);
-    debug!("trans_object_shim: fty={:?} method_ty={:?}", fty, method_ty);
 
     //
-    let shim_fn_ty = tcx.mk_fn(None, fty);
-    let method_bare_fn_ty = tcx.mk_fn(None, method_ty);
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
     let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty);
 
-    let sig = ccx.tcx().erase_late_bound_regions(&fty.sig);
-    let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
-
     let empty_substs = tcx.mk_substs(Substs::trans_empty());
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
     block_arena = TypedArena::new();
@@ -421,11 +236,11 @@ pub fn trans_object_shim<'a, 'tcx>(
                       llfn,
                       ast::DUMMY_NODE_ID,
                       false,
-                      sig.output,
+                      ret_ty,
                       empty_substs,
                       None,
                       &block_arena);
-    let mut bcx = init_function(&fcx, false, sig.output);
+    let mut bcx = init_function(&fcx, false, ret_ty);
 
     let llargs = get_params(fcx.llfn);
 
@@ -440,21 +255,18 @@ pub fn trans_object_shim<'a, 'tcx>(
 
     let dest =
         fcx.llretslotptr.get().map(
-            |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
+            |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot")));
 
     debug!("trans_object_shim: method_offset_in_vtable={}",
            vtable_index);
 
-    bcx = trans_call_inner(bcx,
-                           DebugLoc::None,
-                           |bcx, _| trans_trait_callee_from_llval(bcx,
-                                                                  method_bare_fn_ty,
-                                                                  vtable_index,
-                                                                  llself, llvtable),
-                           ArgVals(&llargs[(self_idx + 2)..]),
-                           dest).bcx;
+    let callee = Callee {
+        data: Virtual(vtable_index),
+        ty: method_ty
+    };
+    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
 
-    finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
+    finish_fn(&fcx, bcx, ret_ty, DebugLoc::None);
 
     immediate_rvalue(llfn, shim_fn_ty)
 }
@@ -466,8 +278,7 @@ pub fn trans_object_shim<'a, 'tcx>(
 /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
 /// `trait_ref` would map `T:Trait`.
 pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                            trait_ref: ty::PolyTraitRef<'tcx>,
-                            param_substs: &'tcx subst::Substs<'tcx>)
+                            trait_ref: ty::PolyTraitRef<'tcx>)
                             -> ValueRef
 {
     let tcx = ccx.tcx();
@@ -503,8 +314,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             Some(mth) => {
                                 trans_fn_ref_with_substs(ccx,
                                                          mth.method.def_id,
-                                                         ExprId(0),
-                                                         param_substs,
+                                                         None,
                                                          mth.substs).val
                             }
                             None => nullptr
@@ -567,7 +377,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     impl_id: DefId,
-                                    substs: subst::Substs<'tcx>)
+                                    substs: &'tcx subst::Substs<'tcx>)
                                     -> Vec<Option<ty::util::ImplMethod<'tcx>>>
 {
     let tcx = ccx.tcx();
@@ -618,7 +428,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
             // The substitutions we have are on the impl, so we grab
             // the method type from the impl to substitute into.
-            let mth = tcx.get_impl_method(impl_id, substs.clone(), name);
+            let mth = tcx.get_impl_method(impl_id, substs, name);
 
             debug!("get_vtable_methods: mth={:?}", mth);
 
@@ -628,7 +438,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // method could then never be called, so we do not want to
             // try and trans it, in that case. Issue #23435.
             if mth.is_provided {
-                let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
+                let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
                 if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
                     debug!("get_vtable_methods: predicates do not hold");
                     return None;
@@ -642,11 +452,11 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 /// Replace the self type (&Self or Box<Self>) with an opaque pointer.
 fn opaque_method_ty<'tcx>(tcx: &TyCtxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
-                          -> &'tcx ty::BareFnTy<'tcx> {
+                          -> Ty<'tcx> {
     let mut inputs = method_ty.sig.0.inputs.clone();
     inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::IntTy::I8));
 
-    tcx.mk_bare_fn(ty::BareFnTy {
+    tcx.mk_fn_ptr(ty::BareFnTy {
         unsafety: method_ty.unsafety,
         abi: method_ty.abi,
         sig: ty::Binder(ty::FnSig {
diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs
index a9fee18ded8..50283c0959c 100644
--- a/src/librustc_trans/trans/mir/block.rs
+++ b/src/librustc_trans/trans/mir/block.rs
@@ -9,72 +9,27 @@
 // except according to those terms.
 
 use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
-use rustc::middle::ty::{self, Ty};
+use rustc::middle::ty;
 use rustc::mir::repr as mir;
 use syntax::abi::Abi;
 use trans::adt;
 use trans::attributes;
 use trans::base;
 use trans::build;
+use trans::callee::{Callee, Fn, Virtual};
 use trans::common::{self, Block, BlockAndBuilder};
 use trans::debuginfo::DebugLoc;
 use trans::Disr;
 use trans::foreign;
+use trans::meth;
 use trans::type_of;
 use trans::glue;
 use trans::type_::Type;
 
 use super::{MirContext, drop};
 use super::operand::OperandValue::{FatPtr, Immediate, Ref};
-use super::operand::OperandRef;
-
-#[derive(PartialEq, Eq)]
-enum AbiStyle {
-    Foreign,
-    RustCall,
-    Rust
-}
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-    fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle {
-        if let ty::TyBareFn(_, ref f) = fn_ty.sty {
-            // We do not translate intrinsics here (they shouldn’t be functions)
-            assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
-
-            match f.abi {
-                Abi::Rust => AbiStyle::Rust,
-                Abi::RustCall => AbiStyle::RustCall,
-                _ => AbiStyle::Foreign
-            }
-        } else {
-            unreachable!()
-        }
-    }
-
-    fn arg_operands(&mut self,
-                    bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                    abi_style: AbiStyle,
-                    args: &[mir::Operand<'tcx>])
-                    -> Vec<OperandRef<'tcx>>
-    {
-        match abi_style {
-            AbiStyle::Foreign | AbiStyle::Rust => {
-                args.iter().map(|arg| self.trans_operand(bcx, arg)).collect()
-            }
-            AbiStyle::RustCall => match args.split_last() {
-                None => vec![],
-                Some((tup, self_ty)) => {
-                    // we can reorder safely because of MIR
-                    let untupled_args = self.trans_operand_untupled(bcx, tup);
-                    self_ty
-                        .iter().map(|arg| self.trans_operand(bcx, arg))
-                        .chain(untupled_args.into_iter())
-                        .collect()
-                }
-            }
-        }
-    }
-
     pub fn trans_block(&mut self, bb: mir::BasicBlock) {
         debug!("trans_block({:?})", bb);
 
@@ -197,9 +152,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             }
 
             mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => {
-                // Create the callee. This will always be a fn ptr and hence a kind of scalar.
+                // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
                 let callee = self.trans_operand(&bcx, func);
-                let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty);
                 let debugloc = DebugLoc::None;
                 // The arguments we'll be passing. Plus one to account for outptr, if used.
                 let mut llargs = Vec::with_capacity(args.len() + 1);
@@ -207,9 +161,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 // filled when `is_foreign` is `true` and foreign calls are minority of the cases.
                 let mut arg_tys = Vec::new();
 
+                let (callee, fty) = match callee.ty.sty {
+                    ty::TyFnDef(def_id, substs, f) => {
+                        (Callee::def(bcx.ccx(), def_id, substs, callee.ty), f)
+                    }
+                    ty::TyFnPtr(f) => {
+                        (Callee {
+                            data: Fn(callee.immediate()),
+                            ty: callee.ty
+                        }, f)
+                    }
+                    _ => unreachable!("{} is not callable", callee.ty)
+                };
+
+                // We do not translate intrinsics here (they shouldn’t be functions)
+                assert!(fty.abi != Abi::RustIntrinsic && fty.abi != Abi::PlatformIntrinsic);
                 // Foreign-ABI functions are translated differently
-                let abi_style = self.abi_style(callee.ty);
-                let is_foreign = abi_style == AbiStyle::Foreign;
+                let is_foreign = fty.abi != Abi::Rust && fty.abi != Abi::RustCall;
 
                 // Prepare the return value destination
                 let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
@@ -225,19 +193,58 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     (None, false)
                 };
 
-                // Process the rest of the args.
-                for operand in self.arg_operands(&bcx, abi_style, args) {
-                    match operand.val {
-                        Ref(llval) | Immediate(llval) => llargs.push(llval),
-                        FatPtr(b, e) => {
-                            llargs.push(b);
-                            llargs.push(e);
+                // Split the rust-call tupled arguments off.
+                let (args, rest) = if fty.abi == Abi::RustCall && !args.is_empty() {
+                    let (tup, args) = args.split_last().unwrap();
+                    // we can reorder safely because of MIR
+                    (args, self.trans_operand_untupled(&bcx, tup))
+                } else {
+                    (&args[..], vec![])
+                };
+
+                let datum = {
+                    let mut arg_ops = args.iter().map(|arg| {
+                        self.trans_operand(&bcx, arg)
+                    }).chain(rest.into_iter());
+
+                    // Get the actual pointer we can call.
+                    // This can involve vtable accesses or reification.
+                    let datum = if let Virtual(idx) = callee.data {
+                        assert!(!is_foreign);
+
+                        // Grab the first argument which is a trait object.
+                        let vtable = match arg_ops.next().unwrap().val {
+                            FatPtr(data, vtable) => {
+                                llargs.push(data);
+                                vtable
+                            }
+                            _ => unreachable!("expected FatPtr for Virtual call")
+                        };
+
+                        bcx.with_block(|bcx| {
+                            meth::get_virtual_method(bcx, vtable, idx, callee.ty)
+                        })
+                    } else {
+                        callee.reify(bcx.ccx())
+                    };
+
+                    // Process the rest of the args.
+                    for operand in arg_ops {
+                        match operand.val {
+                            Ref(llval) | Immediate(llval) => llargs.push(llval),
+                            FatPtr(b, e) => {
+                                llargs.push(b);
+                                llargs.push(e);
+                            }
+                        }
+                        if is_foreign {
+                            arg_tys.push(operand.ty);
                         }
                     }
-                    if is_foreign {
-                        arg_tys.push(operand.ty);
-                    }
-                }
+
+                    datum
+                };
+                let attrs = attributes::from_fn_type(bcx.ccx(), datum.ty);
 
                 // Many different ways to call a function handled here
                 match (is_foreign, cleanup, destination) {
@@ -246,7 +253,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         let cleanup = self.bcx(cleanup);
                         let landingpad = self.make_landing_pad(cleanup);
                         let unreachable_blk = self.unreachable_block();
-                        bcx.invoke(callee.immediate(),
+                        bcx.invoke(datum.val,
                                    &llargs[..],
                                    unreachable_blk.llbb,
                                    landingpad.llbb(),
@@ -259,7 +266,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     (false, &Some(cleanup), &Some((_, success))) => {
                         let cleanup = self.bcx(cleanup);
                         let landingpad = self.make_landing_pad(cleanup);
-                        let invokeret = bcx.invoke(callee.immediate(),
+                        let invokeret = bcx.invoke(datum.val,
                                                    &llargs[..],
                                                    self.llblock(success),
                                                    landingpad.llbb(),
@@ -282,7 +289,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         });
                     },
                     (false, _, &None) => {
-                        bcx.call(callee.immediate(),
+                        bcx.call(datum.val,
                                  &llargs[..],
                                  cleanup_bundle.as_ref(),
                                  Some(attrs));
@@ -290,7 +297,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         bcx.unreachable();
                     }
                     (false, _, &Some((_, target))) => {
-                        let llret = bcx.call(callee.immediate(),
+                        let llret = bcx.call(datum.val,
                                              &llargs[..],
                                              cleanup_bundle.as_ref(),
                                              Some(attrs));
@@ -312,8 +319,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             .expect("return destination is not set");
                         bcx = bcx.map_block(|bcx| {
                             foreign::trans_native_call(bcx,
-                                                       callee.ty,
-                                                       callee.immediate(),
+                                                       datum.ty,
+                                                       datum.val,
                                                        dest.llval,
                                                        &llargs[..],
                                                        arg_tys,
diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs
index 7f03069385f..a0615a6cf5b 100644
--- a/src/librustc_trans/trans/mir/constant.rs
+++ b/src/librustc_trans/trans/mir/constant.rs
@@ -10,14 +10,14 @@
 
 use back::abi;
 use llvm::ValueRef;
-use middle::subst::Substs;
 use middle::ty::{Ty, TypeFoldable};
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_eval::{self, ConstVal};
 use rustc::mir::repr as mir;
 use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
-                    C_str_slice};
+                    C_str_slice, C_nil, C_undef};
 use trans::consts;
 use trans::expr;
+use trans::inline;
 use trans::type_of;
 
 use super::operand::{OperandRef, OperandValue};
@@ -32,7 +32,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                           -> OperandRef<'tcx>
     {
         let ccx = bcx.ccx();
-        let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx().param_substs);
+        let val = self.trans_constval_inner(bcx, cv, ty);
         let val = if common::type_is_immediate(ccx, ty) {
             OperandValue::Immediate(val)
         } else if common::type_is_fat_ptr(bcx.tcx(), ty) {
@@ -55,8 +55,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     fn trans_constval_inner(&mut self,
                             bcx: &BlockAndBuilder<'bcx, 'tcx>,
                             cv: &ConstVal,
-                            ty: Ty<'tcx>,
-                            param_substs: &'tcx Substs<'tcx>)
+                            ty: Ty<'tcx>)
                             -> ValueRef
     {
         let ccx = bcx.ccx();
@@ -75,8 +74,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     expr::trans(bcx, expr).datum.val
                 })
             },
-            ConstVal::Function(did) =>
-                self.trans_fn_ref(bcx, ty, param_substs, did).immediate()
+            ConstVal::Function(_) => C_nil(ccx)
         }
     }
 
@@ -85,13 +83,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                           constant: &mir::Constant<'tcx>)
                           -> OperandRef<'tcx>
     {
+        let ty = bcx.monomorphize(&constant.ty);
         match constant.literal {
-            mir::Literal::Item { def_id, kind, substs } => {
+            mir::Literal::Item { def_id, substs } => {
+                // Shortcut for zero-sized types, including function item
+                // types, which would not work with lookup_const_by_id.
+                if common::type_is_zero_size(bcx.ccx(), ty) {
+                    let llty = type_of::type_of(bcx.ccx(), ty);
+                    return OperandRef {
+                        val: OperandValue::Immediate(C_undef(llty)),
+                        ty: ty
+                    };
+                }
+
                 let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
-                self.trans_item_ref(bcx, constant.ty, kind, substs, def_id)
+                let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
+                let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs))
+                            .expect("def was const, but lookup_const_by_id failed");
+                // FIXME: this is falling back to translating from HIR. This is not easy to fix,
+                // because we would have somehow adapt const_eval to work on MIR rather than HIR.
+                let d = bcx.with_block(|bcx| {
+                    expr::trans(bcx, expr)
+                });
+                OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
             }
             mir::Literal::Value { ref value } => {
-                let ty = bcx.monomorphize(&constant.ty);
                 self.trans_constval(bcx, value, ty)
             }
         }
diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs
deleted file mode 100644
index 3741b07d248..00000000000
--- a/src/librustc_trans/trans/mir/did.rs
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Code for translating references to other items (DefIds).
-
-use syntax::codemap::DUMMY_SP;
-use rustc::front::map;
-use rustc::middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::middle::subst::Substs;
-use rustc::middle::const_eval;
-use rustc::middle::def_id::DefId;
-use rustc::middle::traits;
-use rustc::mir::repr::ItemKind;
-use trans::common::{BlockAndBuilder, fulfill_obligation};
-use trans::base;
-use trans::closure;
-use trans::expr;
-use trans::monomorphize;
-use trans::meth;
-use trans::inline;
-
-use super::MirContext;
-use super::operand::{OperandRef, OperandValue};
-
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-    /// Translate reference to item.
-    pub fn trans_item_ref(&mut self,
-                          bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                          ty: Ty<'tcx>,
-                          kind: ItemKind,
-                          substs: &'tcx Substs<'tcx>,
-                          did: DefId)
-                          -> OperandRef<'tcx> {
-        debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})",
-            ty, kind, substs, bcx.tcx().item_path_str(did));
-
-        match kind {
-            ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
-            ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
-                ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
-                ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs)
-            },
-            ItemKind::Constant => {
-                let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
-                let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs))
-                            .expect("def was const, but lookup_const_by_id failed");
-                // FIXME: this is falling back to translating from HIR. This is not easy to fix,
-                // because we would have somehow adapt const_eval to work on MIR rather than HIR.
-                let d = bcx.with_block(|bcx| {
-                    expr::trans(bcx, expr)
-                });
-                OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
-            }
-        }
-    }
-
-    /// Translates references to a function-like items.
-    ///
-    /// That includes regular functions, non-static methods, struct and enum variant constructors,
-    /// closures and possibly more.
-    ///
-    /// This is an adaptation of callee::trans_fn_ref_with_substs.
-    pub fn trans_fn_ref(&mut self,
-                        bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                        ty: Ty<'tcx>,
-                        substs: &'tcx Substs<'tcx>,
-                        did: DefId)
-                        -> OperandRef<'tcx> {
-        debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})",
-            ty, substs, bcx.tcx().item_path_str(did));
-
-        let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
-
-        if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) {
-            let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs, None);
-            // FIXME: cast fnptr to proper type if necessary
-            OperandRef {
-                ty: fn_ty,
-                val: OperandValue::Immediate(val)
-            }
-        } else {
-            let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
-                base::get_item_val(bcx.ccx(), node_id)
-            } else {
-                base::trans_external_path(bcx.ccx(), did, ty)
-            };
-            // FIXME: cast fnptr to proper type if necessary
-            OperandRef {
-                ty: ty,
-                val: OperandValue::Immediate(val)
-            }
-        }
-    }
-
-    /// Translates references to trait methods.
-    ///
-    /// This is an adaptation of meth::trans_static_method_callee
-    pub fn trans_trait_method(&mut self,
-                              bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                              ty: Ty<'tcx>,
-                              method_id: DefId,
-                              trait_id: DefId,
-                              substs: &'tcx Substs<'tcx>)
-                              -> OperandRef<'tcx> {
-        debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})",
-                ty,
-                bcx.tcx().item_path_str(method_id),
-                bcx.tcx().item_path_str(trait_id),
-                substs);
-
-        let ccx = bcx.ccx();
-        let tcx = bcx.tcx();
-        let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
-        let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
-        match vtbl {
-            traits::VtableImpl(traits::VtableImplData {
-                impl_def_id, substs: impl_substs, ..
-            }) => {
-                assert!(!impl_substs.types.needs_infer());
-
-                let mname = tcx.item_name(method_id);
-
-                let callee_substs = impl_substs.with_method_from(substs);
-                let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
-                let mth_substs = tcx.mk_substs(mth.substs);
-                self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id)
-            },
-            traits::VtableClosure(data) => {
-                let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
-                let llfn = closure::trans_closure_method(bcx.ccx(),
-                                                         data.closure_def_id,
-                                                         data.substs,
-                                                         trait_closure_kind);
-                OperandRef {
-                    ty: ty,
-                    val: OperandValue::Immediate(llfn)
-                }
-            },
-            traits::VtableObject(ref data) => {
-                let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
-                OperandRef::from_rvalue_datum(
-                    meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx)
-                )
-            }
-            _ => {
-                tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl));
-            }
-        }
-   }
-}
-
-fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
-    let node_id = match tcx.map.as_local_node_id(def_id) {
-        Some(n) => n,
-        None => { return false; }
-    };
-    match tcx.map.find(node_id).expect("local item should be in ast map") {
-        map::NodeVariant(v) => {
-            v.node.data.is_tuple()
-        }
-        map::NodeStructCtor(_) => true,
-        _ => false
-    }
-}
diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs
index 40dc22e31aa..4ad2e035945 100644
--- a/src/librustc_trans/trans/mir/mod.rs
+++ b/src/librustc_trans/trans/mir/mod.rs
@@ -196,7 +196,6 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
 mod analyze;
 mod block;
 mod constant;
-mod did;
 mod drop;
 mod lvalue;
 mod operand;
diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs
index 541df43b49b..ce10ed425f6 100644
--- a/src/librustc_trans/trans/mir/rvalue.rs
+++ b/src/librustc_trans/trans/mir/rvalue.rs
@@ -15,6 +15,7 @@ use rustc::mir::repr as mir;
 
 use trans::asm;
 use trans::base;
+use trans::callee::Callee;
 use trans::common::{self, BlockAndBuilder, Result};
 use trans::debuginfo::DebugLoc;
 use trans::declare;
@@ -193,9 +194,20 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let cast_ty = bcx.monomorphize(&cast_ty);
 
                 let val = match *kind {
-                    mir::CastKind::ReifyFnPointer |
+                    mir::CastKind::ReifyFnPointer => {
+                        match operand.ty.sty {
+                            ty::TyFnDef(def_id, substs, _) => {
+                                OperandValue::Immediate(
+                                    Callee::def(bcx.ccx(), def_id, substs, operand.ty)
+                                        .reify(bcx.ccx()).val)
+                            }
+                            _ => {
+                                unreachable!("{} cannot be reified to a fn ptr", operand.ty)
+                            }
+                        }
+                    }
                     mir::CastKind::UnsafeFnPointer => {
-                        // these are no-ops at the LLVM level
+                        // this is a no-op at the LLVM level
                         operand.val
                     }
                     mir::CastKind::Unsize => {
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 9edda3d2b5c..c6119416e47 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -37,16 +37,9 @@ use std::hash::{Hasher, Hash, SipHasher};
 
 pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 fn_id: DefId,
-                                psubsts: &'tcx subst::Substs<'tcx>,
-                                ref_id: Option<ast::NodeId>)
+                                psubsts: &'tcx subst::Substs<'tcx>)
                                 -> (ValueRef, Ty<'tcx>, bool) {
-    debug!("monomorphic_fn(\
-            fn_id={:?}, \
-            real_substs={:?}, \
-            ref_id={:?})",
-           fn_id,
-           psubsts,
-           ref_id);
+    debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts);
 
     assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types());
 
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index 24a7fd372f6..b78bf9bfc3f 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -150,26 +150,6 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     Type::func(&atys[..], &lloutputtype)
 }
 
-// Given a function type and a count of ty params, construct an llvm type
-pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type {
-    match fty.sty {
-        ty::TyBareFn(_, ref f) => {
-            // FIXME(#19925) once fn item types are
-            // zero-sized, we'll need to do something here
-            if f.abi == Abi::Rust || f.abi == Abi::RustCall {
-                let sig = cx.tcx().erase_late_bound_regions(&f.sig);
-                let sig = infer::normalize_associated_type(cx.tcx(), &sig);
-                type_of_rust_fn(cx, None, &sig, f.abi)
-            } else {
-                foreign::lltype_for_foreign_fn(cx, fty)
-            }
-        }
-        _ => {
-            cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn")
-        }
-    }
-}
-
 // A "sizing type" is an LLVM type, the size and alignment of which are
 // guaranteed to be equivalent to what you would get out of `type_of()`. It's
 // useful because:
@@ -210,7 +190,8 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
             }
         }
 
-        ty::TyBareFn(..) => Type::i8p(cx),
+        ty::TyFnDef(..) => Type::nil(cx),
+        ty::TyFnPtr(_) => Type::i8p(cx),
 
         ty::TyArray(ty, size) => {
             let llty = sizing_type_of(cx, ty);
@@ -415,8 +396,15 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TySlice(ty) => in_memory_type_of(cx, ty),
       ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
 
-      ty::TyBareFn(..) => {
-          type_of_fn_from_ty(cx, t).ptr_to()
+      ty::TyFnDef(..) => Type::nil(cx),
+      ty::TyFnPtr(f) => {
+        if f.abi == Abi::Rust || f.abi == Abi::RustCall {
+            let sig = cx.tcx().erase_late_bound_regions(&f.sig);
+            let sig = infer::normalize_associated_type(cx.tcx(), &sig);
+            type_of_rust_fn(cx, None, &sig, f.abi).ptr_to()
+        } else {
+            foreign::lltype_for_foreign_fn(cx, t).ptr_to()
+        }
       }
       ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
       ty::TyTuple(..) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 134da7a3bb0..1938fa75829 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1636,8 +1636,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
         }
         hir::TyBareFn(ref bf) => {
             require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
-            let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &bf.decl);
-            tcx.mk_fn(None, tcx.mk_bare_fn(bare_fn))
+            tcx.mk_fn_ptr(ty_of_bare_fn(this, bf.unsafety, bf.abi, &bf.decl))
         }
         hir::TyPolyTraitRef(ref bounds) => {
             conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds)
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 548f5ee5e94..305970db9e7 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -15,9 +15,10 @@ use middle::pat_util::pat_is_resolved_const;
 use middle::subst::Substs;
 use middle::ty::{self, Ty, TypeFoldable, LvaluePreference};
 use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
-use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
+use check::{demand, FnCtxt, Expectation};
 use check::{check_expr_with_lvalue_pref};
 use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
+use check::coercion;
 use lint;
 use require_same_types;
 use util::nodemap::FnvHashMap;
@@ -492,54 +493,67 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // of execution reach it, we will panic, so bottom is an appropriate
     // type in that case)
     let expected = expected.adjust_for_branches(fcx);
-    let result_ty = arms.iter().fold(fcx.infcx().next_diverging_ty_var(), |result_ty, arm| {
-        let bty = match expected {
-            // We don't coerce to `()` so that if the match expression is a
-            // statement it's branches can have any consistent type. That allows
-            // us to give better error messages (pointing to a usually better
-            // arm for inconsistent arms or to the whole match when a `()` type
-            // is required).
-            Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => {
-                check_expr_coercable_to_type(fcx, &arm.body, ety);
-                ety
-            }
-            _ => {
-                check_expr_with_expectation(fcx, &arm.body, expected);
-                fcx.node_ty(arm.body.id)
+    let mut result_ty = fcx.infcx().next_diverging_ty_var();
+    let coerce_first = match expected {
+        // We don't coerce to `()` so that if the match expression is a
+        // statement it's branches can have any consistent type. That allows
+        // us to give better error messages (pointing to a usually better
+        // arm for inconsistent arms or to the whole match when a `()` type
+        // is required).
+        Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => {
+            ety
+        }
+        _ => result_ty
+    };
+    for (i, arm) in arms.iter().enumerate() {
+        if let Some(ref e) = arm.guard {
+            check_expr_has_type(fcx, e, tcx.types.bool);
+        }
+        check_expr_with_expectation(fcx, &arm.body, expected);
+        let arm_ty = fcx.expr_ty(&arm.body);
+
+        if result_ty.references_error() || arm_ty.references_error() {
+            result_ty = tcx.types.err;
+            continue;
+        }
+
+        // Handle the fallback arm of a desugared if-let like a missing else.
+        let is_if_let_fallback = match match_src {
+            hir::MatchSource::IfLetDesugar { contains_else_clause: false } => {
+                i == arms.len() - 1 && arm_ty.is_nil()
             }
+            _ => false
         };
 
-        if let Some(ref e) = arm.guard {
-            check_expr_has_type(fcx, &e, tcx.types.bool);
-        }
+        let origin = if is_if_let_fallback {
+            TypeOrigin::IfExpressionWithNoElse(expr.span)
+        } else {
+            TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src)
+        };
 
-        if result_ty.references_error() || bty.references_error() {
-            tcx.types.err
+        let result = if is_if_let_fallback {
+            fcx.infcx().eq_types(true, origin, arm_ty, result_ty).map(|_| arm_ty)
+        } else if i == 0 {
+            // Special-case the first arm, as it has no "previous expressions".
+            coercion::try(fcx, &arm.body, coerce_first)
         } else {
-            let (origin, expected, found) = match match_src {
-                /* if-let construct without an else block */
-                hir::MatchSource::IfLetDesugar { contains_else_clause }
-                if !contains_else_clause => (
-                    TypeOrigin::IfExpressionWithNoElse(expr.span),
-                    bty,
-                    result_ty,
-                ),
-                _ => (
-                    TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src),
-                    result_ty,
-                    bty,
-                ),
-            };
+            let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
+            coercion::try_find_lub(fcx, origin, prev_arms, result_ty, &arm.body)
+        };
 
-            infer::common_supertype(
-                fcx.infcx(),
-                origin,
-                true,
-                expected,
-                found,
-            )
-        }
-    });
+        result_ty = match result {
+            Ok(ty) => ty,
+            Err(e) => {
+                let (expected, found) = if is_if_let_fallback {
+                    (arm_ty, result_ty)
+                } else {
+                    (result_ty, arm_ty)
+                };
+                fcx.infcx().report_mismatched_types(origin, expected, found, e);
+                fcx.tcx().types.err
+            }
+        };
+    }
 
     fcx.write_ty(expr.id, result_ty);
 }
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 42ea3cc2aaa..bf60f435a22 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -82,7 +82,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         autoderef(fcx,
                   callee_expr.span,
                   original_callee_ty,
-                  Some(callee_expr),
+                  || Some(callee_expr),
                   UnresolvedTypeAction::Error,
                   LvaluePreference::NoPreference,
                   |adj_ty, idx| {
@@ -130,7 +130,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     // If the callee is a bare function or a closure, then we're all set.
     match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
-        ty::TyBareFn(..) => {
+        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
             fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
             return Some(CallStep::Builtin);
         }
@@ -225,7 +225,8 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     let error_fn_sig;
 
     let fn_sig = match callee_ty.sty {
-        ty::TyBareFn(_, &ty::BareFnTy {ref sig, ..}) => {
+        ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) |
+        ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => {
             sig
         }
         _ => {
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 2ea0df280db..b5cd5d7f8e5 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -55,7 +55,7 @@ use syntax::ast;
 /// Reifies a cast check to be checked once we have full type information for
 /// a function context.
 pub struct CastCheck<'tcx> {
-    expr: hir::Expr,
+    expr: &'tcx hir::Expr,
     expr_ty: Ty<'tcx>,
     cast_ty: Ty<'tcx>,
     span: Span,
@@ -109,7 +109,7 @@ enum CastError {
 }
 
 impl<'tcx> CastCheck<'tcx> {
-    pub fn new(expr: hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
+    pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
                -> CastCheck<'tcx> {
         CastCheck {
             expr: expr,
@@ -235,6 +235,20 @@ impl<'tcx> CastCheck<'tcx> {
         let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty),
                                       CastTy::from_ty(self.cast_ty)) {
             (Some(t_from), Some(t_cast)) => (t_from, t_cast),
+            // Function item types may need to be reified before casts.
+            (None, Some(t_cast)) => {
+                if let ty::TyFnDef(_, _, f) = self.expr_ty.sty {
+                    // Attempt a coercion to a fn pointer type.
+                    let res = coercion::try(fcx, self.expr,
+                                            fcx.tcx().mk_ty(ty::TyFnPtr(f)));
+                    if !res.is_ok() {
+                        return Err(CastError::NonScalar);
+                    }
+                    (FnPtr, t_cast)
+                } else {
+                    return Err(CastError::NonScalar);
+                }
+            }
             _ => {
                 return Err(CastError::NonScalar)
             }
@@ -376,14 +390,7 @@ impl<'tcx> CastCheck<'tcx> {
     }
 
     fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
-        if let Ok(()) = coercion::mk_assignty(fcx,
-                                              &self.expr,
-                                              self.expr_ty,
-                                              self.cast_ty) {
-            true
-        } else {
-            false
-        }
+        coercion::try(fcx, self.expr, self.cast_ty).is_ok()
     }
 
 }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 5ab3c6f983f..aa359c95e2d 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -62,7 +62,7 @@
 
 use check::{autoderef, FnCtxt, UnresolvedTypeAction};
 
-use middle::infer::{self, Coercion, TypeOrigin};
+use middle::infer::{Coercion, TypeOrigin, TypeTrace};
 use middle::traits::{self, ObligationCause};
 use middle::traits::{predicate_for_trait_def, report_selection_error};
 use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
@@ -71,7 +71,7 @@ use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
 use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt};
 use middle::ty::fold::TypeFoldable;
 use middle::ty::error::TypeError;
-use middle::ty::relate::RelateResult;
+use middle::ty::relate::{relate_substs, RelateResult, TypeRelation};
 use util::common::indent;
 
 use std::cell::RefCell;
@@ -80,42 +80,75 @@ use rustc_front::hir;
 
 struct Coerce<'a, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'tcx>,
-    origin: infer::TypeOrigin,
+    origin: TypeOrigin,
+    use_lub: bool,
     unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
 }
 
-type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>;
+type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>;
+
+fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
+                       to_mutbl: hir::Mutability)
+                       -> RelateResult<'tcx, ()> {
+    match (from_mutbl, to_mutbl) {
+        (hir::MutMutable, hir::MutMutable) |
+        (hir::MutImmutable, hir::MutImmutable) |
+        (hir::MutMutable, hir::MutImmutable) => Ok(()),
+        (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
+    }
+}
 
 impl<'f, 'tcx> Coerce<'f, 'tcx> {
+    fn new(fcx: &'f FnCtxt<'f, 'tcx>, origin: TypeOrigin) -> Self {
+        Coerce {
+            fcx: fcx,
+            origin: origin,
+            use_lub: false,
+            unsizing_obligations: RefCell::new(vec![])
+        }
+    }
+
     fn tcx(&self) -> &TyCtxt<'tcx> {
         self.fcx.tcx()
     }
 
-    fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
-        try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
-        Ok(None) // No coercion required.
+    /// Unify two types (using sub or lub) and produce a noop coercion.
+    fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
+        let infcx = self.fcx.infcx();
+        infcx.commit_if_ok(|_| {
+            let trace = TypeTrace::types(self.origin, false, a, b);
+            if self.use_lub {
+                infcx.lub(false, trace).relate(&a, &b)
+            } else {
+                infcx.sub(false, trace).relate(&a, &b)
+            }
+        }).and_then(|ty| self.identity(ty))
     }
 
-    fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
-        F: FnOnce(Ty<'tcx>) -> T,
-    {
-        f(self.fcx.infcx().shallow_resolve(a))
+    /// Synthesize an identity adjustment.
+    fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
+        Ok((ty, AdjustDerefRef(AutoDerefRef {
+            autoderefs: 0,
+            autoref: None,
+            unsize: None
+        })))
     }
 
-    fn coerce(&self,
-              expr_a: &hir::Expr,
-              a: Ty<'tcx>,
-              b: Ty<'tcx>)
-              -> CoerceResult<'tcx> {
-        debug!("Coerce.tys({:?} => {:?})",
-               a,
-               b);
+    fn coerce<'a, E, I>(&self,
+                        exprs: &E,
+                        a: Ty<'tcx>,
+                        b: Ty<'tcx>)
+                        -> CoerceResult<'tcx>
+        // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+        where E: Fn() -> I,
+              I: IntoIterator<Item=&'a hir::Expr> {
 
         let a = self.fcx.infcx().shallow_resolve(a);
+        debug!("Coerce.tys({:?} => {:?})", a, b);
 
         // Just ignore error types.
         if a.references_error() || b.references_error() {
-            return Ok(None);
+            return self.identity(b);
         }
 
         // Consider coercing the subtype to a DST
@@ -134,27 +167,27 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
 
             ty::TyRef(_, mt_b) => {
-                return self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl);
+                return self.coerce_borrowed_pointer(exprs, a, b, mt_b.mutbl);
             }
 
             _ => {}
         }
 
         match a.sty {
-            ty::TyBareFn(Some(_), a_f) => {
+            ty::TyFnDef(_, _, a_f) => {
                 // Function items are coercible to any closure
                 // type; function pointers are not (that would
                 // require double indirection).
                 self.coerce_from_fn_item(a, a_f, b)
             }
-            ty::TyBareFn(None, a_f) => {
+            ty::TyFnPtr(a_f) => {
                 // We permit coercion of fn pointers to drop the
                 // unsafe qualifier.
                 self.coerce_from_fn_pointer(a, a_f, b)
             }
             _ => {
-                // Otherwise, just use subtyping rules.
-                self.subtype(a, b)
+                // Otherwise, just use unification rules.
+                self.unify(a, b)
             }
         }
     }
@@ -162,15 +195,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
     /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
     /// To match `A` with `B`, autoderef will be performed,
     /// calling `deref`/`deref_mut` where necessary.
-    fn coerce_borrowed_pointer(&self,
-                               expr_a: &hir::Expr,
-                               a: Ty<'tcx>,
-                               b: Ty<'tcx>,
-                               mutbl_b: hir::Mutability)
-                               -> CoerceResult<'tcx> {
-        debug!("coerce_borrowed_pointer(a={:?}, b={:?})",
-               a,
-               b);
+    fn coerce_borrowed_pointer<'a, E, I>(&self,
+                                         exprs: &E,
+                                         a: Ty<'tcx>,
+                                         b: Ty<'tcx>,
+                                         mutbl_b: hir::Mutability)
+                                         -> CoerceResult<'tcx>
+        // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+        where E: Fn() -> I,
+              I: IntoIterator<Item=&'a hir::Expr> {
+
+        debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
 
         // If we have a parameter of type `&M T_a` and the value
         // provided is `expr`, we will be adding an implicit borrow,
@@ -182,20 +217,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             ty::TyRef(_, mt_a) => {
                 try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
             }
-            _ => return self.subtype(a, b)
+            _ => return self.unify(a, b)
         }
 
-        let coercion = Coercion(self.origin.span());
+        let span = self.origin.span();
+        let coercion = Coercion(span);
         let r_borrow = self.fcx.infcx().next_region_var(coercion);
         let r_borrow = self.tcx().mk_region(r_borrow);
         let autoref = Some(AutoPtr(r_borrow, mutbl_b));
 
         let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
         let mut first_error = None;
-        let (_, autoderefs, success) = autoderef(self.fcx,
-                                                 expr_a.span,
-                                                 a,
-                                                 Some(expr_a),
+        let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs,
                                                  UnresolvedTypeAction::Ignore,
                                                  lvalue_pref,
                                                  |inner_ty, autoderef| {
@@ -206,19 +239,20 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
             let ty = self.tcx().mk_ref(r_borrow,
                                         TypeAndMut {ty: inner_ty, mutbl: mutbl_b});
-            if let Err(err) = self.subtype(ty, b) {
-                if first_error.is_none() {
-                    first_error = Some(err);
+            match self.unify(ty, b) {
+                Err(err) => {
+                    if first_error.is_none() {
+                        first_error = Some(err);
+                    }
+                    None
                 }
-                None
-            } else {
-                Some(())
+                Ok((ty, _)) => Some(ty)
             }
         });
 
         match success {
-            Some(_) => {
-                Ok(Some(AdjustDerefRef(AutoDerefRef {
+            Some(ty) => {
+                Ok((ty, AdjustDerefRef(AutoDerefRef {
                     autoderefs: autoderefs,
                     autoref: autoref,
                     unsize: None
@@ -329,9 +363,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
         }
 
-        let mut obligations = self.unsizing_obligations.borrow_mut();
-        assert!(obligations.is_empty());
-        *obligations = leftover_predicates;
+        *self.unsizing_obligations.borrow_mut() = leftover_predicates;
 
         let adjustment = AutoDerefRef {
             autoderefs: if reborrow.is_some() { 1 } else { 0 },
@@ -339,7 +371,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             unsize: Some(target)
         };
         debug!("Success, coerced with {:?}", adjustment);
-        Ok(Some(AdjustDerefRef(adjustment)))
+        Ok((target, AdjustDerefRef(adjustment)))
     }
 
     fn coerce_from_fn_pointer(&self,
@@ -353,22 +385,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
          * into a closure or a `proc`.
          */
 
-        self.unpack_actual_value(b, |b| {
-            debug!("coerce_from_fn_pointer(a={:?}, b={:?})",
-                   a, b);
+        let b = self.fcx.infcx().shallow_resolve(b);
+        debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
 
-            if let ty::TyBareFn(None, fn_ty_b) = b.sty {
-                match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
-                    (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
-                        let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
-                        try!(self.subtype(unsafe_a, b));
-                        return Ok(Some(AdjustUnsafeFnPointer));
-                    }
-                    _ => {}
+        if let ty::TyFnPtr(fn_ty_b) = b.sty {
+            match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
+                (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
+                    let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
+                    return self.unify(unsafe_a, b).map(|(ty, _)| {
+                        (ty, AdjustUnsafeFnPointer)
+                    });
                 }
+                _ => {}
             }
-            self.subtype(a, b)
-        })
+        }
+        self.unify(a, b)
     }
 
     fn coerce_from_fn_item(&self,
@@ -381,19 +412,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
          * into a closure or a `proc`.
          */
 
-        self.unpack_actual_value(b, |b| {
-            debug!("coerce_from_fn_item(a={:?}, b={:?})",
-                   a, b);
+        let b = self.fcx.infcx().shallow_resolve(b);
+        debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
 
-            match b.sty {
-                ty::TyBareFn(None, _) => {
-                    let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a);
-                    try!(self.subtype(a_fn_pointer, b));
-                    Ok(Some(AdjustReifyFnPointer))
-                }
-                _ => self.subtype(a, b)
+        match b.sty {
+            ty::TyFnPtr(_) => {
+                let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a));
+                self.unify(a_fn_pointer, b).map(|(ty, _)| {
+                    (ty, AdjustReifyFnPointer)
+                })
             }
-        })
+            _ => self.unify(a, b)
+        }
     }
 
     fn coerce_unsafe_ptr(&self,
@@ -409,74 +439,192 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             ty::TyRef(_, mt) => (true, mt),
             ty::TyRawPtr(mt) => (false, mt),
             _ => {
-                return self.subtype(a, b);
+                return self.unify(a, b);
             }
         };
 
         // Check that the types which they point at are compatible.
         let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
-        try!(self.subtype(a_unsafe, b));
+        let (ty, noop) = try!(self.unify(a_unsafe, b));
         try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
 
         // Although references and unsafe ptrs have the same
         // representation, we still register an AutoDerefRef so that
         // regionck knows that the region for `a` must be valid here.
-        if is_ref {
-            Ok(Some(AdjustDerefRef(AutoDerefRef {
+        Ok((ty, if is_ref {
+            AdjustDerefRef(AutoDerefRef {
                 autoderefs: 1,
                 autoref: Some(AutoUnsafe(mutbl_b)),
                 unsize: None
-            })))
+            })
         } else if mt_a.mutbl != mutbl_b {
-            Ok(Some(AdjustMutToConstPointer))
+            AdjustMutToConstPointer
         } else {
-            Ok(None)
-        }
+            noop
+        }))
     }
 }
 
-pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                             expr: &hir::Expr,
+fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>,
+                             exprs: &E,
                              a: Ty<'tcx>,
                              b: Ty<'tcx>)
-                             -> RelateResult<'tcx, ()> {
-    debug!("mk_assignty({:?} -> {:?})", a, b);
-    let mut unsizing_obligations = vec![];
-    let adjustment = try!(indent(|| {
-        fcx.infcx().commit_if_ok(|_| {
-            let coerce = Coerce {
-                fcx: fcx,
-                origin: TypeOrigin::ExprAssignable(expr.span),
-                unsizing_obligations: RefCell::new(vec![])
-            };
-            let adjustment = try!(coerce.coerce(expr, a, b));
-            unsizing_obligations = coerce.unsizing_obligations.into_inner();
-            Ok(adjustment)
-        })
-    }));
+                             -> CoerceResult<'tcx>
+    where E: Fn() -> I,
+          I: IntoIterator<Item=&'b hir::Expr> {
 
-    if let Some(AdjustDerefRef(auto)) = adjustment {
+    let (ty, adjustment) = try!(indent(|| coerce.coerce(exprs, a, b)));
+
+    let fcx = coerce.fcx;
+    if let AdjustDerefRef(auto) = adjustment {
         if auto.unsize.is_some() {
-            for obligation in unsizing_obligations {
+            let mut obligations = coerce.unsizing_obligations.borrow_mut();
+            for obligation in obligations.drain(..) {
                 fcx.register_predicate(obligation);
             }
         }
     }
 
-    if let Some(adjustment) = adjustment {
-        debug!("Success, coerced with {:?}", adjustment);
-        fcx.write_adjustment(expr.id, adjustment);
-    }
-    Ok(())
+    Ok((ty, adjustment))
 }
 
-fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
-                       to_mutbl: hir::Mutability)
-                       -> CoerceResult<'tcx> {
-    match (from_mutbl, to_mutbl) {
-        (hir::MutMutable, hir::MutMutable) |
-        (hir::MutImmutable, hir::MutImmutable) |
-        (hir::MutMutable, hir::MutImmutable) => Ok(None),
-        (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
+/// Attempt to coerce an expression to a type, and return the
+/// adjusted type of the expression, if successful.
+/// Adjustments are only recorded if the coercion succeeded.
+/// The expressions *must not* have any pre-existing adjustments.
+pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                     expr: &hir::Expr,
+                     target: Ty<'tcx>)
+                     -> RelateResult<'tcx, Ty<'tcx>> {
+    let source = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr));
+    debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
+
+    let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span));
+    fcx.infcx().commit_if_ok(|_| {
+        let (ty, adjustment) =
+            try!(apply(&mut coerce, &|| Some(expr), source, target));
+        if !adjustment.is_identity() {
+            debug!("Success, coerced with {:?}", adjustment);
+            assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
+            fcx.write_adjustment(expr.id, adjustment);
+        }
+        Ok(ty)
+    })
+}
+
+/// Given some expressions, their known unified type and another expression,
+/// tries to unify the types, potentially inserting coercions on any of the
+/// provided expressions and returns their LUB (aka "common supertype").
+pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
+                                        origin: TypeOrigin,
+                                        exprs: E,
+                                        prev_ty: Ty<'tcx>,
+                                        new: &'b hir::Expr)
+                                        -> RelateResult<'tcx, Ty<'tcx>>
+    // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+    where E: Fn() -> I,
+          I: IntoIterator<Item=&'b hir::Expr> {
+
+    let prev_ty = fcx.resolve_type_vars_if_possible(prev_ty);
+    let new_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(new));
+    debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
+
+    let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
+    let mut lub = fcx.infcx().lub(true, trace);
+
+    // Special-case that coercion alone cannot handle:
+    // Two function item types of differing IDs or Substs.
+    match (&prev_ty.sty, &new_ty.sty) {
+        (&ty::TyFnDef(a_def_id, a_substs, a_fty),
+         &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
+            // The signature must always match.
+            let fty = try!(lub.relate(a_fty, b_fty));
+
+            if a_def_id == b_def_id {
+                // Same function, maybe the parameters match.
+                let substs = fcx.infcx().commit_if_ok(|_| {
+                    relate_substs(&mut lub, None, a_substs, b_substs)
+                }).map(|s| fcx.tcx().mk_substs(s));
+
+                if let Ok(substs) = substs {
+                    // We have a LUB of prev_ty and new_ty, just return it.
+                    return Ok(fcx.tcx().mk_fn_def(a_def_id, substs, fty));
+                }
+            }
+
+            // Reify both sides and return the reified fn pointer type.
+            for expr in exprs().into_iter().chain(Some(new)) {
+                // No adjustments can produce a fn item, so this should never trip.
+                assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
+                fcx.write_adjustment(expr.id, AdjustReifyFnPointer);
+            }
+            return Ok(fcx.tcx().mk_fn_ptr(fty));
+        }
+        _ => {}
+    }
+
+    let mut coerce = Coerce::new(fcx, origin);
+    coerce.use_lub = true;
+
+    // First try to coerce the new expression to the type of the previous ones,
+    // but only if the new expression has no coercion already applied to it.
+    let mut first_error = None;
+    if !fcx.inh.tables.borrow().adjustments.contains_key(&new.id) {
+        let result = fcx.infcx().commit_if_ok(|_| {
+            apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
+        });
+        match result {
+            Ok((ty, adjustment)) => {
+                if !adjustment.is_identity() {
+                    fcx.write_adjustment(new.id, adjustment);
+                }
+                return Ok(ty);
+            }
+            Err(e) => first_error = Some(e)
+        }
+    }
+
+    // Then try to coerce the previous expressions to the type of the new one.
+    // This requires ensuring there are no coercions applied to *any* of the
+    // previous expressions, other than noop reborrows (ignoring lifetimes).
+    for expr in exprs() {
+        let noop = match fcx.inh.tables.borrow().adjustments.get(&expr.id) {
+            Some(&AdjustDerefRef(AutoDerefRef {
+                autoderefs: 1,
+                autoref: Some(AutoPtr(_, mutbl_adj)),
+                unsize: None
+            })) => match fcx.expr_ty(expr).sty {
+                ty::TyRef(_, mt_orig) => {
+                    // Reborrow that we can safely ignore.
+                    mutbl_adj == mt_orig.mutbl
+                }
+                _ => false
+            },
+            Some(_) => false,
+            None => true
+        };
+
+        if !noop {
+            return fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty));
+        }
+    }
+
+    match fcx.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
+        Err(_) => {
+            // Avoid giving strange errors on failed attempts.
+            if let Some(e) = first_error {
+                Err(e)
+            } else {
+                fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty))
+            }
+        }
+        Ok((ty, adjustment)) => {
+            if !adjustment.is_identity() {
+                for expr in exprs() {
+                    fcx.write_adjustment(expr.id, adjustment);
+                }
+            }
+            Ok(ty)
+        }
     }
 }
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 2bf7d65e331..ff7b809577f 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -276,9 +276,9 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>,
     // type.
 
     // Compute skolemized form of impl and trait method tys.
-    let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(impl_m.fty.clone()));
+    let impl_fty = tcx.mk_fn_ptr(impl_m.fty.clone());
     let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
-    let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(trait_m.fty.clone()));
+    let trait_fty = tcx.mk_fn_ptr(trait_m.fty.clone());
     let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
 
     let err = infcx.commit_if_ok(|snapshot| {
@@ -296,11 +296,11 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &impl_sig);
-        let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy {
+        let impl_fty = tcx.mk_fn_ptr(ty::BareFnTy {
             unsafety: impl_m.fty.unsafety,
             abi: impl_m.fty.abi,
             sig: ty::Binder(impl_sig)
-        }));
+        });
         debug!("compare_impl_method: impl_fty={:?}",
                impl_fty);
 
@@ -314,11 +314,11 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &trait_sig);
-        let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy {
+        let trait_fty = tcx.mk_fn_ptr(ty::BareFnTy {
             unsafety: trait_m.fty.unsafety,
             abi: trait_m.fty.abi,
             sig: ty::Binder(trait_sig)
-        }));
+        });
 
         debug!("compare_impl_method: trait_fty={:?}",
                trait_fty);
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 63dac49b384..1f61198bef9 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -10,45 +10,27 @@
 
 
 use check::{coercion, FnCtxt};
-use middle::ty::{self, Ty};
-use middle::infer::{self, TypeOrigin};
+use middle::ty::Ty;
+use middle::infer::TypeOrigin;
 
-use std::result::Result::{Err, Ok};
 use syntax::codemap::Span;
 use rustc_front::hir;
 
 // Requires that the two types unify, and prints an error message if
 // they don't.
 pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
-                         ty_expected: Ty<'tcx>, ty_actual: Ty<'tcx>) {
-    suptype_with_fn(fcx, sp, false, ty_expected, ty_actual,
-        |sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) })
-}
-
-/// As `suptype`, but call `handle_err` if unification for subtyping fails.
-pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
-                                    sp: Span,
-                                    b_is_expected: bool,
-                                    ty_a: Ty<'tcx>,
-                                    ty_b: Ty<'tcx>,
-                                    handle_err: F) where
-    F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::error::TypeError<'tcx>),
-{
-    // n.b.: order of actual, expected is reversed
-    match infer::mk_subty(fcx.infcx(), b_is_expected, TypeOrigin::Misc(sp),
-                          ty_b, ty_a) {
-      Ok(()) => { /* ok */ }
-      Err(ref err) => {
-          handle_err(sp, ty_a, ty_b, err);
-      }
+                         expected: Ty<'tcx>, actual: Ty<'tcx>) {
+    let origin = TypeOrigin::Misc(sp);
+    if let Err(e) = fcx.infcx().sub_types(false, origin, actual, expected) {
+        fcx.infcx().report_mismatched_types(origin, expected, actual, e);
     }
 }
 
 pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
                         expected: Ty<'tcx>, actual: Ty<'tcx>) {
-    match infer::mk_eqty(fcx.infcx(), false, TypeOrigin::Misc(sp), actual, expected) {
-        Ok(()) => { /* ok */ }
-        Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); }
+    let origin = TypeOrigin::Misc(sp);
+    if let Err(e) = fcx.infcx().eq_types(false, origin, actual, expected) {
+        fcx.infcx().report_mismatched_types(origin, expected, actual, e);
     }
 }
 
@@ -57,16 +39,10 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                         sp: Span,
                         expected: Ty<'tcx>,
                         expr: &hir::Expr) {
-    let expr_ty = fcx.expr_ty(expr);
-    debug!("demand::coerce(expected = {:?}, expr_ty = {:?})",
-           expected,
-           expr_ty);
-    let expr_ty = fcx.resolve_type_vars_if_possible(expr_ty);
     let expected = fcx.resolve_type_vars_if_possible(expected);
-    match coercion::mk_assignty(fcx, expr, expr_ty, expected) {
-      Ok(()) => { /* ok */ }
-      Err(ref err) => {
-        fcx.report_mismatched_types(sp, expected, expr_ty, err);
-      }
+    if let Err(e) = coercion::try(fcx, expr, expected) {
+        let origin = TypeOrigin::Misc(sp);
+        let expr_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr));
+        fcx.infcx().report_mismatched_types(origin, expected, expr_ty, e);
     }
 }
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 78faef473dd..4ebe4c25dd1 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -479,7 +479,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
             Ok(())
         }
 
-        ty::TyBareFn(..) => {
+        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
             // FIXME(#26656): this type is always destruction-safe, but
             // it implicitly witnesses Self: Fn, which can be false.
             Ok(())
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 6d8fff3caca..a05329bc4a4 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -13,7 +13,7 @@
 
 use astconv::AstConv;
 use intrinsics;
-use middle::subst;
+use middle::subst::{self, Substs};
 use middle::ty::FnSig;
 use middle::ty::{self, Ty, TyCtxt};
 use middle::ty::fold::TypeFolder;
@@ -33,7 +33,13 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem,
                                    abi: Abi,
                                    inputs: Vec<ty::Ty<'tcx>>,
                                    output: ty::FnOutput<'tcx>) {
-    let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy {
+    let def_id = tcx.map.local_def_id(it.id);
+    let i_ty = tcx.lookup_item_type(def_id);
+
+    let mut substs = Substs::empty();
+    substs.types = i_ty.generics.types.map(|def| tcx.mk_param_from_def(def));
+
+    let fty = tcx.mk_fn_def(def_id, tcx.mk_substs(substs), ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: abi,
         sig: ty::Binder(FnSig {
@@ -41,8 +47,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem,
             output: output,
             variadic: false,
         }),
-    }));
-    let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id));
+    });
     let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
     if i_n_tps != n_tps {
         span_err!(tcx.sess, it.span, E0094,
@@ -296,8 +301,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
                         variadic: false,
                     }),
                 };
-                let fn_ty = tcx.mk_bare_fn(fn_ty);
-                (0, vec![tcx.mk_fn(None, fn_ty), mut_u8, mut_u8], tcx.types.i32)
+                (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
             }
 
             ref other => {
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index f2f2eb66444..f4268deee37 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -98,27 +98,29 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         let InstantiatedMethodSig {
             method_sig, all_substs, method_predicates
         } = self.instantiate_method_sig(&pick, all_substs);
+        let all_substs = self.tcx().mk_substs(all_substs);
         let method_self_ty = method_sig.inputs[0];
 
         // Unify the (adjusted) self type with what the method expects.
         self.unify_receivers(self_ty, method_self_ty);
 
         // Create the method type
+        let def_id = pick.item.def_id();
         let method_ty = pick.item.as_opt_method().unwrap();
-        let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy {
+        let fty = self.tcx().mk_fn_def(def_id, all_substs, ty::BareFnTy {
             sig: ty::Binder(method_sig),
             unsafety: method_ty.fty.unsafety,
             abi: method_ty.fty.abi.clone(),
-        }));
+        });
 
         // Add any trait/regions obligations specified on the method's type parameters.
-        self.add_obligations(fty, &all_substs, &method_predicates);
+        self.add_obligations(fty, all_substs, &method_predicates);
 
         // Create the final `MethodCallee`.
         let callee = ty::MethodCallee {
-            def_id: pick.item.def_id(),
+            def_id: def_id,
             ty: fty,
-            substs: self.tcx().mk_substs(all_substs)
+            substs: all_substs
         };
         // If this is an `&mut self` method, bias the receiver
         // expression towards mutability (this will switch
@@ -156,7 +158,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         let (autoderefd_ty, n, result) = check::autoderef(self.fcx,
                                                           self.span,
                                                           unadjusted_self_ty,
-                                                          Some(self.self_expr),
+                                                          || Some(self.self_expr),
                                                           UnresolvedTypeAction::Error,
                                                           NoPreference,
                                                           |_, n| {
@@ -285,7 +287,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         let (_, _, result) = check::autoderef(self.fcx,
                                               self.span,
                                               self_ty,
-                                              None,
+                                              || None,
                                               UnresolvedTypeAction::Error,
                                               NoPreference,
                                               |ty, _| {
@@ -457,7 +459,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
     fn fixup_derefs_on_method_receiver_if_necessary(&self,
                                                     method_callee: &ty::MethodCallee) {
         let sig = match method_callee.ty.sty {
-            ty::TyBareFn(_, ref f) => f.sig.clone(),
+            ty::TyFnDef(_, _, ref f) => f.sig.clone(),
             _ => return,
         };
 
@@ -507,7 +509,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                 check::autoderef(self.fcx,
                                  expr.span,
                                  self.fcx.expr_ty(expr),
-                                 Some(expr),
+                                 || Some(expr),
                                  UnresolvedTypeAction::Error,
                                  PreferMutLvalue,
                                  |_, autoderefs| {
@@ -520,92 +522,94 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             }
 
             // Don't retry the first one or we might infinite loop!
-            if i != 0 {
-                match expr.node {
-                    hir::ExprIndex(ref base_expr, ref index_expr) => {
-                        // If this is an overloaded index, the
-                        // adjustment will include an extra layer of
-                        // autoref because the method is an &self/&mut
-                        // self method. We have to peel it off to get
-                        // the raw adjustment that `try_index_step`
-                        // expects. This is annoying and horrible. We
-                        // ought to recode this routine so it doesn't
-                        // (ab)use the normal type checking paths.
-                        let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id)
-                                                                          .cloned();
-                        let (autoderefs, unsize) = match adj {
-                            Some(AdjustDerefRef(adr)) => match adr.autoref {
-                                None => {
-                                    assert!(adr.unsize.is_none());
-                                    (adr.autoderefs, None)
-                                }
-                                Some(AutoPtr(_, _)) => {
-                                    (adr.autoderefs, adr.unsize.map(|target| {
-                                        target.builtin_deref(false, NoPreference)
-                                              .expect("fixup: AutoPtr is not &T").ty
-                                    }))
-                                }
-                                Some(_) => {
-                                    self.tcx().sess.span_bug(
-                                        base_expr.span,
-                                        &format!("unexpected adjustment autoref {:?}",
-                                                adr));
-                                }
-                            },
-                            None => (0, None),
+            if i == 0 {
+                continue;
+            }
+            match expr.node {
+                hir::ExprIndex(ref base_expr, ref index_expr) => {
+                    // If this is an overloaded index, the
+                    // adjustment will include an extra layer of
+                    // autoref because the method is an &self/&mut
+                    // self method. We have to peel it off to get
+                    // the raw adjustment that `try_index_step`
+                    // expects. This is annoying and horrible. We
+                    // ought to recode this routine so it doesn't
+                    // (ab)use the normal type checking paths.
+                    let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id)
+                                                                        .cloned();
+                    let (autoderefs, unsize) = match adj {
+                        Some(AdjustDerefRef(adr)) => match adr.autoref {
+                            None => {
+                                assert!(adr.unsize.is_none());
+                                (adr.autoderefs, None)
+                            }
+                            Some(AutoPtr(_, _)) => {
+                                (adr.autoderefs, adr.unsize.map(|target| {
+                                    target.builtin_deref(false, NoPreference)
+                                            .expect("fixup: AutoPtr is not &T").ty
+                                }))
+                            }
                             Some(_) => {
                                 self.tcx().sess.span_bug(
                                     base_expr.span,
-                                    "unexpected adjustment type");
+                                    &format!("unexpected adjustment autoref {:?}",
+                                            adr));
                             }
-                        };
-
-                        let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
-                            (target, true)
-                        } else {
-                            (self.fcx.adjust_expr_ty(base_expr,
-                                Some(&AdjustDerefRef(AutoDerefRef {
-                                    autoderefs: autoderefs,
-                                    autoref: None,
-                                    unsize: None
-                                }))), false)
-                        };
-                        let index_expr_ty = self.fcx.expr_ty(&index_expr);
-
-                        let result = check::try_index_step(
-                            self.fcx,
-                            ty::MethodCall::expr(expr.id),
-                            expr,
-                            &base_expr,
-                            adjusted_base_ty,
-                            autoderefs,
-                            unsize,
-                            PreferMutLvalue,
-                            index_expr_ty);
-
-                        if let Some((input_ty, return_ty)) = result {
-                            demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);
-
-                            let expr_ty = self.fcx.expr_ty(&expr);
-                            demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
+                        },
+                        None => (0, None),
+                        Some(_) => {
+                            self.tcx().sess.span_bug(
+                                base_expr.span,
+                                "unexpected adjustment type");
                         }
+                    };
+
+                    let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
+                        (target, true)
+                    } else {
+                        (self.fcx.adjust_expr_ty(base_expr,
+                            Some(&AdjustDerefRef(AutoDerefRef {
+                                autoderefs: autoderefs,
+                                autoref: None,
+                                unsize: None
+                            }))), false)
+                    };
+                    let index_expr_ty = self.fcx.expr_ty(&index_expr);
+
+                    let result = check::try_index_step(
+                        self.fcx,
+                        ty::MethodCall::expr(expr.id),
+                        expr,
+                        &base_expr,
+                        adjusted_base_ty,
+                        autoderefs,
+                        unsize,
+                        PreferMutLvalue,
+                        index_expr_ty);
+
+                    if let Some((input_ty, return_ty)) = result {
+                        demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);
+
+                        let expr_ty = self.fcx.expr_ty(&expr);
+                        demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
                     }
-                    hir::ExprUnary(hir::UnDeref, ref base_expr) => {
-                        // if this is an overloaded deref, then re-evaluate with
-                        // a preference for mut
-                        let method_call = ty::MethodCall::expr(expr.id);
-                        if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
-                            check::try_overloaded_deref(
-                                self.fcx,
-                                expr.span,
-                                Some(method_call),
-                                Some(&base_expr),
-                                self.fcx.expr_ty(&base_expr),
-                                PreferMutLvalue);
-                        }
+                }
+                hir::ExprUnary(hir::UnDeref, ref base_expr) => {
+                    // if this is an overloaded deref, then re-evaluate with
+                    // a preference for mut
+                    let method_call = ty::MethodCall::expr(expr.id);
+                    if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
+                        let method = check::try_overloaded_deref(
+                            self.fcx,
+                            expr.span,
+                            Some(&base_expr),
+                            self.fcx.expr_ty(&base_expr),
+                            PreferMutLvalue);
+                        let method = method.expect("re-trying deref failed");
+                        self.fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
                     }
-                    _ => {}
                 }
+                _ => {}
             }
         }
     }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index fce44683413..e74623eda6d 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -230,11 +230,12 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                                                        &method_ty.fty.sig).0;
     let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
     let transformed_self_ty = fn_sig.inputs[0];
-    let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy {
+    let def_id = method_item.def_id();
+    let fty = tcx.mk_fn_def(def_id, trait_ref.substs, ty::BareFnTy {
         sig: ty::Binder(fn_sig),
         unsafety: method_ty.fty.unsafety,
         abi: method_ty.fty.abi.clone(),
-    }));
+    });
 
     debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
            fty,
@@ -318,7 +319,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 
     let callee = ty::MethodCallee {
-        def_id: method_item.def_id(),
+        def_id: def_id,
         ty: fty,
         substs: trait_ref.substs
     };
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 02f8584c55d..d11a07cb41f 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -200,7 +200,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     let (final_ty, dereferences, _) = check::autoderef(fcx,
                                                        span,
                                                        self_ty,
-                                                       None,
+                                                       || None,
                                                        UnresolvedTypeAction::Error,
                                                        NoPreference,
                                                        |t, d| {
@@ -697,11 +697,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         // Check if this is one of the Fn,FnMut,FnOnce traits.
         let tcx = self.tcx();
         let kind = if Some(trait_def_id) == tcx.lang_items.fn_trait() {
-            ty::FnClosureKind
+            ty::ClosureKind::Fn
         } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
-            ty::FnMutClosureKind
+            ty::ClosureKind::FnMut
         } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
-            ty::FnOnceClosureKind
+            ty::ClosureKind::FnOnce
         } else {
             return Ok(());
         };
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index e7d84efdaa2..7dc9d46c303 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -101,7 +101,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     match field_ty.sty {
                         // Not all of these (e.g. unsafe fns) implement FnOnce
                         // so we look for these beforehand
-                        ty::TyClosure(..) | ty::TyBareFn(..) => {
+                        ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => {
                             span_stored_function!();
                         }
                         // If it's not a simple function, look for things which implement FnOnce
@@ -351,7 +351,7 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty));
     }
 
-    check::autoderef(fcx, span, rcvr_ty, None,
+    check::autoderef(fcx, span, rcvr_ty, || None,
                      check::UnresolvedTypeAction::Ignore, ty::NoPreference,
                      |ty, _| {
         if is_local(ty) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9be46cf4053..0743c0b9e18 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -89,7 +89,7 @@ use middle::cstore::LOCAL_CRATE;
 use middle::def::{self, Def};
 use middle::def_id::DefId;
 use middle::infer;
-use middle::infer::{TypeOrigin, type_variable};
+use middle::infer::{TypeOrigin, TypeTrace, type_variable};
 use middle::pat_util::{self, pat_id_map};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
 use middle::traits::{self, report_fulfillment_errors};
@@ -101,6 +101,7 @@ use middle::ty::{MethodCall, MethodCallee};
 use middle::ty::adjustment;
 use middle::ty::error::TypeError;
 use middle::ty::fold::{TypeFolder, TypeFoldable};
+use middle::ty::relate::TypeRelation;
 use middle::ty::util::Representability;
 use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
@@ -434,7 +435,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            param_env: ty::ParameterEnvironment<'a, 'tcx>)
 {
     match raw_fty.sty {
-        ty::TyBareFn(_, ref fn_ty) => {
+        ty::TyFnDef(_, _, ref fn_ty) => {
             let tables = RefCell::new(ty::Tables::empty());
             let inh = Inherited::new(ccx.tcx, &tables, param_env);
 
@@ -1622,14 +1623,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.infcx().type_error_struct(sp, mk_msg, actual_ty, err)
     }
 
-    pub fn report_mismatched_types(&self,
-                                   sp: Span,
-                                   e: Ty<'tcx>,
-                                   a: Ty<'tcx>,
-                                   err: &TypeError<'tcx>) {
-        self.infcx().report_mismatched_types(sp, e, a, err)
-    }
-
     /// Registers an obligation for checking later, during regionck, that the type `ty` must
     /// outlive the region `r`.
     pub fn register_region_obligation(&self,
@@ -1709,6 +1702,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     // FIXME(arielb1): use this instead of field.ty everywhere
+    // Only for fields! Returns <none> for methods>
+    // Indifferent to privacy flags
     pub fn field_ty(&self,
                     span: Span,
                     field: ty::FieldDef<'tcx>,
@@ -1719,8 +1714,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                            &field.ty(self.tcx(), substs))
     }
 
-    // Only for fields! Returns <none> for methods>
-    // Indifferent to privacy flags
     fn check_casts(&self) {
         let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
         for cast in deferred_cast_checks.drain(..) {
@@ -2061,20 +2054,21 @@ pub enum UnresolvedTypeAction {
 ///
 /// Note: this method does not modify the adjustments table. The caller is responsible for
 /// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods.
-pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
-                                 sp: Span,
-                                 base_ty: Ty<'tcx>,
-                                 opt_expr: Option<&hir::Expr>,
-                                 unresolved_type_action: UnresolvedTypeAction,
-                                 mut lvalue_pref: LvaluePreference,
-                                 mut should_stop: F)
-                                 -> (Ty<'tcx>, usize, Option<T>)
-    where F: FnMut(Ty<'tcx>, usize) -> Option<T>,
+pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>,
+                                           sp: Span,
+                                           base_ty: Ty<'tcx>,
+                                           maybe_exprs: E,
+                                           unresolved_type_action: UnresolvedTypeAction,
+                                           mut lvalue_pref: LvaluePreference,
+                                           mut should_stop: F)
+                                           -> (Ty<'tcx>, usize, Option<T>)
+    // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+    where E: Fn() -> I,
+          I: IntoIterator<Item=&'b hir::Expr>,
+          F: FnMut(Ty<'tcx>, usize) -> Option<T>,
 {
-    debug!("autoderef(base_ty={:?}, opt_expr={:?}, lvalue_pref={:?})",
-           base_ty,
-           opt_expr,
-           lvalue_pref);
+    debug!("autoderef(base_ty={:?}, lvalue_pref={:?})",
+           base_ty, lvalue_pref);
 
     let mut t = base_ty;
     for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
@@ -2087,7 +2081,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
                 // (i.e. it is an inference variable) because `Ty::builtin_deref`
                 // and `try_overloaded_deref` both simply return `None`
                 // in such a case without producing spurious errors.
-                fcx.resolve_type_vars_if_possible(t)
+                fcx.infcx().resolve_type_vars_if_possible(&t)
             }
         };
         if resolved_t.references_error() {
@@ -2100,34 +2094,34 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
         }
 
         // Otherwise, deref if type is derefable:
-        let mt = match resolved_t.builtin_deref(false, lvalue_pref) {
-            Some(mt) => Some(mt),
-            None => {
-                let method_call =
-                    opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32));
-
-                // Super subtle: it might seem as though we should
-                // pass `opt_expr` to `try_overloaded_deref`, so that
-                // the (implicit) autoref of using an overloaded deref
-                // would get added to the adjustment table. However we
-                // do not do that, because it's kind of a
-                // "meta-adjustment" -- instead, we just leave it
-                // unrecorded and know that there "will be" an
-                // autoref. regionck and other bits of the code base,
-                // when they encounter an overloaded autoderef, have
-                // to do some reconstructive surgery. This is a pretty
-                // complex mess that is begging for a proper MIR.
-                try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
+
+        // Super subtle: it might seem as though we should
+        // pass `opt_expr` to `try_overloaded_deref`, so that
+        // the (implicit) autoref of using an overloaded deref
+        // would get added to the adjustment table. However we
+        // do not do that, because it's kind of a
+        // "meta-adjustment" -- instead, we just leave it
+        // unrecorded and know that there "will be" an
+        // autoref. regionck and other bits of the code base,
+        // when they encounter an overloaded autoderef, have
+        // to do some reconstructive surgery. This is a pretty
+        // complex mess that is begging for a proper MIR.
+        let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) {
+            mt
+        } else if let Some(method) = try_overloaded_deref(fcx, sp, None,
+                                                          resolved_t, lvalue_pref) {
+            for expr in maybe_exprs() {
+                let method_call = MethodCall::autoderef(expr.id, autoderefs as u32);
+                fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
             }
+            make_overloaded_lvalue_return_type(fcx.tcx(), method)
+        } else {
+            return (resolved_t, autoderefs, None);
         };
-        match mt {
-            Some(mt) => {
-                t = mt.ty;
-                if mt.mutbl == hir::MutImmutable {
-                    lvalue_pref = NoPreference;
-                }
-            }
-            None => return (resolved_t, autoderefs, None)
+
+        t = mt.ty;
+        if mt.mutbl == hir::MutImmutable {
+            lvalue_pref = NoPreference;
         }
     }
 
@@ -2140,11 +2134,10 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
 
 fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                   span: Span,
-                                  method_call: Option<MethodCall>,
                                   base_expr: Option<&hir::Expr>,
                                   base_ty: Ty<'tcx>,
                                   lvalue_pref: LvaluePreference)
-                                  -> Option<ty::TypeAndMut<'tcx>>
+                                  -> Option<MethodCallee<'tcx>>
 {
     // Try DerefMut first, if preferred.
     let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
@@ -2166,33 +2159,23 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         (method, _) => method
     };
 
-    make_overloaded_lvalue_return_type(fcx, method_call, method)
+    method
 }
 
 /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the
 /// actual type we assign to the *expression* is `T`. So this function just peels off the return
-/// type by one layer to yield `T`. It also inserts the `method-callee` into the method map.
-fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                                method_call: Option<MethodCall>,
-                                                method: Option<MethodCallee<'tcx>>)
-                                                -> Option<ty::TypeAndMut<'tcx>>
+/// type by one layer to yield `T`.
+fn make_overloaded_lvalue_return_type<'tcx>(tcx: &TyCtxt<'tcx>,
+                                            method: MethodCallee<'tcx>)
+                                            -> ty::TypeAndMut<'tcx>
 {
-    match method {
-        Some(method) => {
-            // extract method return type, which will be &T;
-            // all LB regions should have been instantiated during method lookup
-            let ret_ty = method.ty.fn_ret();
-            let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap();
-
-            if let Some(method_call) = method_call {
-                fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
-            }
+    // extract method return type, which will be &T;
+    // all LB regions should have been instantiated during method lookup
+    let ret_ty = method.ty.fn_ret();
+    let ret_ty = tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
 
-            // method returns &T, but the type as visible to user is T, so deref
-            ret_ty.builtin_deref(true, NoPreference)
-        }
-        None => None,
-    }
+    // method returns &T, but the type as visible to user is T, so deref
+    ret_ty.builtin_deref(true, NoPreference).unwrap()
 }
 
 fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
@@ -2210,7 +2193,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     let (ty, autoderefs, final_mt) = autoderef(fcx,
                                                base_expr.span,
                                                base_ty,
-                                               Some(base_expr),
+                                               || Some(base_expr),
                                                UnresolvedTypeAction::Error,
                                                lvalue_pref,
                                                |adj_ty, idx| {
@@ -2307,10 +2290,10 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // If some lookup succeeds, write callee into table and extract index/element
     // type from the method signature.
     // If some lookup succeeded, install method in table
-    method.and_then(|method| {
+    method.map(|method| {
         debug!("try_index_step: success, using overloaded indexing");
-        make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method)).
-            map(|ret| (input_ty, ret.ty))
+        fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
+        (input_ty, make_overloaded_lvalue_return_type(fcx.tcx(), method).ty)
     })
 }
 
@@ -2340,7 +2323,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         ty::FnConverging(fcx.tcx().types.err)
     } else {
         match method_fn_ty.sty {
-            ty::TyBareFn(_, ref fty) => {
+            ty::TyFnDef(_, _, ref fty) => {
                 // HACK(eddyb) ignore self in the definition (see above).
                 let expected_arg_tys = expected_types_for_fn_args(fcx,
                                                                   sp,
@@ -2509,20 +2492,17 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     Expectation::rvalue_hint(fcx.tcx(), ty)
                 });
 
-                check_expr_with_unifier(fcx,
-                                        &arg,
-                                        expected.unwrap_or(ExpectHasType(formal_ty)),
-                                        NoPreference, || {
-                    // 2. Coerce to the most detailed type that could be coerced
-                    //    to, which is `expected_ty` if `rvalue_hint` returns an
-                    //    `ExprHasType(expected_ty)`, or the `formal_ty` otherwise.
-                    let coerce_ty = expected.and_then(|e| e.only_has_type(fcx));
-                    demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg);
-
-                    // 3. Relate the expected type and the formal one,
-                    //    if the expected type was used for the coercion.
-                    coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty));
-                });
+                check_expr_with_expectation(fcx, &arg,
+                    expected.unwrap_or(ExpectHasType(formal_ty)));
+                // 2. Coerce to the most detailed type that could be coerced
+                //    to, which is `expected_ty` if `rvalue_hint` returns an
+                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+                let coerce_ty = expected.and_then(|e| e.only_has_type(fcx));
+                demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg);
+
+                // 3. Relate the expected type and the formal one,
+                //    if the expected type was used for the coercion.
+                coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty));
             }
 
             if let Some(&arg_ty) = fcx.inh.tables.borrow().node_types.get(&arg.id) {
@@ -2619,7 +2599,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     ty::TyInt(_) | ty::TyUint(_) => Some(ty),
                     ty::TyChar => Some(tcx.types.u8),
                     ty::TyRawPtr(..) => Some(tcx.types.usize),
-                    ty::TyBareFn(..) => Some(tcx.types.usize),
+                    ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize),
                     _ => None
                 }
             });
@@ -2644,57 +2624,42 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                 expr: &'tcx hir::Expr,
                                 expected: Ty<'tcx>) {
-    check_expr_with_unifier(
-        fcx, expr, ExpectHasType(expected), NoPreference,
-        || demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr)));
+    check_expr_with_hint(fcx, expr, expected);
+    demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr));
 }
 
 pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                      expr: &'tcx hir::Expr,
                                      expected: Ty<'tcx>) {
-    check_expr_with_unifier(
-        fcx, expr, ExpectHasType(expected), NoPreference,
-        || demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr)));
+    check_expr_with_hint(fcx, expr, expected);
+    demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
 }
 
 fn check_expr_coercable_to_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                           expr: &'tcx hir::Expr,
                                           expected: Ty<'tcx>) {
-    check_expr_with_unifier(
-        fcx, expr, ExpectHasType(expected), NoPreference,
-        || demand::coerce(fcx, expr.span, expected, expr));
+    check_expr_with_hint(fcx, expr, expected);
+    demand::coerce(fcx, expr.span, expected, expr);
 }
 
 fn check_expr_with_hint<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr,
                                   expected: Ty<'tcx>) {
-    check_expr_with_unifier(
-        fcx, expr, ExpectHasType(expected), NoPreference,
-        || ())
+    check_expr_with_expectation(fcx, expr, ExpectHasType(expected))
 }
 
 fn check_expr_with_expectation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                          expr: &'tcx hir::Expr,
                                          expected: Expectation<'tcx>) {
-    check_expr_with_unifier(
-        fcx, expr, expected, NoPreference,
-        || ())
-}
-
-fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                                         expr: &'tcx hir::Expr,
-                                                         expected: Expectation<'tcx>,
-                                                         lvalue_pref: LvaluePreference)
-{
-    check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
+    check_expr_with_expectation_and_lvalue_pref(fcx, expr, expected, NoPreference)
 }
 
 fn check_expr<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr)  {
-    check_expr_with_unifier(fcx, expr, NoExpectation, NoPreference, || ())
+    check_expr_with_expectation(fcx, expr, NoExpectation)
 }
 
 fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr,
                                         lvalue_pref: LvaluePreference)  {
-    check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ())
+    check_expr_with_expectation_and_lvalue_pref(fcx, expr, NoExpectation, lvalue_pref)
 }
 
 // determine the `self` type, using fresh variables for all variables
@@ -2796,13 +2761,10 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 /// Note that inspecting a type's structure *directly* may expose the fact
 /// that there are actually multiple representations for `TyError`, so avoid
 /// that when err needs to be handled differently.
-fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
-                                        expr: &'tcx hir::Expr,
-                                        expected: Expectation<'tcx>,
-                                        lvalue_pref: LvaluePreference,
-                                        unifier: F) where
-    F: FnOnce(),
-{
+fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                                         expr: &'tcx hir::Expr,
+                                                         expected: Expectation<'tcx>,
+                                                         lvalue_pref: LvaluePreference) {
     debug!(">> typechecking: expr={:?} expected={:?}",
            expr, expected);
 
@@ -2873,30 +2835,52 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         check_block_with_expected(fcx, then_blk, expected);
         let then_ty = fcx.node_ty(then_blk.id);
 
-        let branches_ty = match opt_else_expr {
-            Some(ref else_expr) => {
-                check_expr_with_expectation(fcx, &else_expr, expected);
-                let else_ty = fcx.expr_ty(&else_expr);
-                infer::common_supertype(fcx.infcx(),
-                                        TypeOrigin::IfExpression(sp),
-                                        true,
-                                        then_ty,
-                                        else_ty)
-            }
-            None => {
-                infer::common_supertype(fcx.infcx(),
-                                        TypeOrigin::IfExpressionWithNoElse(sp),
-                                        false,
-                                        then_ty,
-                                        fcx.tcx().mk_nil())
-            }
-        };
+        let unit = fcx.tcx().mk_nil();
+        let (origin, expected, found, result) =
+        if let Some(else_expr) = opt_else_expr {
+            check_expr_with_expectation(fcx, else_expr, expected);
+            let else_ty = fcx.expr_ty(else_expr);
+            let origin = TypeOrigin::IfExpression(sp);
+
+            // Only try to coerce-unify if we have a then expression
+            // to assign coercions to, otherwise it's () or diverging.
+            let result = if let Some(ref then) = then_blk.expr {
+                let res = coercion::try_find_lub(fcx, origin, || Some(&**then),
+                                                 then_ty, else_expr);
+
+                // In case we did perform an adjustment, we have to update
+                // the type of the block, because old trans still uses it.
+                let adj = fcx.inh.tables.borrow().adjustments.get(&then.id).cloned();
+                if res.is_ok() && adj.is_some() {
+                    fcx.write_ty(then_blk.id, fcx.adjust_expr_ty(then, adj.as_ref()));
+                }
 
-        let cond_ty = fcx.expr_ty(cond_expr);
-        let if_ty = if cond_ty.references_error() {
-            fcx.tcx().types.err
+                res
+            } else {
+                fcx.infcx().commit_if_ok(|_| {
+                    let trace = TypeTrace::types(origin, true, then_ty, else_ty);
+                    fcx.infcx().lub(true, trace).relate(&then_ty, &else_ty)
+                })
+            };
+            (origin, then_ty, else_ty, result)
         } else {
-            branches_ty
+            let origin = TypeOrigin::IfExpressionWithNoElse(sp);
+            (origin, unit, then_ty,
+             fcx.infcx().eq_types(true, origin, unit, then_ty).map(|_| unit))
+        };
+
+        let if_ty = match result {
+            Ok(ty) => {
+                if fcx.expr_ty(cond_expr).references_error() {
+                    fcx.tcx().types.err
+                } else {
+                    ty
+                }
+            }
+            Err(e) => {
+                fcx.infcx().report_mismatched_types(origin, expected, found, e);
+                fcx.tcx().types.err
+            }
         };
 
         fcx.write_ty(id, if_ty);
@@ -2915,7 +2899,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         let (_, autoderefs, field_ty) = autoderef(fcx,
                                                   expr.span,
                                                   expr_t,
-                                                  Some(base),
+                                                  || Some(base),
                                                   UnresolvedTypeAction::Error,
                                                   lvalue_pref,
                                                   |base_t, _| {
@@ -3013,7 +2997,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         let (_, autoderefs, field_ty) = autoderef(fcx,
                                                   expr.span,
                                                   expr_t,
-                                                  Some(base),
+                                                  || Some(base),
                                                   UnresolvedTypeAction::Error,
                                                   lvalue_pref,
                                                   |base_t, _| {
@@ -3261,21 +3245,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
             match unop {
                 hir::UnDeref => {
                     oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
-                    oprnd_t = match oprnd_t.builtin_deref(true, NoPreference) {
-                        Some(mt) => mt.ty,
-                        None => match try_overloaded_deref(fcx, expr.span,
-                                                           Some(MethodCall::expr(expr.id)),
-                                                           Some(&oprnd), oprnd_t, lvalue_pref) {
-                            Some(mt) => mt.ty,
-                            None => {
-                                fcx.type_error_message(expr.span, |actual| {
-                                    format!("type `{}` cannot be \
-                                            dereferenced", actual)
-                                }, oprnd_t, None);
-                                tcx.types.err
-                            }
-                        }
-                    };
+
+                    if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
+                        oprnd_t = mt.ty;
+                    } else if let Some(method) = try_overloaded_deref(
+                            fcx, expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
+                        oprnd_t = make_overloaded_lvalue_return_type(tcx, method).ty;
+                        fcx.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
+                                                                      method);
+                    } else {
+                        fcx.type_error_message(expr.span, |actual| {
+                            format!("type `{}` cannot be \
+                                    dereferenced", actual)
+                        }, oprnd_t, None);
+                        oprnd_t = tcx.types.err;
+                    }
                 }
                 hir::UnNot => {
                     oprnd_t = structurally_resolved_type(fcx, oprnd.span,
@@ -3519,7 +3503,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
 
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
-            let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span);
+            let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span);
             deferred_cast_checks.push(cast_check);
         }
       }
@@ -3536,23 +3520,30 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
             }
         });
 
-        let typ = match uty {
-            Some(uty) => {
-                for e in args {
-                    check_expr_coercable_to_type(fcx, &e, uty);
-                }
-                uty
-            }
-            None => {
-                let t: Ty = fcx.infcx().next_ty_var();
-                for e in args {
-                    check_expr_has_type(fcx, &e, t);
+        let mut unified = fcx.infcx().next_ty_var();
+        let coerce_to = uty.unwrap_or(unified);
+
+        for (i, e) in args.iter().enumerate() {
+            check_expr_with_hint(fcx, e, coerce_to);
+            let e_ty = fcx.expr_ty(e);
+            let origin = TypeOrigin::Misc(e.span);
+
+            // Special-case the first element, as it has no "previous expressions".
+            let result = if i == 0 {
+                coercion::try(fcx, e, coerce_to)
+            } else {
+                let prev_elems = || args[..i].iter().map(|e| &**e);
+                coercion::try_find_lub(fcx, origin, prev_elems, unified, e)
+            };
+
+            match result {
+                Ok(ty) => unified = ty,
+                Err(e) => {
+                    fcx.infcx().report_mismatched_types(origin, unified, e_ty, e);
                 }
-                t
             }
-        };
-        let typ = tcx.mk_array(typ, args.len());
-        fcx.write_ty(id, typ);
+        }
+        fcx.write_ty(id, tcx.mk_array(unified, args.len()));
       }
       hir::ExprRepeat(ref element, ref count_expr) => {
         check_expr_has_type(fcx, &count_expr, tcx.types.usize);
@@ -3673,87 +3664,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
               }
           }
        }
-       hir::ExprRange(ref start, ref end) => {
-          let t_start = start.as_ref().map(|e| {
-            check_expr(fcx, &e);
-            fcx.expr_ty(&e)
-          });
-          let t_end = end.as_ref().map(|e| {
-            check_expr(fcx, &e);
-            fcx.expr_ty(&e)
-          });
-
-          let idx_type = match (t_start, t_end) {
-              (Some(ty), None) | (None, Some(ty)) => {
-                  Some(ty)
-              }
-              (Some(t_start), Some(t_end)) if (t_start.references_error() ||
-                                               t_end.references_error()) => {
-                  Some(fcx.tcx().types.err)
-              }
-              (Some(t_start), Some(t_end)) => {
-                  Some(infer::common_supertype(fcx.infcx(),
-                                               TypeOrigin::RangeExpression(expr.span),
-                                               true,
-                                               t_start,
-                                               t_end))
-              }
-              _ => None
-          };
-
-          // Note that we don't check the type of start/end satisfy any
-          // bounds because right now the range structs do not have any. If we add
-          // some bounds, then we'll need to check `t_start` against them here.
-
-          let range_type = match idx_type {
-            Some(idx_type) if idx_type.references_error() => {
-                fcx.tcx().types.err
-            }
-            Some(idx_type) => {
-                // Find the did from the appropriate lang item.
-                let did = match (start, end) {
-                    (&Some(_), &Some(_)) => tcx.lang_items.range_struct(),
-                    (&Some(_), &None) => tcx.lang_items.range_from_struct(),
-                    (&None, &Some(_)) => tcx.lang_items.range_to_struct(),
-                    (&None, &None) => {
-                        tcx.sess.span_bug(expr.span, "full range should be dealt with above")
-                    }
-                };
-
-                if let Some(did) = did {
-                    let def = tcx.lookup_adt_def(did);
-                    let predicates = tcx.lookup_predicates(did);
-                    let substs = Substs::new_type(vec![idx_type], vec![]);
-                    let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates);
-                    fcx.add_obligations_for_parameters(
-                        traits::ObligationCause::new(expr.span,
-                                                     fcx.body_id,
-                                                     traits::ItemObligation(did)),
-                        &bounds);
-
-                    tcx.mk_struct(def, tcx.mk_substs(substs))
-                } else {
-                    span_err!(tcx.sess, expr.span, E0236, "no lang item for range syntax");
-                    fcx.tcx().types.err
-                }
-            }
-            None => {
-                // Neither start nor end => RangeFull
-                if let Some(did) = tcx.lang_items.range_full_struct() {
-                    tcx.mk_struct(
-                        tcx.lookup_adt_def(did),
-                        tcx.mk_substs(Substs::empty())
-                    )
-                } else {
-                    span_err!(tcx.sess, expr.span, E0237, "no lang item for range syntax");
-                    fcx.tcx().types.err
-                }
-            }
-          };
-
-          fcx.write_ty(id, range_type);
-       }
-
     }
 
     debug!("type of expr({}) {} is...", expr.id,
@@ -3761,8 +3671,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
     debug!("... {:?}, expected is {:?}",
            fcx.expr_ty(expr),
            expected);
-
-    unifier();
 }
 
 pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index f6225cf6ca7..e428fc927f0 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -881,7 +881,7 @@ fn constrain_callee(rcx: &mut Rcx,
                     _callee_expr: &hir::Expr) {
     let callee_ty = rcx.resolve_node_type(callee_id);
     match callee_ty.sty {
-        ty::TyBareFn(..) => { }
+        ty::TyFnDef(..) | ty::TyFnPtr(_) => { }
         _ => {
             // this should not happen, but it does if the program is
             // erroneous
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index fca2c8193a7..2bb8c874d20 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -131,7 +131,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
         if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
             self.closures_with_inferred_kinds.insert(expr.id);
             self.fcx.inh.tables.borrow_mut().closure_kinds
-                                            .insert(closure_def_id, ty::FnClosureKind);
+                                            .insert(closure_def_id, ty::ClosureKind::Fn);
             debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds",
                    closure_def_id);
         }
@@ -301,7 +301,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                                upvar_id);
 
                         // to move out of an upvar, this must be a FnOnce closure
-                        self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
+                        self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce);
 
                         let upvar_capture_map =
                             &mut self.fcx.inh.tables.borrow_mut().upvar_capture_map;
@@ -314,7 +314,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                         // must still adjust the kind of the closure
                         // to be a FnOnce closure to permit moves out
                         // of the environment.
-                        self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
+                        self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce);
                     }
                     mc::NoteNone => {
                     }
@@ -418,7 +418,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                 }
 
                 // also need to be in an FnMut closure since this is not an ImmBorrow
-                self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind);
+                self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut);
 
                 true
             }
@@ -426,7 +426,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                 // this kind of deref occurs in a `move` closure, or
                 // for a by-value upvar; in either case, to mutate an
                 // upvar, we need to be an FnMut closure
-                self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind);
+                self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut);
 
                 true
             }
@@ -488,16 +488,16 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                closure_id, existing_kind, new_kind);
 
         match (existing_kind, new_kind) {
-            (ty::FnClosureKind, ty::FnClosureKind) |
-            (ty::FnMutClosureKind, ty::FnClosureKind) |
-            (ty::FnMutClosureKind, ty::FnMutClosureKind) |
-            (ty::FnOnceClosureKind, _) => {
+            (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
+            (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) |
+            (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
+            (ty::ClosureKind::FnOnce, _) => {
                 // no change needed
             }
 
-            (ty::FnClosureKind, ty::FnMutClosureKind) |
-            (ty::FnClosureKind, ty::FnOnceClosureKind) |
-            (ty::FnMutClosureKind, ty::FnOnceClosureKind) => {
+            (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) |
+            (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
+            (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
                 // new kind is stronger than the old kind
                 closure_kinds.insert(closure_def_id, new_kind);
             }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 997f56bd449..a8ada806131 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -255,9 +255,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
             let bare_fn_ty = match item_ty.sty {
-                ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty,
+                ty::TyFnDef(_, _, ref bare_fn_ty) => bare_fn_ty,
                 _ => {
-                    this.tcx().sess.span_bug(item.span, "Fn item without bare fn type");
+                    this.tcx().sess.span_bug(item.span, "Fn item without fn type");
                 }
             };
 
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 61060114330..cad321c0b23 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -27,7 +27,7 @@ use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
 use middle::ty::{TyParam, TyRawPtr};
 use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple};
 use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
-use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn};
+use middle::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
 use middle::ty::TyProjection;
 use middle::ty::util::CopyImplementationError;
 use middle::free_region::FreeRegionMap;
@@ -67,8 +67,8 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
         }
 
         TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
-        TyStr | TyArray(..) | TySlice(..) | TyBareFn(..) | TyTuple(..) |
-        TyParam(..) | TyError |
+        TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
+        TyTuple(..) | TyParam(..) | TyError |
         TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
             None
         }
@@ -385,11 +385,12 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
 
             let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
 
+            let origin = TypeOrigin::Misc(span);
             let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,
                                mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
                 if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
-                    infcx.report_mismatched_types(span, mk_ptr(mt_b.ty),
-                                                  target, &ty::error::TypeError::Mutability);
+                    infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty),
+                                                  target, ty::error::TypeError::Mutability);
                 }
                 (mt_a.ty, mt_b.ty, unsize_trait, None)
             };
@@ -418,7 +419,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                         return;
                     }
 
-                    let origin = TypeOrigin::Misc(span);
                     let fields = &def_a.struct_variant().fields;
                     let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
                         let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index b3305fdb9a0..3ce03e24578 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -543,6 +543,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                               sig, untransformed_rcvr_ty);
 
     let def_id = ccx.tcx.map.local_def_id(id);
+    let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
+
     let ty_method = ty::Method::new(name,
                                     ty_generics,
                                     ty_generic_predicates,
@@ -552,8 +554,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                     def_id,
                                     container);
 
-    let fty = ccx.tcx.mk_fn(Some(def_id),
-                            ccx.tcx.mk_bare_fn(ty_method.fty.clone()));
+    let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty.clone());
     debug!("method {} (id {}) has type {:?}",
             name, id, fty);
     ccx.tcx.register_item_type(def_id, TypeScheme {
@@ -715,17 +716,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             tcx.register_item_type(def_id,
                                    TypeScheme { generics: ty_generics.clone(),
                                                 ty: selfty });
-            if let &Some(ref ast_trait_ref) = opt_trait_ref {
-                tcx.impl_trait_refs.borrow_mut().insert(
-                    def_id,
-                    Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
-                                                             &ExplicitRscope,
-                                                             ast_trait_ref,
-                                                             Some(selfty)))
-                        );
-            } else {
-                tcx.impl_trait_refs.borrow_mut().insert(def_id, None);
-            }
+            let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
+                astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
+                                                    &ExplicitRscope,
+                                                    ast_trait_ref,
+                                                    Some(selfty))
+            });
+            tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref);
 
             enforce_impl_params_are_constrained(tcx, generics, &mut ty_predicates, def_id);
             tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
@@ -902,7 +899,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             }
 
             if !struct_def.is_struct() {
-                convert_variant_ctor(tcx, struct_def.id(), variant, scheme, predicates);
+                convert_variant_ctor(ccx, struct_def.id(), variant, scheme, predicates);
             }
         },
         hir::ItemTy(_, ref generics) => {
@@ -920,11 +917,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
     }
 }
 
-fn convert_variant_ctor<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
+fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                   ctor_id: ast::NodeId,
                                   variant: ty::VariantDef<'tcx>,
                                   scheme: ty::TypeScheme<'tcx>,
                                   predicates: ty::GenericPredicates<'tcx>) {
+    let tcx = ccx.tcx;
     let ctor_ty = match variant.kind() {
         VariantKind::Unit | VariantKind::Struct => scheme.ty,
         VariantKind::Tuple => {
@@ -933,9 +931,17 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
                 .iter()
                 .map(|field| field.unsubst_ty())
                 .collect();
-            tcx.mk_ctor_fn(tcx.map.local_def_id(ctor_id),
-                           &inputs[..],
-                           scheme.ty)
+            let def_id = tcx.map.local_def_id(ctor_id);
+            let substs = tcx.mk_substs(mk_item_substs(ccx, &scheme.generics));
+            tcx.mk_fn_def(def_id, substs, ty::BareFnTy {
+                unsafety: hir::Unsafety::Normal,
+                abi: abi::Abi::Rust,
+                sig: ty::Binder(ty::FnSig {
+                    inputs: inputs,
+                    output: ty::FnConverging(scheme.ty),
+                    variadic: false
+                })
+            })
         }
     };
     write_ty_to_tcx(tcx, ctor_id, ctor_ty);
@@ -961,7 +967,7 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // Convert the ctor, if any. This also registers the variant as
         // an item.
         convert_variant_ctor(
-            ccx.tcx,
+            ccx,
             variant.node.data.id(),
             ty_variant,
             scheme.clone(),
@@ -1436,7 +1442,9 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
             let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
             let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl);
-            let ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(it.id)), tcx.mk_bare_fn(tofd));
+            let def_id = ccx.tcx.map.local_def_id(it.id);
+            let substs = tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
+            let ty = tcx.mk_fn_def(def_id, substs, tofd);
             ty::TypeScheme { ty: ty, generics: ty_generics }
         }
         hir::ItemTy(ref t, ref generics) => {
@@ -1556,7 +1564,9 @@ fn compute_type_scheme_of_foreign_item<'a, 'tcx>(
 {
     match it.node {
         hir::ForeignItemFn(ref fn_decl, ref generics) => {
-            compute_type_scheme_of_foreign_fn_decl(ccx, fn_decl, generics, abi)
+            compute_type_scheme_of_foreign_fn_decl(
+                ccx, ccx.tcx.map.local_def_id(it.id),
+                fn_decl, generics, abi)
         }
         hir::ForeignItemStatic(ref t, _) => {
             ty::TypeScheme {
@@ -2107,6 +2117,7 @@ fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>,
 
 fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
     ccx: &CrateCtxt<'a, 'tcx>,
+    id: DefId,
     decl: &hir::FnDecl,
     ast_generics: &hir::Generics,
     abi: abi::Abi)
@@ -2140,14 +2151,14 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
             ty::FnDiverging
     };
 
-    let t_fn = ccx.tcx.mk_fn(None,
-        ccx.tcx.mk_bare_fn(ty::BareFnTy {
-            abi: abi,
-            unsafety: hir::Unsafety::Unsafe,
-            sig: ty::Binder(ty::FnSig {inputs: input_tys,
-                                       output: output,
-                                       variadic: decl.variadic}),
-        }));
+    let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
+    let t_fn = ccx.tcx.mk_fn_def(id, substs, ty::BareFnTy {
+        abi: abi,
+        unsafety: hir::Unsafety::Unsafe,
+        sig: ty::Binder(ty::FnSig {inputs: input_tys,
+                                    output: output,
+                                    variadic: decl.variadic}),
+    });
 
     ty::TypeScheme {
         generics: ty_generics,
diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs
index 336bff26e2c..907ee15c41b 100644
--- a/src/librustc_typeck/constrained_type_params.rs
+++ b/src/librustc_typeck/constrained_type_params.rs
@@ -72,7 +72,8 @@ fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
             parameters_for_regions_in_substs(&pi.trait_ref.substs),
         ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
         ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr |
-        ty::TyArray(..) | ty::TySlice(..) | ty::TyBareFn(..) |
+        ty::TyArray(..) | ty::TySlice(..) |
+        ty::TyFnDef(..) | ty::TyFnPtr(_) |
         ty::TyTuple(..) | ty::TyRawPtr(..) |
         ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError =>
             vec![]
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 0ff6dcccde6..cfe76206b02 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1133,15 +1133,16 @@ enum Bad {
 }
 ```
 
-Here `X` will have already been assigned the discriminant 0 by the time `Y` is
+Here `X` will have already been specified the discriminant 0 by the time `Y` is
 encountered, so a conflict occurs.
 "##,
 
 E0082: r##"
-The default type for enum discriminants is `isize`, but it can be adjusted by
-adding the `repr` attribute to the enum declaration. This error indicates that
-an integer literal given as a discriminant is not a member of the discriminant
-type. For example:
+When you specify enum discriminants with `=`, the compiler expects `isize`
+values by default. Or you can add the `repr` attibute to the enum declaration
+for an explicit choice of the discriminant type. In either cases, the
+discriminant values must fall within a valid range for the expected type;
+otherwise this error is raised. For example:
 
 ```compile_fail
 #[repr(u8)]
@@ -1152,11 +1153,19 @@ enum Thing {
 ```
 
 Here, 1024 lies outside the valid range for `u8`, so the discriminant for `A` is
-invalid. You may want to change representation types to fix this, or else change
-invalid discriminant values so that they fit within the existing type.
+invalid. Here is another, more subtle example which depends on target word size:
 
-Note also that without a representation manually defined, the compiler will
-optimize by using the smallest integer type possible.
+```compile_fail
+enum DependsOnPointerSize {
+    A = 1 << 32
+}
+```
+
+Here, `1 << 32` is interpreted as an `isize` value. So it is invalid for 32 bit
+target (`target_pointer_width = "32"`) but valid for 64 bit target.
+
+You may want to change representation types to fix this, or else change invalid
+discriminant values so that they fit within the existing type.
 "##,
 
 E0084: r##"
@@ -3643,8 +3652,8 @@ register_diagnostics! {
 //  E0233,
 //  E0234,
 //  E0235, // structure constructor specifies a structure of type but
-    E0236, // no lang item for range syntax
-    E0237, // no lang item for range syntax
+//  E0236, // no lang item for range syntax
+//  E0237, // no lang item for range syntax
     E0238, // parenthesized parameters may only be used with a trait
 //  E0239, // `next` method of `Iterator` trait has unexpected type
 //  E0240,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index a103cbc928b..035f8c60500 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -103,7 +103,7 @@ use dep_graph::DepNode;
 use front::map as hir_map;
 use middle::def::Def;
 use middle::infer::{self, TypeOrigin};
-use middle::subst;
+use middle::subst::Substs;
 use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use session::{config, CompileResult};
 use util::common::time;
@@ -128,7 +128,7 @@ pub mod coherence;
 pub mod variance;
 
 pub struct TypeAndSubsts<'tcx> {
-    pub substs: subst::Substs<'tcx>,
+    pub substs: Substs<'tcx>,
     pub ty: Ty<'tcx>,
 }
 
@@ -220,7 +220,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
     let tcx = ccx.tcx;
     let main_t = tcx.node_id_to_type(main_id);
     match main_t.sty {
-        ty::TyBareFn(..) => {
+        ty::TyFnDef(..) => {
             match tcx.map.find(main_id) {
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
@@ -236,7 +236,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 _ => ()
             }
             let main_def_id = tcx.map.local_def_id(main_id);
-            let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy {
+            let substs = tcx.mk_substs(Substs::empty());
+            let se_ty = tcx.mk_fn_def(main_def_id, substs, ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -244,7 +245,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                     output: ty::FnConverging(tcx.mk_nil()),
                     variadic: false
                 })
-            }));
+            });
 
             require_same_types(tcx, None, false, main_span, main_t, se_ty,
                 || {
@@ -266,7 +267,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
     let tcx = ccx.tcx;
     let start_t = tcx.node_id_to_type(start_id);
     match start_t.sty {
-        ty::TyBareFn(..) => {
+        ty::TyFnDef(..) => {
             match tcx.map.find(start_id) {
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
@@ -282,8 +283,9 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                 _ => ()
             }
 
-            let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)),
-                                  tcx.mk_bare_fn(ty::BareFnTy {
+            let start_def_id = ccx.tcx.map.local_def_id(start_id);
+            let substs = tcx.mk_substs(Substs::empty());
+            let se_ty = tcx.mk_fn_def(start_def_id, substs, ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -294,7 +296,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                     output: ty::FnConverging(tcx.types.isize),
                     variadic: false,
                 }),
-            }));
+            });
 
             require_same_types(tcx, None, false, start_span, start_t, se_ty,
                 || {
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 0c9fa9fd0ab..aecc588c3e2 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -429,7 +429,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
             }
 
-            ty::TyBareFn(_, &ty::BareFnTy { ref sig, .. }) => {
+            ty::TyFnDef(_, _, &ty::BareFnTy { ref sig, .. }) |
+            ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
                 self.add_constraints_from_sig(generics, sig, variance);
             }
 
diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs
index 4cbcfd5a0b2..fb85176340e 100644
--- a/src/librustc_unicode/lib.rs
+++ b/src/librustc_unicode/lib.rs
@@ -51,3 +51,8 @@ pub mod str {
 pub mod derived_property {
     pub use tables::derived_property::{Cased, Case_Ignorable};
 }
+
+// For use in libsyntax
+pub mod property {
+    pub use tables::property::Pattern_White_Space;
+}
diff --git a/src/librustc_unicode/tables.rs b/src/librustc_unicode/tables.rs
index a147bea791c..ad17016eae8 100644
--- a/src/librustc_unicode/tables.rs
+++ b/src/librustc_unicode/tables.rs
@@ -1180,6 +1180,15 @@ pub mod derived_property {
 }
 
 pub mod property {
+    pub const Pattern_White_Space_table: &'static [(char, char)] = &[
+        ('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{200e}', '\u{200f}'),
+        ('\u{2028}', '\u{2029}')
+    ];
+
+    pub fn Pattern_White_Space(c: char) -> bool {
+        super::bsearch_range_table(c, Pattern_White_Space_table)
+    }
+
     pub const White_Space_table: &'static [(char, char)] = &[
         ('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{a0}', '\u{a0}'),
         ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'), ('\u{2028}', '\u{2029}'), ('\u{202f}',
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 02ea83615a3..c14e4af8103 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -26,7 +26,7 @@ use rustc::middle::const_eval;
 
 use core::DocContext;
 use doctree;
-use clean;
+use clean::{self, Attributes};
 
 use super::{Clean, ToSource};
 
@@ -138,13 +138,10 @@ pub fn load_attrs(cx: &DocContext, tcx: &TyCtxt,
 /// These names are used later on by HTML rendering to generate things like
 /// source links back to the original item.
 pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
-    match cx.tcx_opt() {
-        Some(tcx) => {
-            let fqn = tcx.sess.cstore.extern_item_path(did);
-            let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
-            cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
-        }
-        None => {}
+    if let Some(tcx) = cx.tcx_opt() {
+        let fqn = tcx.sess.cstore.extern_item_path(did);
+        let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
+        cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
     }
 }
 
@@ -167,7 +164,7 @@ pub fn build_external_trait(cx: &DocContext, tcx: &TyCtxt,
 fn build_external_function(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Function {
     let t = tcx.lookup_item_type(did);
     let (decl, style, abi) = match t.ty.sty {
-        ty::TyBareFn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
+        ty::TyFnDef(_, _, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
         _ => panic!("bad function"),
     };
 
@@ -230,12 +227,9 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt,
     tcx.populate_inherent_implementations_for_type_if_necessary(did);
     let mut impls = Vec::new();
 
-    match tcx.inherent_impls.borrow().get(&did) {
-        None => {}
-        Some(i) => {
-            for &did in i.iter() {
-                build_impl(cx, tcx, did, &mut impls);
-            }
+    if let Some(i) = tcx.inherent_impls.borrow().get(&did) {
+        for &did in i.iter() {
+            build_impl(cx, tcx, did, &mut impls);
         }
     }
 
@@ -259,7 +253,7 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt,
                 cstore::DlImpl(did) => build_impl(cx, tcx, did, impls),
                 cstore::DlDef(Def::Mod(did)) => {
                     // Don't recurse if this is a #[doc(hidden)] module
-                    if load_attrs(cx, tcx, did).iter().any(|a| is_doc_hidden(a)) {
+                    if load_attrs(cx, tcx, did).list_def("doc").has_word("hidden") {
                         return;
                     }
 
@@ -288,7 +282,7 @@ pub fn build_impl(cx: &DocContext,
     if let Some(ref t) = associated_trait {
         // If this is an impl for a #[doc(hidden)] trait, be sure to not inline
         let trait_attrs = load_attrs(cx, tcx, t.def_id);
-        if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
+        if trait_attrs.list_def("doc").has_word("hidden") {
             return
         }
     }
@@ -428,20 +422,6 @@ pub fn build_impl(cx: &DocContext,
     });
 }
 
-fn is_doc_hidden(a: &clean::Attribute) -> bool {
-    match *a {
-        clean::List(ref name, ref inner) if *name == "doc" => {
-            inner.iter().any(|a| {
-                match *a {
-                    clean::Word(ref s) => *s == "hidden",
-                    _ => false,
-                }
-            })
-        }
-        _ => false
-    }
-}
-
 fn build_module(cx: &DocContext, tcx: &TyCtxt,
                 did: DefId) -> clean::Module {
     let mut items = Vec::new();
@@ -464,9 +444,8 @@ fn build_module(cx: &DocContext, tcx: &TyCtxt,
                 }
                 cstore::DlDef(def) if item.vis == hir::Public => {
                     if !visited.insert(def) { continue }
-                    match try_inline_def(cx, tcx, def) {
-                        Some(i) => items.extend(i),
-                        None => {}
+                    if let Some(i) = try_inline_def(cx, tcx, def) {
+                        items.extend(i)
                     }
                 }
                 cstore::DlDef(..) => {}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b6da5b0ef20..5921093bcac 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -100,10 +100,7 @@ impl<T: Clean<U>, U> Clean<U> for Rc<T> {
 
 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
     fn clean(&self, cx: &DocContext) -> Option<U> {
-        match self {
-            &None => None,
-            &Some(ref v) => Some(v.clean(cx))
-        }
+        self.as_ref().map(|v| v.clean(cx))
     }
 }
 
@@ -178,9 +175,8 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
             };
             let mut tmp = Vec::new();
             for child in &mut m.items {
-                match child.inner {
-                    ModuleItem(..) => {}
-                    _ => continue,
+                if !child.is_mod() {
+                    continue;
                 }
                 let prim = match PrimitiveType::find(&child.attrs) {
                     Some(prim) => prim,
@@ -261,7 +257,7 @@ pub struct Item {
     pub source: Span,
     /// Not everything has a name. E.g., impls
     pub name: Option<String>,
-    pub attrs: Vec<Attribute> ,
+    pub attrs: Vec<Attribute>,
     pub inner: ItemEnum,
     pub visibility: Option<Visibility>,
     pub def_id: DefId,
@@ -270,51 +266,17 @@ pub struct Item {
 }
 
 impl Item {
-    /// Finds the `doc` attribute as a List and returns the list of attributes
-    /// nested inside.
-    pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
-        for attr in &self.attrs {
-            match *attr {
-                List(ref x, ref list) if "doc" == *x => {
-                    return Some(list);
-                }
-                _ => {}
-            }
-        }
-        return None;
-    }
-
     /// Finds the `doc` attribute as a NameValue and returns the corresponding
     /// value found.
     pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
-        for attr in &self.attrs {
-            match *attr {
-                NameValue(ref x, ref v) if "doc" == *x => {
-                    return Some(v);
-                }
-                _ => {}
-            }
-        }
-        return None;
+        self.attrs.value("doc")
     }
-
-    pub fn is_hidden_from_doc(&self) -> bool {
-        match self.doc_list() {
-            Some(l) => {
-                for innerattr in l {
-                    match *innerattr {
-                        Word(ref s) if "hidden" == *s => {
-                            return true
-                        }
-                        _ => (),
-                    }
-                }
-            },
-            None => ()
+    pub fn is_crate(&self) -> bool {
+        match self.inner {
+            ModuleItem(Module { items: _, is_crate: true }) => true,
+            _ => false
         }
-        return false;
     }
-
     pub fn is_mod(&self) -> bool {
         match self.inner { ModuleItem(..) => true, _ => false }
     }
@@ -330,29 +292,34 @@ impl Item {
     pub fn is_fn(&self) -> bool {
         match self.inner { FunctionItem(..) => true, _ => false }
     }
+    pub fn is_associated_type(&self) -> bool {
+        match self.inner { AssociatedTypeItem(..) => true, _ => false }
+    }
+    pub fn is_associated_const(&self) -> bool {
+        match self.inner { AssociatedConstItem(..) => true, _ => false }
+    }
+    pub fn is_method(&self) -> bool {
+        match self.inner { MethodItem(..) => true, _ => false }
+    }
+    pub fn is_ty_method(&self) -> bool {
+        match self.inner { TyMethodItem(..) => true, _ => false }
+    }
 
     pub fn stability_class(&self) -> String {
-        match self.stability {
-            Some(ref s) => {
-                let mut base = match s.level {
-                    stability::Unstable => "unstable".to_string(),
-                    stability::Stable => String::new(),
-                };
-                if !s.deprecated_since.is_empty() {
-                    base.push_str(" deprecated");
-                }
-                base
+        self.stability.as_ref().map(|ref s| {
+            let mut base = match s.level {
+                stability::Unstable => "unstable".to_string(),
+                stability::Stable => String::new(),
+            };
+            if !s.deprecated_since.is_empty() {
+                base.push_str(" deprecated");
             }
-            _ => String::new(),
-        }
+            base
+        }).unwrap_or(String::new())
     }
 
     pub fn stable_since(&self) -> Option<&str> {
-        if let Some(ref s) = self.stability {
-            return Some(&s.since[..]);
-        }
-
-        None
+        self.stability.as_ref().map(|s| &s.since[..])
     }
 }
 
@@ -448,10 +415,54 @@ impl Clean<Item> for doctree::Module {
     }
 }
 
+pub trait Attributes {
+    fn has_word(&self, &str) -> bool;
+    fn value<'a>(&'a self, &str) -> Option<&'a str>;
+    fn list_def<'a>(&'a self, &str) -> &'a [Attribute];
+}
+
+impl Attributes for [Attribute] {
+    /// Returns whether the attribute list contains a specific `Word`
+    fn has_word(&self, word: &str) -> bool {
+        for attr in self {
+            if let Word(ref w) = *attr {
+                if word == *w {
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
+    /// Finds an attribute as NameValue and returns the corresponding value found.
+    fn value<'a>(&'a self, name: &str) -> Option<&'a str> {
+        for attr in self {
+            if let NameValue(ref x, ref v) = *attr {
+                if name == *x {
+                    return Some(v);
+                }
+            }
+        }
+        None
+    }
+
+    /// Finds an attribute as List and returns the list of attributes nested inside.
+    fn list_def<'a>(&'a self, name: &str) -> &'a [Attribute] {
+        for attr in self {
+            if let List(ref x, ref list) = *attr {
+                if name == *x {
+                    return &list[..];
+                }
+            }
+        }
+        &[]
+    }
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub enum Attribute {
     Word(String),
-    List(String, Vec<Attribute> ),
+    List(String, Vec<Attribute>),
     NameValue(String, String)
 }
 
@@ -496,12 +507,6 @@ impl attr::AttrMetaMethods for Attribute {
     fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
     fn span(&self) -> codemap::Span { unimplemented!() }
 }
-impl<'a> attr::AttrMetaMethods for &'a Attribute {
-    fn name(&self) -> InternedString { (**self).name() }
-    fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
-    fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
-    fn span(&self) -> codemap::Span { unimplemented!() }
-}
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub struct TyParam {
@@ -711,7 +716,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
                         if let &ty::Region::ReLateBound(_, _) = *reg {
                             debug!("  hit an ReLateBound {:?}", reg);
                             if let Some(lt) = reg.clean(cx) {
-                                late_bounds.push(lt)
+                                late_bounds.push(lt);
                             }
                         }
                     }
@@ -780,8 +785,7 @@ impl Clean<Option<Lifetime>> for ty::Region {
     fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
         match *self {
             ty::ReStatic => Some(Lifetime::statik()),
-            ty::ReLateBound(_, ty::BrNamed(_, name)) =>
-                Some(Lifetime(name.to_string())),
+            ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
             ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
 
             ty::ReLateBound(..) |
@@ -1151,12 +1155,12 @@ impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
 impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
     fn clean(&self, cx: &DocContext) -> FnDecl {
         let (did, sig) = *self;
-        let mut names = if let Some(_) = cx.map.as_local_node_id(did) {
+        let mut names = if cx.map.as_local_node_id(did).is_some() {
             vec![].into_iter()
         } else {
             cx.tcx().sess.cstore.method_arg_names(did).into_iter()
         }.peekable();
-        if names.peek().map(|s| &**s) == Some("self") {
+        if let Some("self") = names.peek().map(|s| &s[..]) {
             let _ = names.next();
         }
         FnDecl {
@@ -1524,24 +1528,16 @@ impl PrimitiveType {
     }
 
     fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
-        for attr in attrs {
-            let list = match *attr {
-                List(ref k, ref l) if *k == "doc" => l,
-                _ => continue,
-            };
-            for sub_attr in list {
-                let value = match *sub_attr {
-                    NameValue(ref k, ref v)
-                        if *k == "primitive" => v,
-                    _ => continue,
-                };
-                match PrimitiveType::from_str(value) {
-                    Some(p) => return Some(p),
-                    None => {}
+        for attr in attrs.list_def("doc") {
+            if let NameValue(ref k, ref v) = *attr {
+                if "primitive" == *k {
+                    if let ret@Some(..) = PrimitiveType::from_str(v) {
+                        return ret;
+                    }
                 }
             }
         }
-        return None
+        None
     }
 
     pub fn to_string(&self) -> &'static str {
@@ -1627,15 +1623,9 @@ impl Clean<Type> for hir::Ty {
                 }
             }
             TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
-            TyPolyTraitRef(ref bounds) => {
-                PolyTraitRef(bounds.clean(cx))
-            },
-            TyInfer => {
-                Infer
-            },
-            TyTypeof(..) => {
-                panic!("Unimplemented type {:?}", self.node)
-            },
+            TyPolyTraitRef(ref bounds) => PolyTraitRef(bounds.clean(cx)),
+            TyInfer => Infer,
+            TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
         }
     }
 }
@@ -1673,7 +1663,8 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                 mutability: mt.mutbl.clean(cx),
                 type_: box mt.ty.clean(cx),
             },
-            ty::TyBareFn(_, ref fty) => BareFunction(box BareFunctionDecl {
+            ty::TyFnDef(_, _, ref fty) |
+            ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl {
                 unsafety: fty.unsafety,
                 generics: Generics {
                     lifetimes: Vec::new(),
@@ -2253,7 +2244,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
                 polarity: Some(self.polarity.clean(cx)),
             }),
         });
-        return ret;
+        ret
     }
 }
 
@@ -2393,9 +2384,8 @@ impl Clean<Vec<Item>> for doctree::Import {
             }
             hir::ViewPathSimple(name, ref p) => {
                 if !denied {
-                    match inline::try_inline(cx, self.id, Some(name)) {
-                        Some(items) => return items,
-                        None => {}
+                    if let Some(items) = inline::try_inline(cx, self.id, Some(name)) {
+                        return items;
                     }
                 }
                 (vec![], SimpleImport(name.clean(cx),
@@ -2460,9 +2450,8 @@ impl Clean<Vec<Item>> for hir::ForeignMod {
     fn clean(&self, cx: &DocContext) -> Vec<Item> {
         let mut items = self.items.clean(cx);
         for item in &mut items {
-            match item.inner {
-                ForeignFunctionItem(ref mut f) => f.abi = self.abi,
-                _ => {}
+            if let ForeignFunctionItem(ref mut f) = item.inner {
+                f.abi = self.abi;
             }
         }
         items
@@ -2598,11 +2587,7 @@ fn resolve_type(cx: &DocContext,
             };
         }
     };
-    let def = match tcx.def_map.borrow().get(&id) {
-        Some(k) => k.full_def(),
-        None => panic!("unresolved id not in defmap")
-    };
-
+    let def = tcx.def_map.borrow().get(&id).expect("unresolved id not in defmap").full_def();
     debug!("resolve_type: def={:?}", def);
 
     let is_generic = match def {
@@ -2659,7 +2644,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
         let t = inline::build_external_trait(cx, tcx, did);
         cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
     }
-    return did;
+    did
 }
 
 fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
@@ -2732,12 +2717,10 @@ impl Clean<Stability> for attr::Stability {
                 _=> "".to_string(),
             },
             reason: {
-                if let Some(ref depr) = self.rustc_depr {
-                    depr.reason.to_string()
-                } else if let attr::Unstable {reason: Some(ref reason), ..} = self.level {
-                    reason.to_string()
-                } else {
-                    "".to_string()
+                match (&self.rustc_depr, &self.level) {
+                    (&Some(ref depr), _) => depr.reason.to_string(),
+                    (&None, &attr::Unstable {reason: Some(ref reason), ..}) => reason.to_string(),
+                    _ => "".to_string(),
                 }
             },
             issue: match self.level {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 345b84e0cac..5a6fe060eb8 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -133,7 +133,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
     let mut cfg = config::build_configuration(&sess);
     target_features::add_configuration(&mut cfg, &sess);
 
-    let krate = driver::phase_1_parse_input(&sess, cfg, &input);
+    let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input));
 
     let name = link::find_crate_name(Some(&sess), &krate.attrs,
                                      &input);
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 5a4f95d1a1a..ceec80402c0 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 use clean::*;
-use std::collections::HashMap;
-use std::mem::{replace, swap};
 
 pub trait DocFolder : Sized {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
@@ -20,12 +18,10 @@ pub trait DocFolder : Sized {
     /// don't override!
     fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
         let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
-        let inner = inner;
         let inner = match inner {
             StructItem(mut i) => {
-                let mut foo = Vec::new(); swap(&mut foo, &mut i.fields);
-                let num_fields = foo.len();
-                i.fields.extend(foo.into_iter().filter_map(|x| self.fold_item(x)));
+                let num_fields = i.fields.len();
+                i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 i.fields_stripped |= num_fields != i.fields.len();
                 StructItem(i)
             },
@@ -33,29 +29,25 @@ pub trait DocFolder : Sized {
                 ModuleItem(self.fold_mod(i))
             },
             EnumItem(mut i) => {
-                let mut foo = Vec::new(); swap(&mut foo, &mut i.variants);
-                let num_variants = foo.len();
-                i.variants.extend(foo.into_iter().filter_map(|x| self.fold_item(x)));
+                let num_variants = i.variants.len();
+                i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 i.variants_stripped |= num_variants != i.variants.len();
                 EnumItem(i)
             },
             TraitItem(mut i) => {
-                let mut foo = Vec::new(); swap(&mut foo, &mut i.items);
-                i.items.extend(foo.into_iter().filter_map(|x| self.fold_item(x)));
+                i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 TraitItem(i)
             },
             ImplItem(mut i) => {
-                let mut foo = Vec::new(); swap(&mut foo, &mut i.items);
-                i.items.extend(foo.into_iter().filter_map(|x| self.fold_item(x)));
+                i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 ImplItem(i)
             },
             VariantItem(i) => {
                 let i2 = i.clone(); // this clone is small
                 match i.kind {
                     StructVariant(mut j) => {
-                        let mut foo = Vec::new(); swap(&mut foo, &mut j.fields);
-                        let num_fields = foo.len();
-                        j.fields.extend(foo.into_iter().filter_map(|x| self.fold_item(x)));
+                        let num_fields = j.fields.len();
+                        j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                         j.fields_stripped |= num_fields != j.fields.len();
                         VariantItem(Variant {kind: StructVariant(j), ..i2})
                     },
@@ -78,16 +70,13 @@ pub trait DocFolder : Sized {
     }
 
     fn fold_crate(&mut self, mut c: Crate) -> Crate {
-        c.module = match replace(&mut c.module, None) {
-            Some(module) => self.fold_item(module), None => None
-        };
-        let external_traits = replace(&mut c.external_traits, HashMap::new());
-        c.external_traits = external_traits.into_iter().map(|(k, mut v)| {
-            let items = replace(&mut v.items, Vec::new());
-            v.items = items.into_iter().filter_map(|i| self.fold_item(i))
-                           .collect();
+        c.module = c.module.and_then(|module| {
+            self.fold_item(module)
+        });
+        c.external_traits = c.external_traits.into_iter().map(|(k, mut v)| {
+            v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
             (k, v)
         }).collect();
-        return c;
+        c
     }
 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index af6dec8dc86..2cb2b299e40 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -62,7 +62,7 @@ use rustc::middle::stability;
 use rustc::session::config::get_unstable_features_setting;
 use rustc_front::hir;
 
-use clean::{self, SelfTy};
+use clean::{self, SelfTy, Attributes};
 use doctree;
 use fold::DocFolder;
 use html::escape::Escape;
@@ -104,6 +104,8 @@ pub struct Context {
     /// the source files are present in the html rendering, then this will be
     /// `true`.
     pub include_sources: bool,
+    /// The local file sources we've emitted and their respective url-paths.
+    pub local_sources: HashMap<PathBuf, String>,
     /// A flag, which when turned off, will render pages which redirect to the
     /// real location of an item. This is used to allow external links to
     /// publicly reused items to redirect to the right location.
@@ -262,8 +264,6 @@ pub struct Cache {
 struct SourceCollector<'a> {
     cx: &'a mut Context,
 
-    /// Processed source-file paths
-    seen: HashSet<String>,
     /// Root destination to place all HTML output into
     dst: PathBuf,
 }
@@ -374,7 +374,7 @@ fn init_ids() -> HashMap<String, usize> {
      "deref-methods",
      "implementations",
      "derived_implementations"
-     ].into_iter().map(|id| (String::from(*id), 1)).collect::<HashMap<_, _>>()
+     ].into_iter().map(|id| (String::from(*id), 1)).collect()
 }
 
 /// This method resets the local table of used ID attributes. This is typically
@@ -423,6 +423,7 @@ pub fn run(mut krate: clean::Crate,
             playground_url: "".to_string(),
         },
         include_sources: true,
+        local_sources: HashMap::new(),
         render_redirect_pages: false,
         issue_tracker_base_url: None,
     };
@@ -431,42 +432,38 @@ pub fn run(mut krate: clean::Crate,
 
     // Crawl the crate attributes looking for attributes which control how we're
     // going to emit HTML
-    let default: &[_] = &[];
-    match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) {
-        Some(attrs) => {
-            for attr in attrs {
-                match *attr {
-                    clean::NameValue(ref x, ref s)
-                            if "html_favicon_url" == *x => {
-                        cx.layout.favicon = s.to_string();
-                    }
-                    clean::NameValue(ref x, ref s)
-                            if "html_logo_url" == *x => {
-                        cx.layout.logo = s.to_string();
-                    }
-                    clean::NameValue(ref x, ref s)
-                            if "html_playground_url" == *x => {
-                        cx.layout.playground_url = s.to_string();
-                        markdown::PLAYGROUND_KRATE.with(|slot| {
-                            if slot.borrow().is_none() {
-                                let name = krate.name.clone();
-                                *slot.borrow_mut() = Some(Some(name));
-                            }
-                        });
-                    }
-                    clean::NameValue(ref x, ref s)
-                            if "issue_tracker_base_url" == *x => {
-                        cx.issue_tracker_base_url = Some(s.to_string());
-                    }
-                    clean::Word(ref x)
-                            if "html_no_source" == *x => {
-                        cx.include_sources = false;
-                    }
-                    _ => {}
+    if let Some(attrs) = krate.module.as_ref().map(|m| m.attrs.list_def("doc")) {
+        for attr in attrs {
+            match *attr {
+                clean::NameValue(ref x, ref s)
+                        if "html_favicon_url" == *x => {
+                    cx.layout.favicon = s.to_string();
                 }
+                clean::NameValue(ref x, ref s)
+                        if "html_logo_url" == *x => {
+                    cx.layout.logo = s.to_string();
+                }
+                clean::NameValue(ref x, ref s)
+                        if "html_playground_url" == *x => {
+                    cx.layout.playground_url = s.to_string();
+                    markdown::PLAYGROUND_KRATE.with(|slot| {
+                        if slot.borrow().is_none() {
+                            let name = krate.name.clone();
+                            *slot.borrow_mut() = Some(Some(name));
+                        }
+                    });
+                }
+                clean::NameValue(ref x, ref s)
+                        if "issue_tracker_base_url" == *x => {
+                    cx.issue_tracker_base_url = Some(s.to_string());
+                }
+                clean::Word(ref x)
+                        if "html_no_source" == *x => {
+                    cx.include_sources = false;
+                }
+                _ => {}
             }
         }
-        None => {}
     }
 
     // Crawl the crate to build various caches used for the output
@@ -770,11 +767,8 @@ fn render_sources(cx: &mut Context,
     try_err!(mkdir(&dst), &dst);
     let mut folder = SourceCollector {
         dst: dst,
-        seen: HashSet::new(),
         cx: cx,
     };
-    // skip all invalid spans
-    folder.seen.insert("".to_string());
     Ok(folder.fold_crate(krate))
 }
 
@@ -838,35 +832,26 @@ fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
 
     // Failing that, see if there's an attribute specifying where to find this
     // external crate
-    for attr in &e.attrs {
-        match *attr {
-            clean::List(ref x, ref list) if "doc" == *x => {
-                for attr in list {
-                    match *attr {
-                        clean::NameValue(ref x, ref s)
-                                if "html_root_url" == *x => {
-                            if s.ends_with("/") {
-                                return Remote(s.to_string());
-                            }
-                            return Remote(format!("{}/", s));
-                        }
-                        _ => {}
-                    }
-                }
-            }
-            _ => {}
+    e.attrs.list_def("doc").value("html_root_url").map(|url| {
+        let mut url = url.to_owned();
+        if !url.ends_with("/") {
+            url.push('/')
         }
-    }
-
-    // Well, at least we tried.
-    return Unknown;
+        Remote(url)
+    }).unwrap_or(Unknown) // Well, at least we tried.
 }
 
 impl<'a> DocFolder for SourceCollector<'a> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         // If we're including source files, and we haven't seen this file yet,
         // then we need to render it out to the filesystem
-        if self.cx.include_sources && !self.seen.contains(&item.source.filename) {
+        if self.cx.include_sources
+            // skip all invalid spans
+            && item.source.filename != ""
+            // macros from other libraries get special filenames which we can
+            // safely ignore
+            && !(item.source.filename.starts_with("<")
+                && item.source.filename.ends_with("macros>")) {
 
             // If it turns out that we couldn't read this file, then we probably
             // can't read any of the files (generating html output from json or
@@ -884,7 +869,6 @@ impl<'a> DocFolder for SourceCollector<'a> {
                     false
                 }
             };
-            self.seen.insert(item.source.filename.clone());
         }
 
         self.fold_item_recur(item)
@@ -895,19 +879,14 @@ impl<'a> SourceCollector<'a> {
     /// Renders the given filename into its corresponding HTML source file.
     fn emit_source(&mut self, filename: &str) -> io::Result<()> {
         let p = PathBuf::from(filename);
+        if self.cx.local_sources.contains_key(&p) {
+            // We've already emitted this source
+            return Ok(());
+        }
 
-        // If we couldn't open this file, then just returns because it
-        // probably means that it's some standard library macro thing and we
-        // can't have the source to it anyway.
         let mut contents = Vec::new();
-        match File::open(&p).and_then(|mut f| f.read_to_end(&mut contents)) {
-            Ok(r) => r,
-            // macros from other libraries get special filenames which we can
-            // safely ignore
-            Err(..) if filename.starts_with("<") &&
-                       filename.ends_with("macros>") => return Ok(()),
-            Err(e) => return Err(e)
-        };
+        try!(File::open(&p).and_then(|mut f| f.read_to_end(&mut contents)));
+
         let contents = str::from_utf8(&contents).unwrap();
 
         // Remove the utf-8 BOM if any
@@ -920,16 +899,20 @@ impl<'a> SourceCollector<'a> {
         // Create the intermediate directories
         let mut cur = self.dst.clone();
         let mut root_path = String::from("../../");
+        let mut href = String::new();
         clean_srcpath(&self.cx.src_root, &p, false, |component| {
             cur.push(component);
             mkdir(&cur).unwrap();
             root_path.push_str("../");
+            href.push_str(component);
+            href.push('/');
         });
-
         let mut fname = p.file_name().expect("source has no filename")
                          .to_os_string();
         fname.push(".html");
         cur.push(&fname[..]);
+        href.push_str(&fname.to_string_lossy());
+
         let mut w = BufWriter::new(try!(File::create(&cur)));
         let title = format!("{} -- source", cur.file_name().unwrap()
                                                .to_string_lossy());
@@ -939,12 +922,13 @@ impl<'a> SourceCollector<'a> {
             ty: "source",
             root_path: &root_path,
             description: &desc,
-            keywords: get_basic_keywords(),
+            keywords: BASIC_KEYWORDS,
         };
         try!(layout::render(&mut w, &self.cx.layout,
                             &page, &(""), &Source(contents)));
         try!(w.flush());
-        return Ok(());
+        self.cx.local_sources.insert(p, href);
+        Ok(())
     }
 }
 
@@ -983,15 +967,12 @@ impl DocFolder for Cache {
 
         // Collect all the implementors of traits.
         if let clean::ImplItem(ref i) = item.inner {
-            match i.trait_ {
-                Some(clean::ResolvedPath{ did, .. }) => {
-                    self.implementors.entry(did).or_insert(vec![]).push(Implementor {
-                        def_id: item.def_id,
-                        stability: item.stability.clone(),
-                        impl_: i.clone(),
-                    });
-                }
-                Some(..) | None => {}
+            if let Some(clean::ResolvedPath{ did, .. }) = i.trait_ {
+                self.implementors.entry(did).or_insert(vec![]).push(Implementor {
+                    def_id: item.def_id,
+                    stability: item.stability.clone(),
+                    impl_: i.clone(),
+                });
             }
         }
 
@@ -1051,6 +1032,9 @@ impl DocFolder for Cache {
                         }
                     });
 
+                    // A crate has a module at its root, containing all items,
+                    // which should not be indexed. The crate-item itself is
+                    // inserted later on when serializing the search-index.
                     if item.def_id.index != CRATE_DEF_INDEX {
                         self.search_index.push(IndexItem {
                             ty: shortty(&item),
@@ -1075,13 +1059,14 @@ impl DocFolder for Cache {
         }
 
         // Keep track of the fully qualified path for this item.
-        let pushed = if item.name.is_some() {
-            let n = item.name.as_ref().unwrap();
-            if !n.is_empty() {
+        let pushed = match item.name {
+            Some(ref n) if !n.is_empty() => {
                 self.stack.push(n.to_string());
                 true
-            } else { false }
-        } else { false };
+            }
+            _ => false,
+        };
+
         match item.inner {
             clean::StructItem(..) | clean::EnumItem(..) |
             clean::TypedefItem(..) | clean::TraitItem(..) |
@@ -1150,60 +1135,40 @@ impl DocFolder for Cache {
 
         // Once we've recursively found all the generics, then hoard off all the
         // implementations elsewhere
-        let ret = match self.fold_item_recur(item) {
-            Some(item) => {
-                match item {
-                    clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
-                        // extract relevant documentation for this impl
-                        let dox = match attrs.into_iter().find(|a| {
-                            match *a {
-                                clean::NameValue(ref x, _)
-                                        if "doc" == *x => {
-                                    true
-                                }
-                                _ => false
-                            }
-                        }) {
-                            Some(clean::NameValue(_, dox)) => Some(dox),
-                            Some(..) | None => None,
-                        };
-
-                        // Figure out the id of this impl. This may map to a
-                        // primitive rather than always to a struct/enum.
-                        let did = match i.for_ {
-                            clean::ResolvedPath { did, .. } |
-                            clean::BorrowedRef {
-                                type_: box clean::ResolvedPath { did, .. }, ..
-                            } => {
-                                Some(did)
-                            }
-
-                            ref t => {
-                                t.primitive_type().and_then(|t| {
-                                    self.primitive_locations.get(&t).map(|n| {
-                                        let id = t.to_def_index();
-                                        DefId { krate: *n, index: id }
-                                    })
-                                })
-                            }
-                        };
-
-                        if let Some(did) = did {
-                            self.impls.entry(did).or_insert(vec![]).push(Impl {
-                                impl_: i,
-                                dox: dox,
-                                stability: item.stability.clone(),
-                            });
-                        }
+        let ret = self.fold_item_recur(item).and_then(|item| {
+            if let clean::Item { attrs, inner: clean::ImplItem(i), .. } = item {
+                // Figure out the id of this impl. This may map to a
+                // primitive rather than always to a struct/enum.
+                let did = match i.for_ {
+                    clean::ResolvedPath { did, .. } |
+                    clean::BorrowedRef {
+                        type_: box clean::ResolvedPath { did, .. }, ..
+                    } => {
+                        Some(did)
+                    }
 
-                        None
+                    ref t => {
+                        t.primitive_type().and_then(|t| {
+                            self.primitive_locations.get(&t).map(|n| {
+                                let id = t.to_def_index();
+                                DefId { krate: *n, index: id }
+                            })
+                        })
                     }
+                };
 
-                    i => Some(i),
+                if let Some(did) = did {
+                    self.impls.entry(did).or_insert(vec![]).push(Impl {
+                        impl_: i,
+                        dox: attrs.value("doc").map(|s|s.to_owned()),
+                        stability: item.stability.clone(),
+                    });
                 }
+                None
+            } else {
+                Some(item)
             }
-            i => i,
-        };
+        });
 
         if pushed { self.stack.pop().unwrap(); }
         if parent_pushed { self.parent_stack.pop().unwrap(); }
@@ -1301,11 +1266,7 @@ impl Context {
             }
             title.push_str(" - Rust");
             let tyname = shortty(it).to_static_str();
-            let is_crate = match it.inner {
-                clean::ModuleItem(clean::Module { items: _, is_crate: true }) => true,
-                _ => false
-            };
-            let desc = if is_crate {
+            let desc = if it.is_crate() {
                 format!("API documentation for the Rust `{}` crate.",
                         cx.layout.krate)
             } else {
@@ -1459,7 +1420,7 @@ impl<'a> Item<'a> {
     /// If `None` is returned, then a source link couldn't be generated. This
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
-    fn href(&self, cx: &Context) -> Option<String> {
+    fn href(&self) -> Option<String> {
         let href = if self.item.source.loline == self.item.source.hiline {
             format!("{}", self.item.source.loline)
         } else {
@@ -1492,25 +1453,13 @@ impl<'a> Item<'a> {
         // know the span, so we plow forward and generate a proper url. The url
         // has anchors for the line numbers that we're linking to.
         } else if self.item.def_id.is_local() {
-            let mut path = Vec::new();
-            clean_srcpath(&cx.src_root, Path::new(&self.item.source.filename),
-                          true, |component| {
-                path.push(component.to_string());
-            });
-
-            // If the span points into an external macro the
-            // source-file will be bogus, i.e `<foo macros>`
-            let filename = &self.item.source.filename;
-            if !(filename.starts_with("<") && filename.ends_with("macros>")) {
-                Some(format!("{root}src/{krate}/{path}.html#{href}",
-                             root = self.cx.root_path,
-                             krate = self.cx.layout.krate,
-                             path = path.join("/"),
-                             href = href))
-            } else {
-                None
-            }
-
+            self.cx.local_sources.get(&PathBuf::from(&self.item.source.filename)).map(|path| {
+                format!("{root}src/{krate}/{path}.html#{href}",
+                        root = self.cx.root_path,
+                        krate = self.cx.layout.krate,
+                        path = path,
+                        href = href)
+            })
         // If this item is not part of the local crate, then things get a little
         // trickier. We don't actually know the span of the external item, but
         // we know that the documentation on the other end knows the span!
@@ -1590,13 +1539,10 @@ impl<'a> fmt::Display for Item<'a> {
         // this page, and this link will be auto-clicked. The `id` attribute is
         // used to find the link to auto-click.
         if self.cx.include_sources && !is_primitive {
-            match self.href(self.cx) {
-                Some(l) => {
-                    try!(write!(fmt, "<a id='src-{}' class='srclink' \
-                                       href='{}' title='{}'>[src]</a>",
-                                self.item.def_id.index.as_usize(), l, "goto source code"));
-                }
-                None => {}
+            if let Some(l) = self.href() {
+                try!(write!(fmt, "<a id='src-{}' class='srclink' \
+                                   href='{}' title='{}'>[src]</a>",
+                            self.item.def_id.index.as_usize(), l, "goto source code"));
             }
         }
 
@@ -1810,7 +1756,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
 }
 
 fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Option<String> {
-    let mut result = item.stability.as_ref().and_then(|stab| {
+    item.stability.as_ref().and_then(|stab| {
         let reason = if show_reason && !stab.reason.is_empty() {
             format!(": {}", stab.reason)
         } else {
@@ -1845,10 +1791,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio
         };
         Some(format!("<em class='stab {}'>{}</em>",
                      item.stability_class(), text))
-    });
-
-    if result.is_none() {
-        result = item.deprecation.as_ref().and_then(|depr| {
+    }).or_else(|| {
+        item.deprecation.as_ref().and_then(|depr| {
             let note = if show_reason && !depr.note.is_empty() {
                 format!(": {}", depr.note)
             } else {
@@ -1862,10 +1806,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio
 
             let text = format!("Deprecated{}{}", since, Markdown(&note));
             Some(format!("<em class='stab deprecated'>{}</em>", text))
-        });
-    }
-
-    result
+        })
+    })
 }
 
 struct Initializer<'a>(&'a str);
@@ -1945,18 +1887,10 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                   bounds,
                   WhereClause(&t.generics)));
 
-    let types = t.items.iter().filter(|m| {
-        match m.inner { clean::AssociatedTypeItem(..) => true, _ => false }
-    }).collect::<Vec<_>>();
-    let consts = t.items.iter().filter(|m| {
-        match m.inner { clean::AssociatedConstItem(..) => true, _ => false }
-    }).collect::<Vec<_>>();
-    let required = t.items.iter().filter(|m| {
-        match m.inner { clean::TyMethodItem(_) => true, _ => false }
-    }).collect::<Vec<_>>();
-    let provided = t.items.iter().filter(|m| {
-        match m.inner { clean::MethodItem(_) => true, _ => false }
-    }).collect::<Vec<_>>();
+    let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
+    let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
+    let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
+    let provided = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
 
     if t.items.is_empty() {
         try!(write!(w, "{{ }}"));
@@ -2117,17 +2051,12 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
 fn render_stability_since_raw<'a>(w: &mut fmt::Formatter,
                                   ver: Option<&'a str>,
                                   containing_ver: Option<&'a str>) -> fmt::Result {
-    if containing_ver != ver {
-        match ver {
-            Some(v) =>
-                if v.len() > 0 {
-                        try!(write!(w, "<span class=\"since\">{}</span>",
-                                    v))
-                },
-            None => {}
+    if let Some(v) = ver {
+        if containing_ver != ver && v.len() > 0 {
+            try!(write!(w, "<span class=\"since\">{}</span>",
+                        v))
         }
     }
-
     Ok(())
 }
 
@@ -2298,43 +2227,33 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
             try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
                           name = variant.name.as_ref().unwrap()));
             try!(document(w, cx, variant));
-            match variant.inner {
-                clean::VariantItem(ref var) => {
-                    match var.kind {
-                        clean::StructVariant(ref s) => {
-                            let fields = s.fields.iter().filter(|f| {
-                                match f.inner {
-                                    clean::StructFieldItem(ref t) => match *t {
-                                        clean::HiddenStructField => false,
-                                        clean::TypedStructField(..) => true,
-                                    },
-                                    _ => false,
-                                }
-                            });
-                            try!(write!(w, "<h3 class='fields'>Fields</h3>\n
-                                              <table>"));
-                            for field in fields {
-                                try!(write!(w, "<tr><td \
-                                                  id='variant.{v}.field.{f}'>\
-                                                  <code>{f}</code></td><td>",
-                                              v = variant.name.as_ref().unwrap(),
-                                              f = field.name.as_ref().unwrap()));
-                                try!(document(w, cx, field));
-                                try!(write!(w, "</td></tr>"));
-                            }
-                            try!(write!(w, "</table>"));
-                        }
-                        _ => ()
+
+            use clean::{Variant, StructVariant};
+            if let clean::VariantItem( Variant { kind: StructVariant(ref s) } ) = variant.inner {
+                let fields = s.fields.iter().filter(|f| {
+                    match f.inner {
+                        clean::StructFieldItem(clean::TypedStructField(..)) => true,
+                        _ => false,
                     }
+                });
+                try!(write!(w, "<h3 class='fields'>Fields</h3>\n
+                                  <table>"));
+                for field in fields {
+                    try!(write!(w, "<tr><td \
+                                      id='variant.{v}.field.{f}'>\
+                                      <code>{f}</code></td><td>",
+                                  v = variant.name.as_ref().unwrap(),
+                                  f = field.name.as_ref().unwrap()));
+                    try!(document(w, cx, field));
+                    try!(write!(w, "</td></tr>"));
                 }
-                _ => ()
+                try!(write!(w, "</table>"));
             }
             try!(write!(w, "</td><td>"));
             try!(render_stability_since(w, variant, it));
             try!(write!(w, "</td></tr>"));
         }
         try!(write!(w, "</table>"));
-
     }
     try!(render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All));
     Ok(())
@@ -2365,9 +2284,8 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                   VisSpace(it.visibility),
                   if structhead {"struct "} else {""},
                   it.name.as_ref().unwrap()));
-    match g {
-        Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))),
-        None => {}
+    if let Some(g) = g {
+        try!(write!(w, "{}{}", *g, WhereClause(g)))
     }
     match ty {
         doctree::Plain => {
@@ -2461,7 +2379,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
         }
     }
     if let AssocItemRender::DerefFor { .. } = what {
-        return Ok(())
+        return Ok(());
     }
     if !traits.is_empty() {
         let deref_impl = traits.iter().find(|t| {
@@ -2542,10 +2460,17 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                     link: AssocItemLink, render_static: bool,
                     outer_version: Option<&str>) -> fmt::Result {
         let name = item.name.as_ref().unwrap();
+
+        let is_static = match item.inner {
+            clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
+            clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
+            _ => false
+        };
+
         match item.inner {
             clean::MethodItem(..) | clean::TyMethodItem(..) => {
                 // Only render when the method is not static or we allow static methods
-                if !is_static_method(item) || render_static {
+                if !is_static || render_static {
                     let id = derive_id(format!("method.{}", name));
                     try!(write!(w, "<h4 id='{}' class='{}'>", id, shortty(item)));
                     try!(render_stability_since_raw(w, item.stable_since(), outer_version));
@@ -2581,22 +2506,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
             _ => panic!("can't make docs for trait item with name {:?}", item.name)
         }
 
-        return if let AssocItemLink::Anchor = link {
-            if is_static_method(item) && !render_static {
-                Ok(())
-            } else {
+        match link {
+            AssocItemLink::Anchor if !is_static || render_static => {
                 document(w, cx, item)
-            }
-        } else {
-            Ok(())
-        };
-
-        fn is_static_method(item: &clean::Item) -> bool {
-            match item.inner {
-                clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
-                clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
-                _ => false
-            }
+            },
+            _ => Ok(()),
         }
     }
 
@@ -2614,9 +2528,8 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                               outer_version: Option<&str>) -> fmt::Result {
         for trait_item in &t.items {
             let n = trait_item.name.clone();
-            match i.items.iter().find(|m| { m.name == n }) {
-                Some(..) => continue,
-                None => {}
+            if i.items.iter().find(|m| { m.name == n }).is_some() {
+                continue;
             }
 
             try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static,
@@ -2632,7 +2545,6 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
     if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
         if let Some(t) = cache().traits.get(&did) {
             try!(render_default_items(w, cx, did, t, &i.impl_, render_header, outer_version));
-
         }
     }
     try!(write!(w, "</div>"));
@@ -2676,7 +2588,7 @@ impl<'a> fmt::Display for Sidebar<'a> {
         try!(write!(fmt, "</p>"));
 
         // sidebar refers to the enclosing module, not this module
-        let relpath = if shortty(it) == ItemType::Module { "../" } else { "" };
+        let relpath = if it.is_mod() { "../" } else { "" };
         try!(write!(fmt,
                     "<script>window.sidebarCurrent = {{\
                         name: '{name}', \
@@ -2734,12 +2646,10 @@ fn item_primitive(w: &mut fmt::Formatter, cx: &Context,
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
-fn get_basic_keywords() -> &'static str {
-    "rust, rustlang, rust-lang"
-}
+const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang";
 
 fn make_item_keywords(it: &clean::Item) -> String {
-    format!("{}, {}", get_basic_keywords(), it.name.as_ref().unwrap())
+    format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap())
 }
 
 fn get_index_search_type(item: &clean::Item,
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ffb15d157b0..21df784b098 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -43,7 +43,7 @@ extern crate rustc_back;
 extern crate rustc_front;
 extern crate rustc_metadata;
 extern crate serialize;
-extern crate syntax;
+#[macro_use] extern crate syntax;
 extern crate test as testing;
 extern crate rustc_unicode;
 #[macro_use] extern crate log;
@@ -94,6 +94,8 @@ pub mod visit_ast;
 pub mod test;
 mod flock;
 
+use clean::Attributes;
+
 type Pass = (&'static str,                                      // name
              fn(clean::Crate) -> plugins::PluginResult,         // fn
              &'static str);                                     // description
@@ -107,6 +109,8 @@ const PASSES: &'static [Pass] = &[
      "concatenates all document attributes into one document attribute"),
     ("strip-private", passes::strip_private,
      "strips all private items from a crate which cannot be seen externally"),
+    ("strip-priv-imports", passes::strip_priv_imports,
+     "strips all private import statements (`use`, `extern crate`) from a crate"),
 ];
 
 const DEFAULT_PASSES: &'static [&'static str] = &[
@@ -283,19 +287,15 @@ pub fn main_args(args: &[String]) -> isize {
     info!("going to format");
     match matches.opt_str("w").as_ref().map(|s| &**s) {
         Some("html") | None => {
-            match html::render::run(krate, &external_html,
-                                    output.unwrap_or(PathBuf::from("doc")),
-                                    passes.into_iter().collect()) {
-                Ok(()) => {}
-                Err(e) => panic!("failed to generate documentation: {}", e),
-            }
+            html::render::run(krate, &external_html,
+                              output.unwrap_or(PathBuf::from("doc")),
+                              passes.into_iter().collect())
+                .expect("failed to generate documentation")
         }
         Some("json") => {
-            match json_output(krate, json_plugins,
-                              output.unwrap_or(PathBuf::from("doc.json"))) {
-                Ok(()) => {}
-                Err(e) => panic!("failed to write json: {}", e),
-            }
+            json_output(krate, json_plugins,
+                        output.unwrap_or(PathBuf::from("doc.json")))
+                .expect("failed to write json")
         }
         Some(s) => {
             println!("unknown output format: {}", s);
@@ -332,18 +332,10 @@ fn parse_externs(matches: &getopts::Matches) -> Result<core::Externs, String> {
     let mut externs = HashMap::new();
     for arg in &matches.opt_strs("extern") {
         let mut parts = arg.splitn(2, '=');
-        let name = match parts.next() {
-            Some(s) => s,
-            None => {
-                return Err("--extern value must not be empty".to_string());
-            }
-        };
-        let location = match parts.next() {
-            Some(s) => s,
-            None => {
-                return Err("--extern value must be of the format `foo=bar`".to_string());
-            }
-        };
+        let name = try!(parts.next().ok_or("--extern value must not be empty".to_string()));
+        let location = try!(parts.next()
+                                 .ok_or("--extern value must be of the format `foo=bar`"
+                                    .to_string()));
         let name = name.to_string();
         externs.entry(name).or_insert(vec![]).push(location.to_string());
     }
@@ -391,32 +383,25 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
 
     // Process all of the crate attributes, extracting plugin metadata along
     // with the passes which we are supposed to run.
-    match krate.module.as_ref().unwrap().doc_list() {
-        Some(nested) => {
-            for inner in nested {
-                match *inner {
-                    clean::Word(ref x)
-                            if "no_default_passes" == *x => {
-                        default_passes = false;
-                    }
-                    clean::NameValue(ref x, ref value)
-                            if "passes" == *x => {
-                        for pass in value.split_whitespace() {
-                            passes.push(pass.to_string());
-                        }
-                    }
-                    clean::NameValue(ref x, ref value)
-                            if "plugins" == *x => {
-                        for p in value.split_whitespace() {
-                            plugins.push(p.to_string());
-                        }
-                    }
-                    _ => {}
+    for attr in krate.module.as_ref().unwrap().attrs.list_def("doc") {
+        match *attr {
+            clean::Word(ref w) if "no_default_passes" == *w => {
+                default_passes = false;
+            },
+            clean::NameValue(ref name, ref value) => {
+                let sink = match &name[..] {
+                    "passes" => &mut passes,
+                    "plugins" => &mut plugins,
+                    _ => continue,
+                };
+                for p in value.split_whitespace() {
+                    sink.push(p.to_string());
                 }
             }
+            _ => (),
         }
-        None => {}
     }
+
     if default_passes {
         for name in DEFAULT_PASSES.iter().rev() {
             passes.insert(0, name.to_string());
@@ -448,17 +433,16 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
     // Run everything!
     info!("Executing passes/plugins");
     let (krate, json) = pm.run_plugins(krate);
-    return Output { krate: krate, json_plugins: json, passes: passes, };
+    Output { krate: krate, json_plugins: json, passes: passes }
 }
 
 /// This input format purely deserializes the json output file. No passes are
 /// run over the deserialized output.
 fn json_input(input: &str) -> Result<Output, String> {
     let mut bytes = Vec::new();
-    match File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) {
-        Ok(_) => {}
-        Err(e) => return Err(format!("couldn't open {}: {}", input, e)),
-    };
+    if let Err(e) = File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) {
+        return Err(format!("couldn't open {}: {}", input, e))
+    }
     match json::from_reader(&mut &bytes[..]) {
         Err(s) => Err(format!("{:?}", s)),
         Ok(Json::Object(obj)) => {
@@ -507,21 +491,13 @@ fn json_output(krate: clean::Crate, res: Vec<plugins::PluginJson> ,
     json.insert("schema".to_string(), Json::String(SCHEMA_VERSION.to_string()));
     let plugins_json = res.into_iter()
                           .filter_map(|opt| {
-                              match opt {
-                                  None => None,
-                                  Some((string, json)) => {
-                                      Some((string.to_string(), json))
-                                  }
-                              }
+                              opt.map(|(string, json)| (string.to_string(), json))
                           }).collect();
 
     // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
     // straight to the Rust JSON representation.
     let crate_json_str = format!("{}", json::as_json(&krate));
-    let crate_json = match json::from_str(&crate_json_str) {
-        Ok(j) => j,
-        Err(e) => panic!("Rust generated JSON is invalid: {:?}", e)
-    };
+    let crate_json = json::from_str(&crate_json_str).expect("Rust generated JSON is invalid");
 
     json.insert("crate".to_string(), crate_json);
     json.insert("plugins".to_string(), Json::Object(plugins_json));
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 957957eaec6..2eb82dec6da 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -16,7 +16,7 @@ use std::string::String;
 use std::usize;
 use rustc_front::hir;
 
-use clean;
+use clean::{self, Attributes};
 use clean::Item;
 use plugins;
 use fold;
@@ -33,7 +33,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
         }
         impl<'a> fold::DocFolder for Stripper<'a> {
             fn fold_item(&mut self, i: Item) -> Option<Item> {
-                if i.is_hidden_from_doc() {
+                if i.attrs.list_def("doc").has_word("hidden") {
                     debug!("found one in strip_hidden; removing");
                     self.stripped.insert(i.def_id);
 
@@ -106,7 +106,7 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
             retained: &mut retained,
             access_levels: &access_levels,
         };
-        krate = stripper.fold_crate(krate);
+        krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
     }
 
     // strip all private implementations of traits
@@ -144,12 +144,6 @@ impl<'a> fold::DocFolder for Stripper<'a> {
                 }
             }
 
-            clean::ExternCrateItem(..) | clean::ImportItem(_) => {
-                if i.visibility != Some(hir::Public) {
-                    return None
-                }
-            }
-
             clean::StructFieldItem(..) => {
                 if i.visibility != Some(hir::Public) {
                     return Some(clean::Item {
@@ -170,6 +164,9 @@ impl<'a> fold::DocFolder for Stripper<'a> {
                     return None;
                 }
             }
+            // handled in the `strip-priv-imports` pass
+            clean::ExternCrateItem(..) | clean::ImportItem(_) => {}
+
             clean::DefaultImplItem(..) | clean::ImplItem(..) => {}
 
             // tymethods/macros have no control over privacy
@@ -205,22 +202,19 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             self.fold_item_recur(i)
         };
 
-        match i {
-            Some(i) => {
-                match i.inner {
-                    // emptied modules/impls have no need to exist
-                    clean::ModuleItem(ref m)
-                        if m.items.is_empty() &&
-                           i.doc_value().is_none() => None,
-                    clean::ImplItem(ref i) if i.items.is_empty() => None,
-                    _ => {
-                        self.retained.insert(i.def_id);
-                        Some(i)
-                    }
+        i.and_then(|i| {
+            match i.inner {
+                // emptied modules/impls have no need to exist
+                clean::ModuleItem(ref m)
+                    if m.items.is_empty() &&
+                       i.doc_value().is_none() => None,
+                clean::ImplItem(ref i) if i.items.is_empty() => None,
+                _ => {
+                    self.retained.insert(i.def_id);
+                    Some(i)
                 }
             }
-            None => None,
-        }
+        })
     }
 }
 
@@ -242,12 +236,26 @@ impl<'a> fold::DocFolder for ImplStripper<'a> {
     }
 }
 
+// This stripper discards all private import statements (`use`, `extern crate`)
+struct ImportStripper;
+impl fold::DocFolder for ImportStripper {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::ExternCrateItem(..) |
+            clean::ImportItem(..) if i.visibility != Some(hir::Public) => None,
+            _ => self.fold_item_recur(i)
+        }
+    }
+}
+
+pub fn strip_priv_imports(krate: clean::Crate)  -> plugins::PluginResult {
+    (ImportStripper.fold_crate(krate), None)
+}
 
 pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
     struct CommentCleaner;
     impl fold::DocFolder for CommentCleaner {
-        fn fold_item(&mut self, i: Item) -> Option<Item> {
-            let mut i = i;
+        fn fold_item(&mut self, mut i: Item) -> Option<Item> {
             let mut avec: Vec<clean::Attribute> = Vec::new();
             for attr in &i.attrs {
                 match attr {
@@ -271,17 +279,14 @@ pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
 pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult {
     struct Collapser;
     impl fold::DocFolder for Collapser {
-        fn fold_item(&mut self, i: Item) -> Option<Item> {
+        fn fold_item(&mut self, mut i: Item) -> Option<Item> {
             let mut docstr = String::new();
-            let mut i = i;
             for attr in &i.attrs {
-                match *attr {
-                    clean::NameValue(ref x, ref s)
-                            if "doc" == *x => {
+                if let clean::NameValue(ref x, ref s) = *attr {
+                    if "doc" == *x {
                         docstr.push_str(s);
                         docstr.push('\n');
-                    },
-                    _ => ()
+                    }
                 }
             }
             let mut a: Vec<clean::Attribute> = i.attrs.iter().filter(|&a| match a {
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 39550488a9e..6294b676651 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -91,7 +91,7 @@ pub fn run(input: &str,
 
     let mut cfg = config::build_configuration(&sess);
     cfg.extend(config::parse_cfgspecs(cfgs.clone()));
-    let krate = driver::phase_1_parse_input(&sess, cfg, &input);
+    let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input));
     let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate,
                                                      "rustdoc-test", None)
         .expect("phase_2_configure_and_expand aborted in rustdoc!");
@@ -121,9 +121,8 @@ pub fn run(input: &str,
     let mut v = RustdocVisitor::new(&ctx, None);
     v.visit(ctx.map.krate());
     let mut krate = v.clean(&ctx);
-    match crate_name {
-        Some(name) => krate.name = name,
-        None => {}
+    if let Some(name) = crate_name {
+        krate.name = name;
     }
     let (krate, _) = passes::collapse_docs(krate);
     let (krate, _) = passes::unindent_comments(krate);
@@ -334,13 +333,10 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool,
     // Don't inject `extern crate std` because it's already injected by the
     // compiler.
     if !s.contains("extern crate") && !opts.no_crate_inject && cratename != Some("std") {
-        match cratename {
-            Some(cratename) => {
-                if s.contains(cratename) {
-                    prog.push_str(&format!("extern crate {};\n", cratename));
-                }
+        if let Some(cratename) = cratename {
+            if s.contains(cratename) {
+                prog.push_str(&format!("extern crate {};\n", cratename));
             }
-            None => {}
         }
     }
     if dont_insert_main || s.contains("fn main") {
@@ -476,12 +472,7 @@ impl DocFolder for Collector {
             _ => typename_if_impl(&item)
         };
 
-        let pushed = if let Some(name) = current_name {
-            self.names.push(name);
-            true
-        } else {
-            false
-        };
+        let pushed = current_name.map(|name| self.names.push(name)).is_some();
 
         if let Some(doc) = item.doc_value() {
             self.cnt = 0;
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index ba389bc42b7..bc6b4f83984 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -263,13 +263,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         let name = renamed.unwrap_or(item.name);
         match item.node {
             hir::ItemExternCrate(ref p) => {
-                let path = match *p {
-                    None => None,
-                    Some(x) => Some(x.to_string()),
-                };
                 om.extern_crates.push(ExternCrate {
                     name: name,
-                    path: path,
+                    path: p.map(|x|x.to_string()),
                     vis: item.vis,
                     attrs: item.attrs.clone(),
                     whence: item.span,
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index 587d1d42258..031a9b8bec2 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Operations on ASCII strings and characters
+//! Operations on ASCII strings and characters.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -169,8 +169,6 @@ pub trait AsciiExt {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ascii)]
-    ///
     /// use std::ascii::AsciiExt;
     ///
     /// let ascii: String = "a".to_owned();
@@ -179,7 +177,7 @@ pub trait AsciiExt {
     ///
     /// assert_eq!(upper, "A");
     /// ```
-    #[unstable(feature = "ascii", issue = "27809")]
+    #[stable(feature = "into_ascii", since = "1.8.0")]
     fn into_ascii_uppercase(self) -> Self::Owned where Self: Sized {
         self.to_ascii_uppercase()
     }
@@ -192,8 +190,6 @@ pub trait AsciiExt {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ascii)]
-    ///
     /// use std::ascii::AsciiExt;
     ///
     /// let ascii: String = "A".to_owned();
@@ -202,7 +198,7 @@ pub trait AsciiExt {
     ///
     /// assert_eq!(lower, "a");
     /// ```
-    #[unstable(feature = "ascii", issue = "27809")]
+    #[stable(feature = "into_ascii", since = "1.8.0")]
     fn into_ascii_lowercase(self) -> Self::Owned where Self: Sized {
         self.to_ascii_lowercase()
     }
@@ -210,7 +206,7 @@ pub trait AsciiExt {
 
 /// Implement `into_ascii_lowercase` and `into_ascii_uppercase` without memory allocation,
 /// defer other methods to `str`.
-#[unstable(feature = "ascii", issue = "27809")]
+#[stable(feature = "into_ascii", since = "1.8.0")]
 impl AsciiExt for String {
     type Owned = Self;
 
@@ -242,7 +238,7 @@ impl AsciiExt for String {
 
 /// Implement `into_ascii_lowercase` and `into_ascii_uppercase` without memory allocation,
 /// defer other methods to `[u8]`.
-#[unstable(feature = "ascii", issue = "27809")]
+#[stable(feature = "into_ascii", since = "1.8.0")]
 impl AsciiExt for Vec<u8> {
     type Owned = Self;
 
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index c60ec4d3655..1c8375479ca 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -28,7 +28,7 @@ fn main() {
     }
 
     if target.contains("unknown-linux") {
-        if target.contains("musl") && target.contains("x86_64") {
+        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
             println!("cargo:rustc-link-lib=static=unwind");
         } else {
             println!("cargo:rustc-link-lib=dl");
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index badbba21d55..6b88d498b10 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Filesystem manipulation operations
+//! Filesystem manipulation operations.
 //!
 //! This module contains basic methods to manipulate the contents of the local
 //! filesystem. All methods in this module represent cross-platform filesystem
@@ -22,7 +22,6 @@ use ffi::OsString;
 use io::{self, SeekFrom, Seek, Read, Write};
 use path::{Path, PathBuf};
 use sys::fs as fs_imp;
-use sys_common::io::read_to_end_uninitialized;
 use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
 use vec::Vec;
 use time::SystemTime;
@@ -351,7 +350,7 @@ impl Read for File {
         self.inner.read(buf)
     }
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
+        self.inner.read_to_end(buf)
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -372,6 +371,9 @@ impl<'a> Read for &'a File {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Write for &'a File {
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index cd2d5e52462..25309a785c4 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -18,7 +18,6 @@ use io::lazy::Lazy;
 use io::{self, BufReader, LineWriter};
 use sync::{Arc, Mutex, MutexGuard};
 use sys::stdio;
-use sys_common::io::{read_to_end_uninitialized};
 use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
 use thread::LocalKeyState;
 
@@ -78,6 +77,9 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
 
 impl Read for StdinRaw {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
 }
 impl Write for StdoutRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
@@ -116,6 +118,12 @@ impl<R: io::Read> io::Read for Maybe<R> {
             Maybe::Fake => Ok(0)
         }
     }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        match *self {
+            Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0),
+            Maybe::Fake => Ok(0)
+        }
+    }
 }
 
 fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
@@ -294,7 +302,7 @@ impl<'a> Read for StdinLock<'a> {
         self.inner.read(buf)
     }
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
+        self.inner.read_to_end(buf)
     }
 }
 
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index e062f9040af..d3a0295c835 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -232,6 +232,7 @@
 #![feature(fnbox)]
 #![feature(heap_api)]
 #![feature(hashmap_hasher)]
+#![feature(inclusive_range)]
 #![feature(int_error_internals)]
 #![feature(into_cow)]
 #![feature(lang_items)]
@@ -246,7 +247,6 @@
 #![feature(optin_builtin_traits)]
 #![feature(placement_in_syntax)]
 #![feature(rand)]
-#![feature(range_inclusive)]
 #![feature(raw)]
 #![feature(repr_simd)]
 #![feature(reflect_marker)]
@@ -281,7 +281,6 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #[cfg(test)] extern crate test;
-#[cfg(test)] #[macro_use] extern crate log;
 
 // We want to reexport a few macros from core but libcore has already been
 // imported by the compiler (via our #[no_std] attribute) In this case we just
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index d241cd032ed..39adda1066a 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -173,18 +173,6 @@ macro_rules! select {
     })
 }
 
-// When testing the standard library, we link to the liblog crate to get the
-// logging macros. In doing so, the liblog crate was linked against the real
-// version of libstd, and uses a different std::fmt module than the test crate
-// uses. To get around this difference, we redefine the log!() macro here to be
-// just a dumb version of what it should be.
-#[cfg(test)]
-macro_rules! log {
-    ($lvl:expr, $($args:tt)*) => (
-        if log_enabled!($lvl) { println!($($args)*) }
-    )
-}
-
 #[cfg(test)]
 macro_rules! assert_approx_eq {
     ($a:expr, $b:expr) => ({
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index 68075af61cf..9c8ff44c704 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -121,6 +121,8 @@ impl Ipv4Addr {
     }
 
     /// Returns true if the address appears to be globally routable.
+    /// See [iana-ipv4-special-registry][ipv4-sr].
+    /// [ipv4-sr]: http://goo.gl/RaZ7lg
     ///
     /// The following return false:
     ///
@@ -129,9 +131,10 @@ impl Ipv4Addr {
     /// - the link-local address (169.254.0.0/16)
     /// - the broadcast address (255.255.255.255/32)
     /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24)
+    /// - the unspecified address (0.0.0.0)
     pub fn is_global(&self) -> bool {
         !self.is_private() && !self.is_loopback() && !self.is_link_local() &&
-        !self.is_broadcast() && !self.is_documentation()
+        !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified()
     }
 
     /// Returns true if this is a multicast address.
@@ -725,22 +728,22 @@ mod tests {
         }
 
         //    address                unspec loopbk privt  linloc global multicast brdcast doc
-        check(&[0, 0, 0, 0],         true,  false, false, false, true,  false,    false,  false);
-        check(&[0, 0, 0, 1],         false, false, false, false, true,  false,    false,  false);
-        check(&[1, 0, 0, 0],         false, false, false, false, true,  false,    false,  false);
-        check(&[10, 9, 8, 7],        false, false, true,  false, false, false,    false,  false);
-        check(&[127, 1, 2, 3],       false, true,  false, false, false, false,    false,  false);
-        check(&[172, 31, 254, 253],  false, false, true,  false, false, false,    false,  false);
-        check(&[169, 254, 253, 242], false, false, false, true,  false, false,    false,  false);
-        check(&[192, 0, 2, 183],     false, false, false, false, false, false,    false,  true);
-        check(&[192, 1, 2, 183],     false, false, false, false, true,  false,    false,  false);
-        check(&[192, 168, 254, 253], false, false, true,  false, false, false,    false,  false);
-        check(&[198, 51, 100, 0],    false, false, false, false, false, false,    false,  true);
-        check(&[203, 0, 113, 0],     false, false, false, false, false, false,    false,  true);
-        check(&[203, 2, 113, 0],     false, false, false, false, true,  false,    false,  false);
-        check(&[224, 0, 0, 0],       false, false, false, false, true,  true,     false,  false);
-        check(&[239, 255, 255, 255], false, false, false, false, true,  true,     false,  false);
-        check(&[255, 255, 255, 255], false, false, false, false, false, false,    true,   false);
+        check(&[0, 0, 0, 0],         true,  false, false, false, false,  false,    false,  false);
+        check(&[0, 0, 0, 1],         false, false, false, false, true,   false,    false,  false);
+        check(&[1, 0, 0, 0],         false, false, false, false, true,   false,    false,  false);
+        check(&[10, 9, 8, 7],        false, false, true,  false, false,  false,    false,  false);
+        check(&[127, 1, 2, 3],       false, true,  false, false, false,  false,    false,  false);
+        check(&[172, 31, 254, 253],  false, false, true,  false, false,  false,    false,  false);
+        check(&[169, 254, 253, 242], false, false, false, true,  false,  false,    false,  false);
+        check(&[192, 0, 2, 183],     false, false, false, false, false,  false,    false,  true);
+        check(&[192, 1, 2, 183],     false, false, false, false, true,   false,    false,  false);
+        check(&[192, 168, 254, 253], false, false, true,  false, false,  false,    false,  false);
+        check(&[198, 51, 100, 0],    false, false, false, false, false,  false,    false,  true);
+        check(&[203, 0, 113, 0],     false, false, false, false, false,  false,    false,  true);
+        check(&[203, 2, 113, 0],     false, false, false, false, true,   false,    false,  false);
+        check(&[224, 0, 0, 0],       false, false, false, false, true,   true,     false,  false);
+        check(&[239, 255, 255, 255], false, false, false, false, true,   true,     false,  false);
+        check(&[255, 255, 255, 255], false, false, false, false, false,  false,    true,   false);
     }
 
     #[test]
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index f8e3b58bb3e..414696413f4 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -14,7 +14,6 @@ use io::prelude::*;
 use fmt;
 use io;
 use net::{ToSocketAddrs, SocketAddr, Shutdown};
-use sys_common::io::read_to_end_uninitialized;
 use sys_common::net as net_imp;
 use sys_common::{AsInner, FromInner, IntoInner};
 use time::Duration;
@@ -269,7 +268,7 @@ impl TcpStream {
 impl Read for TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
+        self.0.read_to_end(buf)
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -281,7 +280,7 @@ impl Write for TcpStream {
 impl<'a> Read for &'a TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
+        self.0.read_to_end(buf)
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/os/emscripten/fs.rs b/src/libstd/os/emscripten/fs.rs
new file mode 100644
index 00000000000..8056ce4fdc4
--- /dev/null
+++ b/src/libstd/os/emscripten/fs.rs
@@ -0,0 +1,128 @@
+// 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.
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use libc;
+
+use fs::Metadata;
+use sys_common::AsInner;
+
+#[allow(deprecated)]
+use os::emscripten::raw;
+
+/// OS-specific extension methods for `fs::Metadata`
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Gain a reference to the underlying `stat` structure which contains
+    /// the raw information returned by the OS.
+    ///
+    /// The contents of the returned `stat` are **not** consistent across
+    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+    /// cross-Unix abstractions contained within the raw stat.
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    #[rustc_deprecated(since = "1.8.0",
+                       reason = "deprecated in favor of the accessor \
+                                 methods of this trait")]
+    #[allow(deprecated)]
+    fn as_raw_stat(&self) -> &raw::stat;
+
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mode(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    #[allow(deprecated)]
+    fn as_raw_stat(&self) -> &raw::stat {
+        unsafe {
+            &*(self.as_inner().as_inner() as *const libc::stat64
+                                          as *const raw::stat)
+        }
+    }
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atime as i64
+    }
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atime_nsec as i64
+    }
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime as i64
+    }
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime_nsec as i64
+    }
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime as i64
+    }
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime_nsec as i64
+    }
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+}
diff --git a/src/libstd/os/emscripten/mod.rs b/src/libstd/os/emscripten/mod.rs
new file mode 100644
index 00000000000..8ec44b9fae4
--- /dev/null
+++ b/src/libstd/os/emscripten/mod.rs
@@ -0,0 +1,16 @@
+// 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.
+
+//! Linux-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/emscripten/raw.rs b/src/libstd/os/emscripten/raw.rs
new file mode 100644
index 00000000000..9da400a6913
--- /dev/null
+++ b/src/libstd/os/emscripten/raw.rs
@@ -0,0 +1,80 @@
+// 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.
+
+//! Emscripten-specific raw type definitions
+//! This is basically exactly the same as the linux definitions,
+//! except using the musl-specific stat64 structure in liblibc.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(since = "1.8.0",
+                    reason = "these type aliases are no longer supported by \
+                              the standard library, the `libc` crate on \
+                              crates.io should be used instead for the correct \
+                              definitions")]
+#![allow(deprecated)]
+
+use os::raw::{c_long, c_short, c_uint, c_ulong};
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
+
+#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_dev: u64,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub __pad1: c_short,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub __st_ino: u32,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_mode: u32,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_nlink: u32,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_uid: u32,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_gid: u32,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_rdev: u64,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub __pad2: c_uint,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_size: i64,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_blksize: i32,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_blocks: i64,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_atime: time_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_atime_nsec: c_long,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_mtime: time_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_mtime_nsec: c_long,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_ctime: time_t,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_ctime_nsec: c_long,
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub st_ino: u64,
+}
diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs
index e15c8d67a8a..a91d251fc12 100644
--- a/src/libstd/os/mod.rs
+++ b/src/libstd/os/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! OS-specific functionality
+//! OS-specific functionality.
 
 #![stable(feature = "os", since = "1.0.0")]
 #![allow(missing_docs, bad_style)]
@@ -31,10 +31,6 @@ pub use sys::ext as windows;
 #[cfg(target_os = "netbsd")]   pub mod netbsd;
 #[cfg(target_os = "openbsd")]   pub mod openbsd;
 #[cfg(target_os = "solaris")]   pub mod solaris;
-
-// Emscripten is just like linux
-#[cfg(target_os = "emscripten")]
-#[path = "linux/mod.rs"]
-pub mod emscripten;
+#[cfg(target_os = "emscripten")] pub mod emscripten;
 
 pub mod raw;
diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs
index ebd299efa78..f4cd319f064 100644
--- a/src/libstd/prelude/mod.rs
+++ b/src/libstd/prelude/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! The Rust Prelude
+//! The Rust Prelude.
 //!
 //! Rust comes with a variety of things in its standard library. However, if
 //! you had to manually import every single thing that you used, it would be
diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
index 839287d1321..24e35b87bf2 100644
--- a/src/libstd/primitive_docs.rs
+++ b/src/libstd/primitive_docs.rs
@@ -370,7 +370,7 @@ mod prim_slice { }
 /// // story has nineteen bytes
 /// assert_eq!(19, len);
 ///
-/// // We can re-build a str out of ptr and len. This is all unsafe becuase
+/// // We can re-build a str out of ptr and len. This is all unsafe because
 /// // we are responsible for making sure the two components are valid:
 /// let s = unsafe {
 ///     // First, we build a &[u8]...
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 8db8ad324be..5813d82a315 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -20,10 +20,9 @@ use fmt;
 use io;
 use path::Path;
 use str;
-use sys::pipe::AnonPipe;
+use sys::pipe::{read2, AnonPipe};
 use sys::process as imp;
 use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-use thread::{self, JoinHandle};
 
 /// Representation of a running or exited child process.
 ///
@@ -134,6 +133,9 @@ impl Read for ChildStdout {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
 }
 
 impl AsInner<AnonPipe> for ChildStdout {
@@ -161,6 +163,9 @@ impl Read for ChildStderr {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
 }
 
 impl AsInner<AnonPipe> for ChildStderr {
@@ -289,7 +294,7 @@ impl Command {
     /// By default, stdin, stdout and stderr are inherited from the parent.
     #[stable(feature = "process", since = "1.0.0")]
     pub fn spawn(&mut self) -> io::Result<Child> {
-        self.inner.spawn(imp::Stdio::Inherit).map(Child::from_inner)
+        self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner)
     }
 
     /// Executes the command as a child process, waiting for it to finish and
@@ -312,7 +317,7 @@ impl Command {
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn output(&mut self) -> io::Result<Output> {
-        self.inner.spawn(imp::Stdio::MakePipe).map(Child::from_inner)
+        self.inner.spawn(imp::Stdio::MakePipe, false).map(Child::from_inner)
             .and_then(|p| p.wait_with_output())
     }
 
@@ -334,7 +339,8 @@ impl Command {
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn status(&mut self) -> io::Result<ExitStatus> {
-        self.spawn().and_then(|mut p| p.wait())
+        self.inner.spawn(imp::Stdio::Inherit, false).map(Child::from_inner)
+                  .and_then(|mut p| p.wait())
     }
 }
 
@@ -496,24 +502,29 @@ impl Child {
     #[stable(feature = "process", since = "1.0.0")]
     pub fn wait_with_output(mut self) -> io::Result<Output> {
         drop(self.stdin.take());
-        fn read<R>(mut input: R) -> JoinHandle<io::Result<Vec<u8>>>
-            where R: Read + Send + 'static
-        {
-            thread::spawn(move || {
-                let mut ret = Vec::new();
-                input.read_to_end(&mut ret).map(|_| ret)
-            })
+
+        let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
+        match (self.stdout.take(), self.stderr.take()) {
+            (None, None) => {}
+            (Some(mut out), None) => {
+                let res = out.read_to_end(&mut stdout);
+                res.unwrap();
+            }
+            (None, Some(mut err)) => {
+                let res = err.read_to_end(&mut stderr);
+                res.unwrap();
+            }
+            (Some(out), Some(err)) => {
+                let res = read2(out.inner, &mut stdout, err.inner, &mut stderr);
+                res.unwrap();
+            }
         }
-        let stdout = self.stdout.take().map(read);
-        let stderr = self.stderr.take().map(read);
-        let status = try!(self.wait());
-        let stdout = stdout.and_then(|t| t.join().unwrap().ok());
-        let stderr = stderr.and_then(|t| t.join().unwrap().ok());
 
+        let status = try!(self.wait());
         Ok(Output {
             status: status,
-            stdout: stdout.unwrap_or(Vec::new()),
-            stderr: stderr.unwrap_or(Vec::new()),
+            stdout: stdout,
+            stderr: stderr,
         })
     }
 }
diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs
index 9c9aa20eff5..1a42b091831 100644
--- a/src/libstd/sync/mod.rs
+++ b/src/libstd/sync/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Useful synchronization primitives
+//! Useful synchronization primitives.
 //!
 //! This module contains useful safe and unsafe synchronization primitives.
 //! Most of the primitives in this module do not provide any sort of locking
diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs
index 3f70afe6ad7..c1e9782852a 100644
--- a/src/libstd/sys/common/libunwind.rs
+++ b/src/libstd/sys/common/libunwind.rs
@@ -106,9 +106,15 @@ pub type _Unwind_Exception_Cleanup_Fn =
 #[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
                target_os = "freebsd",
                target_os = "solaris",
-               all(target_os = "linux", target_env = "musl", not(target_arch = "x86_64"))),
+               all(target_os = "linux",
+                   target_env = "musl",
+                   not(target_arch = "x86"),
+                   not(target_arch = "x86_64"))),
            link(name = "gcc_s"))]
-#[cfg_attr(all(target_os = "linux", target_env = "musl", target_arch = "x86_64", not(test)),
+#[cfg_attr(all(target_os = "linux",
+               target_env = "musl",
+               any(target_arch = "x86", target_arch = "x86_64"),
+               not(test)),
            link(name = "unwind", kind = "static"))]
 #[cfg_attr(any(target_os = "android", target_os = "openbsd"),
            link(name = "gcc"))]
diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs
index ca4f6e19882..aa92e5be114 100644
--- a/src/libstd/sys/common/net.rs
+++ b/src/libstd/sys/common/net.rs
@@ -225,6 +225,10 @@ impl TcpStream {
         self.inner.read(buf)
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
         let ret = try!(cvt(unsafe {
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index 299c6ec2731..8ec073858fd 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -8,12 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use io;
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use prelude::v1::*;
+
+use io::{self, Read};
 use libc::{self, c_int, size_t, c_void};
 use mem;
+use sync::atomic::{AtomicBool, Ordering};
 use sys::cvt;
 use sys_common::AsInner;
-use sync::atomic::{AtomicBool, Ordering};
+use sys_common::io::read_to_end_uninitialized;
 
 pub struct FileDesc {
     fd: c_int,
@@ -42,6 +47,11 @@ impl FileDesc {
         Ok(ret as usize)
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let ret = try!(cvt(unsafe {
             libc::write(self.fd,
@@ -67,6 +77,20 @@ impl FileDesc {
         }
     }
 
+    pub fn set_nonblocking(&self, nonblocking: bool) {
+        unsafe {
+            let previous = libc::fcntl(self.fd, libc::F_GETFL);
+            debug_assert!(previous != -1);
+            let new = if nonblocking {
+                previous | libc::O_NONBLOCK
+            } else {
+                previous & !libc::O_NONBLOCK
+            };
+            let ret = libc::fcntl(self.fd, libc::F_SETFL, new);
+            debug_assert!(ret != -1);
+        }
+    }
+
     pub fn duplicate(&self) -> io::Result<FileDesc> {
         // We want to atomically duplicate this file descriptor and set the
         // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
@@ -118,6 +142,16 @@ impl FileDesc {
     }
 }
 
+impl<'a> Read for &'a FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        unsafe { read_to_end_uninitialized(self, buf) }
+    }
+}
+
 impl AsInner<c_int> for FileDesc {
     fn as_inner(&self) -> &c_int { &self.fd }
 }
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 250b1b015a0..3985a07470e 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -25,15 +25,19 @@ use sys::time::SystemTime;
 use sys::{cvt, cvt_r};
 use sys_common::{AsInner, FromInner};
 
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "emscripten"))]
 use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64};
 #[cfg(target_os = "android")]
 use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off64_t, ftruncate64, lseek64,
            dirent as dirent64, open as open64};
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
+#[cfg(not(any(target_os = "linux",
+              target_os = "emscripten",
+              target_os = "android")))]
 use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
            ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
-#[cfg(not(any(target_os = "linux", target_os = "solaris")))]
+#[cfg(not(any(target_os = "linux",
+              target_os = "emscripten",
+              target_os = "solaris")))]
 use libc::{readdir_r as readdir64_r};
 
 pub struct File(FileDesc);
@@ -482,6 +486,10 @@ impl File {
         self.0.read(buf)
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index 8785da51986..acf501d5fda 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -116,6 +116,10 @@ impl Socket {
         self.0.read(buf)
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
     pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
         let timeout = match dur {
             Some(dur) => {
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index 667f0f9e6bf..e5cb3761001 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -8,8 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use prelude::v1::*;
+
+use cmp;
 use io;
 use libc::{self, c_int};
+use mem;
 use sys::cvt_r;
 use sys::fd::FileDesc;
 
@@ -57,6 +61,10 @@ impl AnonPipe {
         self.0.read(buf)
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
@@ -64,3 +72,54 @@ impl AnonPipe {
     pub fn fd(&self) -> &FileDesc { &self.0 }
     pub fn into_fd(self) -> FileDesc { self.0 }
 }
+
+pub fn read2(p1: AnonPipe,
+             v1: &mut Vec<u8>,
+             p2: AnonPipe,
+             v2: &mut Vec<u8>) -> io::Result<()> {
+    // Set both pipes into nonblocking mode as we're gonna be reading from both
+    // in the `select` loop below, and we wouldn't want one to block the other!
+    let p1 = p1.into_fd();
+    let p2 = p2.into_fd();
+    p1.set_nonblocking(true);
+    p2.set_nonblocking(true);
+
+    let max = cmp::max(p1.raw(), p2.raw());
+    loop {
+        // wait for either pipe to become readable using `select`
+        try!(cvt_r(|| unsafe {
+            let mut read: libc::fd_set = mem::zeroed();
+            libc::FD_SET(p1.raw(), &mut read);
+            libc::FD_SET(p2.raw(), &mut read);
+            libc::select(max + 1, &mut read, 0 as *mut _, 0 as *mut _,
+                         0 as *mut _)
+        }));
+
+        // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
+        // EAGAIN. If we hit EOF, then this will happen because the underlying
+        // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
+        // this case we flip the other fd back into blocking mode and read
+        // whatever's leftover on that file descriptor.
+        let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
+            match fd.read_to_end(dst) {
+                Ok(_) => Ok(true),
+                Err(e) => {
+                    if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
+                       e.raw_os_error() == Some(libc::EAGAIN) {
+                        Ok(false)
+                    } else {
+                        Err(e)
+                    }
+                }
+            }
+        };
+        if try!(read(&p1, v1)) {
+            p2.set_nonblocking(false);
+            return p2.read_to_end(v2).map(|_| ());
+        }
+        if try!(read(&p2, v2)) {
+            p1.set_nonblocking(false);
+            return p1.read_to_end(v1).map(|_| ());
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs
index 28475f50ce6..47b0ff42f93 100644
--- a/src/libstd/sys/unix/process.rs
+++ b/src/libstd/sys/unix/process.rs
@@ -216,7 +216,7 @@ impl Command {
         self.stderr = Some(stderr);
     }
 
-    pub fn spawn(&mut self, default: Stdio)
+    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                  -> io::Result<(Process, StdioPipes)> {
         const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
 
@@ -225,7 +225,7 @@ impl Command {
                                       "nul byte found in provided data"));
         }
 
-        let (ours, theirs) = try!(self.setup_io(default));
+        let (ours, theirs) = try!(self.setup_io(default, needs_stdin));
         let (input, output) = try!(sys::pipe::anon_pipe());
 
         let pid = unsafe {
@@ -298,7 +298,7 @@ impl Command {
                                   "nul byte found in provided data")
         }
 
-        match self.setup_io(default) {
+        match self.setup_io(default, true) {
             Ok((_, theirs)) => unsafe { self.do_exec(theirs) },
             Err(e) => e,
         }
@@ -408,8 +408,11 @@ impl Command {
     }
 
 
-    fn setup_io(&self, default: Stdio) -> io::Result<(StdioPipes, ChildPipes)> {
-        let stdin = self.stdin.as_ref().unwrap_or(&default);
+    fn setup_io(&self, default: Stdio, needs_stdin: bool)
+                -> io::Result<(StdioPipes, ChildPipes)> {
+        let null = Stdio::Null;
+        let default_stdin = if needs_stdin {&default} else {&null};
+        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
         let stdout = self.stdout.as_ref().unwrap_or(&default);
         let stderr = self.stderr.as_ref().unwrap_or(&default);
         let (their_stdin, our_stdin) = try!(stdin.to_child_stdio(true));
@@ -648,7 +651,7 @@ mod tests {
             cmd.stdin(Stdio::MakePipe);
             cmd.stdout(Stdio::MakePipe);
 
-            let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null));
+            let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
             let stdin_write = pipes.stdin.take().unwrap();
             let stdout_read = pipes.stdout.take().unwrap();
 
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
index ccbb14677c7..37d1d9a969e 100644
--- a/src/libstd/sys/unix/stdio.rs
+++ b/src/libstd/sys/unix/stdio.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use prelude::v1::*;
+
 use io;
 use libc;
 use sys::fd::FileDesc;
@@ -25,6 +27,13 @@ impl Stdin {
         fd.into_raw();
         ret
     }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let fd = FileDesc::new(libc::STDIN_FILENO);
+        let ret = fd.read_to_end(buf);
+        fd.into_raw();
+        ret
+    }
 }
 
 impl Stdout {
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 472ffdf9e1d..002ffc7c868 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -12,6 +12,7 @@
 
 #![allow(bad_style)]
 #![cfg_attr(test, allow(dead_code))]
+#![unstable(issue = "0", feature = "windows_c")]
 
 use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort,};
 use os::raw::{c_char, c_ulonglong};
@@ -181,6 +182,7 @@ pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
 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_BROKEN_PIPE: DWORD = 109;
 pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
 pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;
@@ -188,6 +190,7 @@ pub const ERROR_ALREADY_EXISTS: DWORD = 183;
 pub const ERROR_NO_DATA: DWORD = 232;
 pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203;
 pub const ERROR_OPERATION_ABORTED: DWORD = 995;
+pub const ERROR_IO_PENDING: DWORD = 997;
 pub const ERROR_TIMEOUT: DWORD = 0x5B4;
 
 pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
@@ -292,6 +295,14 @@ pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
                                     EXCEPTION_TARGET_UNWIND |
                                     EXCEPTION_COLLIDED_UNWIND;
 
+pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
+pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
+pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000;
+pub const PIPE_WAIT: DWORD = 0x00000000;
+pub const PIPE_TYPE_BYTE: DWORD = 0x00000000;
+pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008;
+pub const PIPE_READMODE_BYTE: DWORD = 0x00000000;
+
 #[repr(C)]
 #[cfg(target_arch = "x86")]
 pub struct WSADATA {
@@ -913,10 +924,6 @@ extern "system" {
                            nOutBufferSize: DWORD,
                            lpBytesReturned: LPDWORD,
                            lpOverlapped: LPOVERLAPPED) -> BOOL;
-    pub fn CreatePipe(hReadPipe: LPHANDLE,
-                      hWritePipe: LPHANDLE,
-                      lpPipeAttributes: LPSECURITY_ATTRIBUTES,
-                      nSize: DWORD) -> BOOL;
     pub fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
                         dwStackSize: SIZE_T,
                         lpStartAddress: extern "system" fn(*mut c_void)
@@ -1129,6 +1136,29 @@ extern "system" {
                        OriginalContext: *const CONTEXT,
                        HistoryTable: *const UNWIND_HISTORY_TABLE);
     pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
+
+    pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
+                        bManualReset: BOOL,
+                        bInitialState: BOOL,
+                        lpName: LPCWSTR) -> HANDLE;
+    pub fn WaitForMultipleObjects(nCount: DWORD,
+                                  lpHandles: *const HANDLE,
+                                  bWaitAll: BOOL,
+                                  dwMilliseconds: DWORD) -> DWORD;
+    pub fn CreateNamedPipeW(lpName: LPCWSTR,
+                            dwOpenMode: DWORD,
+                            dwPipeMode: DWORD,
+                            nMaxInstances: DWORD,
+                            nOutBufferSize: DWORD,
+                            nInBufferSize: DWORD,
+                            nDefaultTimeOut: DWORD,
+                            lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
+                            -> HANDLE;
+    pub fn CancelIo(handle: HANDLE) -> BOOL;
+    pub fn GetOverlappedResult(hFile: HANDLE,
+                               lpOverlapped: LPOVERLAPPED,
+                               lpNumberOfBytesTransferred: LPDWORD,
+                               bWait: BOOL) -> BOOL;
 }
 
 // Functions that aren't available on Windows XP, but we still use them and just
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 95fb1e7c600..624fef097fc 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use prelude::v1::*;
 use io::prelude::*;
 use os::windows::prelude::*;
 
@@ -312,6 +313,10 @@ impl File {
         self.handle.read(buf)
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.handle.read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.handle.write(buf)
     }
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
index 47676a927f6..1396d670902 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -8,14 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![unstable(issue = "0", feature = "windows_handle")]
+
+use prelude::v1::*;
+
 use cmp;
-use io::ErrorKind;
+use io::{ErrorKind, Read};
 use io;
 use mem;
 use ops::Deref;
 use ptr;
 use sys::c;
 use sys::cvt;
+use sys_common::io::read_to_end_uninitialized;
 use u32;
 
 /// An owned container for `HANDLE` object, closing them on Drop.
@@ -39,6 +44,20 @@ impl Handle {
         Handle(RawHandle::new(handle))
     }
 
+    pub fn new_event(manual: bool, init: bool) -> io::Result<Handle> {
+        unsafe {
+            let event = c::CreateEventW(0 as *mut _,
+                                        manual as c::BOOL,
+                                        init as c::BOOL,
+                                        0 as *const _);
+            if event.is_null() {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(Handle::new(event))
+            }
+        }
+    }
+
     pub fn into_raw(self) -> c::HANDLE {
         let ret = self.raw();
         mem::forget(self);
@@ -87,6 +106,64 @@ impl RawHandle {
         }
     }
 
+    pub unsafe fn read_overlapped(&self,
+                                  buf: &mut [u8],
+                                  overlapped: *mut c::OVERLAPPED)
+                                  -> io::Result<Option<usize>> {
+        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        let mut amt = 0;
+        let res = cvt({
+            c::ReadFile(self.0, buf.as_ptr() as c::LPVOID,
+                        len, &mut amt, overlapped)
+        });
+        match res {
+            Ok(_) => Ok(Some(amt as usize)),
+            Err(e) => {
+                if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) {
+                    Ok(None)
+                } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) {
+                    Ok(Some(0))
+                } else {
+                    Err(e)
+                }
+            }
+        }
+    }
+
+    pub fn overlapped_result(&self,
+                             overlapped: *mut c::OVERLAPPED,
+                             wait: bool) -> io::Result<usize> {
+        unsafe {
+            let mut bytes = 0;
+            let wait = if wait {c::TRUE} else {c::FALSE};
+            let res = cvt({
+                c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait)
+            });
+            match res {
+                Ok(_) => Ok(bytes as usize),
+                Err(e) => {
+                    if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) ||
+                       e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) {
+                        Ok(0)
+                    } else {
+                        Err(e)
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn cancel_io(&self) -> io::Result<()> {
+        unsafe {
+            cvt(c::CancelIo(self.raw())).map(|_| ())
+        }
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let mut amt = 0;
         // WriteFile takes a DWORD (u32) for the length so it only supports
@@ -111,3 +188,13 @@ impl RawHandle {
         Ok(Handle::new(ret))
     }
 }
+
+impl<'a> Read for &'a RawHandle {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        unsafe { read_to_end_uninitialized(self, buf) }
+    }
+}
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
index dfa44a651e6..bb3c79c5a84 100644
--- a/src/libstd/sys/windows/net.rs
+++ b/src/libstd/sys/windows/net.rs
@@ -8,8 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![unstable(issue = "0", feature = "windows_net")]
+
+use prelude::v1::*;
+
 use cmp;
-use io;
+use io::{self, Read};
 use libc::{c_int, c_void, c_ulong};
 use mem;
 use net::{SocketAddr, Shutdown};
@@ -20,6 +24,7 @@ use sync::Once;
 use sys::c;
 use sys;
 use sys_common::{self, AsInner, FromInner, IntoInner};
+use sys_common::io::read_to_end_uninitialized;
 use sys_common::net;
 use time::Duration;
 
@@ -142,6 +147,11 @@ impl Socket {
         }
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+
     pub fn set_timeout(&self, dur: Option<Duration>,
                        kind: c_int) -> io::Result<()> {
         let timeout = match dur {
@@ -206,6 +216,17 @@ impl Socket {
     }
 }
 
+#[unstable(reason = "not public", issue = "0", feature = "fd_read")]
+impl<'a> Read for &'a Socket {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        unsafe { read_to_end_uninitialized(self, buf) }
+    }
+}
+
 impl Drop for Socket {
     fn drop(&mut self) {
         let _ = unsafe { c::closesocket(self.0) };
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index aec41885f3b..fbe38d76e95 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -8,10 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use prelude::v1::*;
+use os::windows::prelude::*;
+
+use ffi::OsStr;
+use path::Path;
 use io;
-use ptr;
-use sys::cvt;
+use mem;
+use rand::{self, Rng};
+use slice;
 use sys::c;
+use sys::fs::{File, OpenOptions};
 use sys::handle::Handle;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -23,14 +30,76 @@ pub struct AnonPipe {
 }
 
 pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
-    let mut reader = c::INVALID_HANDLE_VALUE;
-    let mut writer = c::INVALID_HANDLE_VALUE;
-    try!(cvt(unsafe {
-        c::CreatePipe(&mut reader, &mut writer, ptr::null_mut(), 0)
-    }));
-    let reader = Handle::new(reader);
-    let writer = Handle::new(writer);
-    Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer }))
+    // Note that we specifically do *not* use `CreatePipe` here because
+    // unfortunately the anonymous pipes returned do not support overlapped
+    // operations.
+    //
+    // Instead, we create a "hopefully unique" name and create a named pipe
+    // which has overlapped operations enabled.
+    //
+    // Once we do this, we connect do it as usual via `CreateFileW`, and then we
+    // return those reader/writer halves.
+    unsafe {
+        let reader;
+        let mut name;
+        let mut tries = 0;
+        loop {
+            tries += 1;
+            let key: u64 = rand::thread_rng().gen();
+            name = format!(r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}",
+                           c::GetCurrentProcessId(),
+                           key);
+            let wide_name = OsStr::new(&name)
+                                  .encode_wide()
+                                  .chain(Some(0))
+                                  .collect::<Vec<_>>();
+
+            let handle = c::CreateNamedPipeW(wide_name.as_ptr(),
+                                             c::PIPE_ACCESS_INBOUND |
+                                              c::FILE_FLAG_FIRST_PIPE_INSTANCE |
+                                              c::FILE_FLAG_OVERLAPPED,
+                                             c::PIPE_TYPE_BYTE |
+                                              c::PIPE_READMODE_BYTE |
+                                              c::PIPE_WAIT |
+                                              c::PIPE_REJECT_REMOTE_CLIENTS,
+                                             1,
+                                             4096,
+                                             4096,
+                                             0,
+                                             0 as *mut _);
+
+            // We pass the FILE_FLAG_FIRST_PIPE_INSTANCE flag above, and we're
+            // also just doing a best effort at selecting a unique name. If
+            // ERROR_ACCESS_DENIED is returned then it could mean that we
+            // accidentally conflicted with an already existing pipe, so we try
+            // again.
+            //
+            // Don't try again too much though as this could also perhaps be a
+            // legit error.
+            if handle == c::INVALID_HANDLE_VALUE {
+                let err = io::Error::last_os_error();
+                if tries < 10 &&
+                   err.raw_os_error() == Some(c::ERROR_ACCESS_DENIED as i32) {
+                    continue
+                }
+                return Err(err)
+            }
+            reader = Handle::new(handle);
+            break
+        }
+
+        // Connect to the named pipe we just created in write-only mode (also
+        // overlapped for async I/O below).
+        let mut opts = OpenOptions::new();
+        opts.write(true);
+        opts.read(false);
+        opts.share_mode(0);
+        opts.attributes(c::FILE_FLAG_OVERLAPPED);
+        let writer = try!(File::open(Path::new(&name), &opts));
+        let writer = AnonPipe { inner: writer.into_handle() };
+
+        Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer.into_handle() }))
+    }
 }
 
 impl AnonPipe {
@@ -41,7 +110,193 @@ impl AnonPipe {
         self.inner.read(buf)
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.inner.write(buf)
     }
 }
+
+pub fn read2(p1: AnonPipe,
+             v1: &mut Vec<u8>,
+             p2: AnonPipe,
+             v2: &mut Vec<u8>) -> io::Result<()> {
+    let p1 = p1.into_handle();
+    let p2 = p2.into_handle();
+
+    let mut p1 = try!(AsyncPipe::new(p1, v1));
+    let mut p2 = try!(AsyncPipe::new(p2, v2));
+    let objs = [p1.event.raw(), p2.event.raw()];
+
+    // In a loop we wait for either pipe's scheduled read operation to complete.
+    // If the operation completes with 0 bytes, that means EOF was reached, in
+    // which case we just finish out the other pipe entirely.
+    //
+    // Note that overlapped I/O is in general super unsafe because we have to
+    // be careful to ensure that all pointers in play are valid for the entire
+    // duration of the I/O operation (where tons of operations can also fail).
+    // The destructor for `AsyncPipe` ends up taking care of most of this.
+    loop {
+        let res = unsafe {
+            c::WaitForMultipleObjects(2, objs.as_ptr(), c::FALSE, c::INFINITE)
+        };
+        if res == c::WAIT_OBJECT_0 {
+            if !try!(p1.result()) || !try!(p1.schedule_read()) {
+                return p2.finish()
+            }
+        } else if res == c::WAIT_OBJECT_0 + 1 {
+            if !try!(p2.result()) || !try!(p2.schedule_read()) {
+                return p1.finish()
+            }
+        } else {
+            return Err(io::Error::last_os_error())
+        }
+    }
+}
+
+struct AsyncPipe<'a> {
+    pipe: Handle,
+    event: Handle,
+    overlapped: Box<c::OVERLAPPED>, // needs a stable address
+    dst: &'a mut Vec<u8>,
+    state: State,
+}
+
+#[derive(PartialEq, Debug)]
+enum State {
+    NotReading,
+    Reading,
+    Read(usize),
+}
+
+impl<'a> AsyncPipe<'a> {
+    fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> {
+        // Create an event which we'll use to coordinate our overlapped
+        // opreations, this event will be used in WaitForMultipleObjects
+        // and passed as part of the OVERLAPPED handle.
+        //
+        // Note that we do a somewhat clever thing here by flagging the
+        // event as being manually reset and setting it initially to the
+        // signaled state. This means that we'll naturally fall through the
+        // WaitForMultipleObjects call above for pipes created initially,
+        // and the only time an even will go back to "unset" will be once an
+        // I/O operation is successfully scheduled (what we want).
+        let event = try!(Handle::new_event(true, true));
+        let mut overlapped: Box<c::OVERLAPPED> = unsafe {
+            Box::new(mem::zeroed())
+        };
+        overlapped.hEvent = event.raw();
+        Ok(AsyncPipe {
+            pipe: pipe,
+            overlapped: overlapped,
+            event: event,
+            dst: dst,
+            state: State::NotReading,
+        })
+    }
+
+    /// Executes an overlapped read operation.
+    ///
+    /// Must not currently be reading, and returns whether the pipe is currently
+    /// at EOF or not. If the pipe is not at EOF then `result()` must be called
+    /// to complete the read later on (may block), but if the pipe is at EOF
+    /// then `result()` should not be called as it will just block forever.
+    fn schedule_read(&mut self) -> io::Result<bool> {
+        assert_eq!(self.state, State::NotReading);
+        let amt = unsafe {
+            let slice = slice_to_end(self.dst);
+            try!(self.pipe.read_overlapped(slice, &mut *self.overlapped))
+        };
+
+        // If this read finished immediately then our overlapped event will
+        // remain signaled (it was signaled coming in here) and we'll progress
+        // down to the method below.
+        //
+        // Otherwise the I/O operation is scheduled and the system set our event
+        // to not signaled, so we flag ourselves into the reading state and move
+        // on.
+        self.state = match amt {
+            Some(0) => return Ok(false),
+            Some(amt) => State::Read(amt),
+            None => State::Reading,
+        };
+        Ok(true)
+    }
+
+    /// Wait for the result of the overlapped operation previously executed.
+    ///
+    /// Takes a parameter `wait` which indicates if this pipe is currently being
+    /// read whether the function should block waiting for the read to complete.
+    ///
+    /// Return values:
+    ///
+    /// * `true` - finished any pending read and the pipe is not at EOF (keep
+    ///            going)
+    /// * `false` - finished any pending read and pipe is at EOF (stop issuing
+    ///             reads)
+    fn result(&mut self) -> io::Result<bool> {
+        let amt = match self.state {
+            State::NotReading => return Ok(true),
+            State::Reading => {
+                try!(self.pipe.overlapped_result(&mut *self.overlapped, true))
+            }
+            State::Read(amt) => amt,
+        };
+        self.state = State::NotReading;
+        unsafe {
+            let len = self.dst.len();
+            self.dst.set_len(len + amt);
+        }
+        Ok(amt != 0)
+    }
+
+    /// Finishes out reading this pipe entirely.
+    ///
+    /// Waits for any pending and schedule read, and then calls `read_to_end`
+    /// if necessary to read all the remaining information.
+    fn finish(&mut self) -> io::Result<()> {
+        while try!(self.result()) && try!(self.schedule_read()) {
+            // ...
+        }
+        Ok(())
+    }
+}
+
+impl<'a> Drop for AsyncPipe<'a> {
+    fn drop(&mut self) {
+        match self.state {
+            State::Reading => {}
+            _ => return,
+        }
+
+        // If we have a pending read operation, then we have to make sure that
+        // it's *done* before we actually drop this type. The kernel requires
+        // that the `OVERLAPPED` and buffer pointers are valid for the entire
+        // I/O operation.
+        //
+        // To do that, we call `CancelIo` to cancel any pending operation, and
+        // if that succeeds we wait for the overlapped result.
+        //
+        // If anything here fails, there's not really much we can do, so we leak
+        // the buffer/OVERLAPPED pointers to ensure we're at least memory safe.
+        if self.pipe.cancel_io().is_err() || self.result().is_err() {
+            let buf = mem::replace(self.dst, Vec::new());
+            let overlapped = Box::new(unsafe { mem::zeroed() });
+            let overlapped = mem::replace(&mut self.overlapped, overlapped);
+            mem::forget((buf, overlapped));
+        }
+    }
+}
+
+unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
+    if v.capacity() == 0 {
+        v.reserve(16);
+    }
+    if v.capacity() == v.len() {
+        v.reserve(1);
+    }
+    slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize),
+                              v.capacity() - v.len())
+}
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index fa118be6fe6..524c932eed4 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -123,7 +123,7 @@ impl Command {
         self.stderr = Some(stderr);
     }
 
-    pub fn spawn(&mut self, default: Stdio)
+    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                  -> io::Result<(Process, StdioPipes)> {
         // To have the spawning semantics of unix/windows stay the same, we need
         // to read the *child's* PATH if one is provided. See #15149 for more
@@ -181,7 +181,9 @@ impl Command {
             stdout: None,
             stderr: None,
         };
-        let stdin = self.stdin.as_ref().unwrap_or(&default);
+        let null = Stdio::Null;
+        let default_stdin = if needs_stdin {&default} else {&null};
+        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
         let stdout = self.stdout.as_ref().unwrap_or(&default);
         let stderr = self.stderr.as_ref().unwrap_or(&default);
         let stdin = try!(stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin));
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index 1cd05b61d25..5883904c21d 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![unstable(issue = "0", feature = "windows_stdio")]
+
 use prelude::v1::*;
 use io::prelude::*;
 
@@ -18,6 +20,7 @@ use sync::Mutex;
 use sys::c;
 use sys::cvt;
 use sys::handle::Handle;
+use sys_common::io::read_to_end_uninitialized;
 
 pub struct NoClose(Option<Handle>);
 
@@ -113,6 +116,22 @@ impl Stdin {
         // MemReader shouldn't error here since we just filled it
         utf8.read(buf)
     }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+}
+
+#[unstable(reason = "not public", issue = "0", feature = "fd_read")]
+impl<'a> Read for &'a Stdin {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        unsafe { read_to_end_uninitialized(self, buf) }
+    }
 }
 
 impl Stdout {
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 981ba1e36e9..6a923c8c094 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Native threads
+//! Native threads.
 //!
 //! ## The threading model
 //!
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 23bb6fd141a..a8bea2da833 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -458,7 +458,7 @@ pub struct WhereEqPredicate {
 
 /// The set of MetaItems that define the compilation environment of the crate,
 /// used to drive conditional compilation
-pub type CrateConfig = Vec<P<MetaItem>> ;
+pub type CrateConfig = Vec<P<MetaItem>>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Crate {
@@ -886,6 +886,15 @@ impl fmt::Debug for Expr {
     }
 }
 
+/// Limit types of a range (inclusive or exclusive)
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum RangeLimits {
+    /// Inclusive at the beginning, exclusive at the end
+    HalfOpen,
+    /// Inclusive at the beginning and end
+    Closed,
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum ExprKind {
     /// A `box x` expression.
@@ -974,8 +983,8 @@ pub enum ExprKind {
     TupField(P<Expr>, Spanned<usize>),
     /// An indexing operation (`foo[2]`)
     Index(P<Expr>, P<Expr>),
-    /// A range (`1..2`, `1..`, or `..2`)
-    Range(Option<P<Expr>>, Option<P<Expr>>),
+    /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`)
+    Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
 
     /// Variable reference, possibly containing `::` and/or type
     /// parameters, e.g. foo::bar::<baz>.
@@ -1013,6 +1022,9 @@ pub enum ExprKind {
 
     /// No-op: used solely so we can pretty-print faithfully
     Paren(P<Expr>),
+
+    /// `expr?`
+    Try(P<Expr>),
 }
 
 /// The explicit Self type in a "qualified path". The actual
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index e8098cfff45..f5794f7219b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1519,7 +1519,7 @@ mod tests {
         let crate_ast = parse::parse_crate_from_source_str(
             "<test>".to_string(),
             src,
-            Vec::new(), &sess);
+            Vec::new(), &sess).unwrap();
         // should fail:
         let mut gated_cfgs = vec![];
         let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
@@ -1535,7 +1535,7 @@ mod tests {
         let crate_ast = parse::parse_crate_from_source_str(
             "<test>".to_string(),
             src,
-            Vec::new(), &sess);
+            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);
@@ -1549,7 +1549,7 @@ mod tests {
         let crate_ast = parse::parse_crate_from_source_str(
             "<test>".to_string(),
             src,
-            Vec::new(), &sess);
+            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);
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index d0eaa89e4ae..38da478b5ed 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -18,12 +18,12 @@ use parse::token::*;
 use parse::token;
 use ptr::P;
 
-///  Quasiquoting works via token trees.
+/// Quasiquoting works via token trees.
 ///
-///  This is registered as a set of expression syntax extension called quote!
-///  that lifts its argument token-tree to an AST representing the
-///  construction of the same token tree, with token::SubstNt interpreted
-///  as antiquotes (splices).
+/// This is registered as a set of expression syntax extension called quote!
+/// that lifts its argument token-tree to an AST representing the
+/// construction of the same token tree, with token::SubstNt interpreted
+/// as antiquotes (splices).
 
 pub mod rt {
     use ast;
@@ -319,34 +319,36 @@ pub mod rt {
     }
 
     impl<'a> ExtParseUtils for ExtCtxt<'a> {
-
         fn parse_item(&self, s: String) -> P<ast::Item> {
-            parse::parse_item_from_source_str(
+            panictry!(parse::parse_item_from_source_str(
                 "<quote expansion>".to_string(),
                 s,
                 self.cfg(),
-                self.parse_sess()).expect("parse error")
+                self.parse_sess())).expect("parse error")
         }
 
         fn parse_stmt(&self, s: String) -> ast::Stmt {
-            parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
-                                              s,
-                                              self.cfg(),
-                                              self.parse_sess()).expect("parse error")
+            panictry!(parse::parse_stmt_from_source_str(
+                "<quote expansion>".to_string(),
+                s,
+                self.cfg(),
+                self.parse_sess())).expect("parse error")
         }
 
         fn parse_expr(&self, s: String) -> P<ast::Expr> {
-            parse::parse_expr_from_source_str("<quote expansion>".to_string(),
-                                              s,
-                                              self.cfg(),
-                                              self.parse_sess())
+            panictry!(parse::parse_expr_from_source_str(
+                "<quote expansion>".to_string(),
+                s,
+                self.cfg(),
+                self.parse_sess()))
         }
 
         fn parse_tts(&self, s: String) -> Vec<TokenTree> {
-            parse::parse_tts_from_source_str("<quote expansion>".to_string(),
-                                             s,
-                                             self.cfg(),
-                                             self.parse_sess())
+            panictry!(parse::parse_tts_from_source_str(
+                "<quote expansion>".to_string(),
+                s,
+                self.cfg(),
+                self.parse_sess()))
         }
     }
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 3f2fb2d3d17..14a3f93738a 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -241,7 +241,13 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
     ("cfg_target_thread_local", "1.7.0", Some(29594), Active),
 
     // rustc internal
-    ("abi_vectorcall", "1.7.0", None, Active)
+    ("abi_vectorcall", "1.7.0", None, Active),
+
+    // a...b and ...b
+    ("inclusive_range_syntax", "1.7.0", Some(28237), Active),
+
+    // `expr?`
+    ("question_mark", "1.9.0", Some(31436), Active)
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -549,6 +555,7 @@ pub struct Features {
     pub allow_placement_in: bool,
     pub allow_box: bool,
     pub allow_pushpop_unsafe: bool,
+    pub allow_inclusive_range: bool,
     pub simd_ffi: bool,
     pub unmarked_api: bool,
     /// spans of #![feature] attrs for stable language features. for error reporting
@@ -566,6 +573,7 @@ pub struct Features {
     pub staged_api: bool,
     pub stmt_expr_attributes: bool,
     pub deprecated: bool,
+    pub question_mark: bool,
 }
 
 impl Features {
@@ -583,6 +591,7 @@ impl Features {
             allow_placement_in: false,
             allow_box: false,
             allow_pushpop_unsafe: false,
+            allow_inclusive_range: false,
             simd_ffi: false,
             unmarked_api: false,
             declared_stable_lang_features: Vec::new(),
@@ -598,6 +607,7 @@ impl Features {
             staged_api: false,
             stmt_expr_attributes: false,
             deprecated: false,
+            question_mark: false,
         }
     }
 }
@@ -991,6 +1001,14 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                 self.gate_feature("type_ascription", e.span,
                                   "type ascription is experimental");
             }
+            ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
+                self.gate_feature("inclusive_range_syntax",
+                                  e.span,
+                                  "inclusive range syntax is experimental");
+            }
+            ast::ExprKind::Try(..) => {
+                self.gate_feature("question_mark", e.span, "the `?` operator is not stable");
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
@@ -1177,6 +1195,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
         allow_placement_in: cx.has_feature("placement_in_syntax"),
         allow_box: cx.has_feature("box_syntax"),
         allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
+        allow_inclusive_range: cx.has_feature("inclusive_range_syntax"),
         simd_ffi: cx.has_feature("simd_ffi"),
         unmarked_api: cx.has_feature("unmarked_api"),
         declared_stable_lang_features: accepted_features,
@@ -1192,6 +1211,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
         staged_api: cx.has_feature("staged_api"),
         stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
         deprecated: cx.has_feature("deprecated"),
+        question_mark: cx.has_feature("question_mark"),
     }
 }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index d75e8f796ae..9056103d300 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1273,9 +1273,10 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
             ExprKind::Index(el, er) => {
                 ExprKind::Index(folder.fold_expr(el), folder.fold_expr(er))
             }
-            ExprKind::Range(e1, e2) => {
+            ExprKind::Range(e1, e2, lim) => {
                 ExprKind::Range(e1.map(|x| folder.fold_expr(x)),
-                          e2.map(|x| folder.fold_expr(x)))
+                                e2.map(|x| folder.fold_expr(x)),
+                                lim)
             }
             ExprKind::Path(qself, path) => {
                 let qself = qself.map(|QSelf { ty, position }| {
@@ -1331,7 +1332,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                         fields.move_map(|x| folder.fold_field(x)),
                         maybe_expr.map(|x| folder.fold_expr(x)))
             },
-            ExprKind::Paren(ex) => ExprKind::Paren(folder.fold_expr(ex))
+            ExprKind::Paren(ex) => ExprKind::Paren(folder.fold_expr(ex)),
+            ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)),
         },
         span: folder.new_span(span),
         attrs: attrs.map_thin_attrs(|v| fold_attrs(v, folder)),
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index d7d3e576a61..04a3cf096ba 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -38,6 +38,7 @@ extern crate term;
 extern crate libc;
 #[macro_use] extern crate log;
 #[macro_use] #[no_link] extern crate rustc_bitflags;
+extern crate rustc_unicode;
 
 extern crate serialize as rustc_serialize; // used by deriving
 
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index e336c98f03c..629edced804 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -15,7 +15,7 @@ use codemap::{BytePos, CharPos, CodeMap, Pos};
 use errors;
 use parse::lexer::is_block_doc_comment;
 use parse::lexer::{StringReader, TokenAndSpan};
-use parse::lexer::{is_whitespace, Reader};
+use parse::lexer::{is_pattern_whitespace, Reader};
 use parse::lexer;
 use print::pprust;
 use str::char_at;
@@ -153,7 +153,7 @@ fn push_blank_line_comment(rdr: &StringReader, comments: &mut Vec<Comment>) {
 }
 
 fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader, comments: &mut Vec<Comment>) {
-    while is_whitespace(rdr.curr) && !rdr.is_eof() {
+    while is_pattern_whitespace(rdr.curr) && !rdr.is_eof() {
         if rdr.col == CharPos(0) && rdr.curr_is('\n') {
             push_blank_line_comment(rdr, &mut *comments);
         }
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 3183dfbd954..a5cb5c7117e 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -16,6 +16,7 @@ use ext::tt::transcribe::tt_next_token;
 use parse::token::str_to_ident;
 use parse::token;
 use str::char_at;
+use rustc_unicode::property::Pattern_White_Space;
 
 use std::borrow::Cow;
 use std::char;
@@ -546,10 +547,10 @@ impl<'a> StringReader<'a> {
                 let c = self.scan_comment();
                 debug!("scanning a comment {:?}", c);
                 c
-            }
-            c if is_whitespace(Some(c)) => {
+            },
+            c if is_pattern_whitespace(Some(c)) => {
                 let start_bpos = self.last_pos;
-                while is_whitespace(self.curr) {
+                while is_pattern_whitespace(self.curr) {
                     self.bump();
                 }
                 let c = Some(TokenAndSpan {
@@ -1440,7 +1441,7 @@ impl<'a> StringReader<'a> {
     }
 
     fn consume_whitespace(&mut self) {
-        while is_whitespace(self.curr) && !self.is_eof() {
+        while is_pattern_whitespace(self.curr) && !self.is_eof() {
             self.bump();
         }
     }
@@ -1465,7 +1466,7 @@ impl<'a> StringReader<'a> {
     }
 
     fn consume_non_eol_whitespace(&mut self) {
-        while is_whitespace(self.curr) && !self.curr_is('\n') && !self.is_eof() {
+        while is_pattern_whitespace(self.curr) && !self.curr_is('\n') && !self.is_eof() {
             self.bump();
         }
     }
@@ -1596,11 +1597,10 @@ impl<'a> StringReader<'a> {
     }
 }
 
-pub fn is_whitespace(c: Option<char>) -> bool {
-    match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
-        ' ' | '\n' | '\t' | '\r' => true,
-        _ => false,
-    }
+// This tests the character for the unicode property 'PATTERN_WHITE_SPACE' which
+// is guaranteed to be forward compatible. http://unicode.org/reports/tr31/#R3
+pub fn is_pattern_whitespace(c: Option<char>) -> bool {
+    c.map_or(false, Pattern_White_Space)
 }
 
 fn in_range(c: Option<char>, lo: char, hi: char) -> bool {
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 1ec2479058c..ea5d6739e6d 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -71,95 +71,97 @@ impl ParseSess {
 // uses a HOF to parse anything, and <source> includes file and
 // source_str.
 
-pub fn parse_crate_from_file(
-    input: &Path,
-    cfg: ast::CrateConfig,
-    sess: &ParseSess
-) -> ast::Crate {
+pub fn parse_crate_from_file<'a>(input: &Path,
+                                 cfg: ast::CrateConfig,
+                                 sess: &'a ParseSess)
+                                 -> PResult<'a, ast::Crate> {
     let mut parser = new_parser_from_file(sess, cfg, input);
-    abort_if_errors(parser.parse_crate_mod(), &parser)
+    parser.parse_crate_mod()
 }
 
-pub fn parse_crate_attrs_from_file(
-    input: &Path,
-    cfg: ast::CrateConfig,
-    sess: &ParseSess
-) -> Vec<ast::Attribute> {
+pub fn parse_crate_attrs_from_file<'a>(input: &Path,
+                                       cfg: ast::CrateConfig,
+                                       sess: &'a ParseSess)
+                                       -> PResult<'a, Vec<ast::Attribute>> {
     let mut parser = new_parser_from_file(sess, cfg, input);
-    abort_if_errors(parser.parse_inner_attributes(), &parser)
+    parser.parse_inner_attributes()
 }
 
-pub fn parse_crate_from_source_str(name: String,
-                                   source: String,
-                                   cfg: ast::CrateConfig,
-                                   sess: &ParseSess)
-                                   -> ast::Crate {
+pub fn parse_crate_from_source_str<'a>(name: String,
+                                       source: String,
+                                       cfg: ast::CrateConfig,
+                                       sess: &'a ParseSess)
+                                       -> PResult<'a, ast::Crate> {
     let mut p = new_parser_from_source_str(sess,
                                            cfg,
                                            name,
                                            source);
-    panictry!(p.parse_crate_mod())
+    p.parse_crate_mod()
 }
 
-pub fn parse_crate_attrs_from_source_str(name: String,
-                                         source: String,
-                                         cfg: ast::CrateConfig,
-                                         sess: &ParseSess)
-                                         -> Vec<ast::Attribute> {
+pub fn parse_crate_attrs_from_source_str<'a>(name: String,
+                                             source: String,
+                                             cfg: ast::CrateConfig,
+                                             sess: &'a ParseSess)
+                                             -> PResult<'a, Vec<ast::Attribute>> {
     let mut p = new_parser_from_source_str(sess,
                                            cfg,
                                            name,
                                            source);
-    panictry!(p.parse_inner_attributes())
+    p.parse_inner_attributes()
 }
 
-pub fn parse_expr_from_source_str(name: String,
-                                  source: String,
-                                  cfg: ast::CrateConfig,
-                                  sess: &ParseSess)
-                                  -> P<ast::Expr> {
+pub fn parse_expr_from_source_str<'a>(name: String,
+                                      source: String,
+                                      cfg: ast::CrateConfig,
+                                      sess: &'a ParseSess)
+                                      -> PResult<'a, P<ast::Expr>> {
     let mut p = new_parser_from_source_str(sess, cfg, name, source);
-    panictry!(p.parse_expr())
+    p.parse_expr()
 }
 
-pub fn parse_item_from_source_str(name: String,
-                                  source: String,
-                                  cfg: ast::CrateConfig,
-                                  sess: &ParseSess)
-                                  -> Option<P<ast::Item>> {
+/// Parses an item.
+///
+/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and`Err`
+/// when a syntax error occurred.
+pub fn parse_item_from_source_str<'a>(name: String,
+                                      source: String,
+                                      cfg: ast::CrateConfig,
+                                      sess: &'a ParseSess)
+                                      -> PResult<'a, Option<P<ast::Item>>> {
     let mut p = new_parser_from_source_str(sess, cfg, name, source);
-    panictry!(p.parse_item())
+    p.parse_item()
 }
 
-pub fn parse_meta_from_source_str(name: String,
-                                  source: String,
-                                  cfg: ast::CrateConfig,
-                                  sess: &ParseSess)
-                                  -> P<ast::MetaItem> {
+pub fn parse_meta_from_source_str<'a>(name: String,
+                                      source: String,
+                                      cfg: ast::CrateConfig,
+                                      sess: &'a ParseSess)
+                                      -> PResult<'a, P<ast::MetaItem>> {
     let mut p = new_parser_from_source_str(sess, cfg, name, source);
-    panictry!(p.parse_meta_item())
+    p.parse_meta_item()
 }
 
-pub fn parse_stmt_from_source_str(name: String,
-                                  source: String,
-                                  cfg: ast::CrateConfig,
-                                  sess: &ParseSess)
-                                  -> Option<ast::Stmt> {
+pub fn parse_stmt_from_source_str<'a>(name: String,
+                                      source: String,
+                                      cfg: ast::CrateConfig,
+                                      sess: &'a ParseSess)
+                                      -> PResult<'a, Option<ast::Stmt>> {
     let mut p = new_parser_from_source_str(
         sess,
         cfg,
         name,
         source
     );
-    panictry!(p.parse_stmt())
+    p.parse_stmt()
 }
 
 // Warning: This parses with quote_depth > 0, which is not the default.
-pub fn parse_tts_from_source_str(name: String,
-                                 source: String,
-                                 cfg: ast::CrateConfig,
-                                 sess: &ParseSess)
-                                 -> Vec<ast::TokenTree> {
+pub fn parse_tts_from_source_str<'a>(name: String,
+                                     source: String,
+                                     cfg: ast::CrateConfig,
+                                     sess: &'a ParseSess)
+                                     -> PResult<'a, Vec<ast::TokenTree>> {
     let mut p = new_parser_from_source_str(
         sess,
         cfg,
@@ -168,7 +170,7 @@ pub fn parse_tts_from_source_str(name: String,
     );
     p.quote_depth += 1;
     // right now this is re-creating the token trees from ... token trees.
-    panictry!(p.parse_all_token_trees())
+    p.parse_all_token_trees()
 }
 
 // Create a new parser from a source string
@@ -265,20 +267,6 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess,
     p
 }
 
-
-fn abort_if_errors<'a, T>(result: PResult<'a, T>, p: &Parser) -> T {
-    match result {
-        Ok(c) => {
-            c
-        }
-        Err(mut e) => {
-            e.emit();
-            p.abort_if_errors();
-            unreachable!();
-        }
-    }
-}
-
 /// Parse a string representing a character literal into its final form.
 /// Rather than just accepting/rejecting a given literal, unescapes it as
 /// well. Can take any slice prefixed by a character escape. Returns the
@@ -1078,19 +1066,21 @@ mod tests {
 
         let name = "<source>".to_string();
         let source = "/// doc comment\r\nfn foo() {}".to_string();
-        let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap();
+        let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess)
+            .unwrap().unwrap();
         let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
         assert_eq!(&doc[..], "/// doc comment");
 
         let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
-        let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap();
+        let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess)
+            .unwrap().unwrap();
         let docs = item.attrs.iter().filter(|a| &*a.name() == "doc")
                     .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>();
         let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()];
         assert_eq!(&docs[..], b);
 
         let source = "/** doc comment\r\n *  with CRLF */\r\nfn foo() {}".to_string();
-        let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap();
+        let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap().unwrap();
         let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
         assert_eq!(&doc[..], "/** doc comment\n *  with CRLF */");
     }
@@ -1099,7 +1089,7 @@ mod tests {
     fn ttdelim_span() {
         let sess = ParseSess::new();
         let expr = parse::parse_expr_from_source_str("foo".to_string(),
-            "foo!( fn main() { body } )".to_string(), vec![], &sess);
+            "foo!( fn main() { body } )".to_string(), vec![], &sess).unwrap();
 
         let tts = match expr.node {
             ast::ExprKind::Mac(ref mac) => mac.node.tts.clone(),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e166a367219..5884be40150 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -20,7 +20,7 @@ use ast::{BlockCheckMode, CaptureBy};
 use ast::{Constness, Crate, CrateConfig};
 use ast::{Decl, DeclKind};
 use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf};
-use ast::{Expr, ExprKind};
+use ast::{Expr, ExprKind, RangeLimits};
 use ast::{Field, FnDecl};
 use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
 use ast::{Ident, ImplItem, Item, ItemKind};
@@ -99,13 +99,6 @@ pub enum BoundParsingMode {
     Modified,
 }
 
-/// `pub` should be parsed in struct fields and not parsed in variant fields
-#[derive(Clone, Copy, PartialEq)]
-pub enum ParsePub {
-    Yes,
-    No,
-}
-
 #[derive(Clone, Copy, PartialEq)]
 pub enum SemiColonMode {
     Break,
@@ -2059,9 +2052,10 @@ impl<'a> Parser<'a> {
 
     pub fn mk_range(&mut self,
                     start: Option<P<Expr>>,
-                    end: Option<P<Expr>>)
+                    end: Option<P<Expr>>,
+                    limits: RangeLimits)
                     -> ast::ExprKind {
-        ExprKind::Range(start, end)
+        ExprKind::Range(start, end, limits)
     }
 
     pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::ExprKind {
@@ -2533,6 +2527,12 @@ impl<'a> Parser<'a> {
         let mut e = e0;
         let mut hi;
         loop {
+            // expr?
+            while self.eat(&token::Question) {
+                let hi = self.span.hi;
+                e = self.mk_expr(lo, hi, ExprKind::Try(e), None);
+            }
+
             // expr.f
             if self.eat(&token::Dot) {
                 match self.token {
@@ -2899,14 +2899,13 @@ impl<'a> Parser<'a> {
                 LhsExpr::AttributesParsed(attrs) => Some(attrs),
                 _ => None,
             };
-            if self.token == token::DotDot {
+            if self.token == token::DotDot || self.token == token::DotDotDot {
                 return self.parse_prefix_range_expr(attrs);
             } else {
                 try!(self.parse_prefix_expr(attrs))
             }
         };
 
-
         if self.expr_is_complete(&lhs) {
             // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
             return Ok(lhs);
@@ -2945,32 +2944,32 @@ impl<'a> Parser<'a> {
                                    ExprKind::Type(lhs, rhs), None);
                 continue
             } else if op == AssocOp::DotDot {
-                    // If we didn’t have to handle `x..`, it would be pretty easy to generalise
-                    // it to the Fixity::None code.
-                    //
-                    // We have 2 alternatives here: `x..y` and `x..` The other two variants are
-                    // handled with `parse_prefix_range_expr` call above.
-                    let rhs = if self.is_at_start_of_range_notation_rhs() {
-                        let rhs = self.parse_assoc_expr_with(op.precedence() + 1,
-                                                             LhsExpr::NotYetParsed);
-                        match rhs {
-                            Ok(e) => Some(e),
-                            Err(mut e) => {
-                                e.cancel();
-                                None
-                            }
+                // If we didn’t have to handle `x..`, it would be pretty easy to generalise
+                // it to the Fixity::None code.
+                //
+                // We have 2 alternatives here: `x..y` and `x..` The other two variants are
+                // handled with `parse_prefix_range_expr` call above.
+                let rhs = if self.is_at_start_of_range_notation_rhs() {
+                    let rhs = self.parse_assoc_expr_with(op.precedence() + 1,
+                                                         LhsExpr::NotYetParsed);
+                    match rhs {
+                        Ok(e) => Some(e),
+                        Err(mut e) => {
+                            e.cancel();
+                            None
                         }
-                    } else {
-                        None
-                    };
-                    let (lhs_span, rhs_span) = (lhs_span, if let Some(ref x) = rhs {
-                        x.span
-                    } else {
-                        cur_op_span
-                    });
-                    let r = self.mk_range(Some(lhs), rhs);
-                    lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
-                    break
+                    }
+                } else {
+                    None
+                };
+                let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs {
+                    x.span
+                } else {
+                    cur_op_span
+                });
+                let r = self.mk_range(Some(lhs), rhs, RangeLimits::HalfOpen);
+                lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
+                break
             }
 
             let rhs = try!(match op.fixity() {
@@ -2986,8 +2985,8 @@ impl<'a> Parser<'a> {
                         this.parse_assoc_expr_with(op.precedence() + 1,
                             LhsExpr::NotYetParsed)
                 }),
-                // We currently have no non-associative operators that are not handled above by
-                // the special cases. The code is here only for future convenience.
+                // the only operator handled here is `...` (the other non-associative operators are
+                // special-cased above)
                 Fixity::None => self.with_res(
                     restrictions - Restrictions::RESTRICTION_STMT_EXPR,
                     |this| {
@@ -3028,6 +3027,11 @@ impl<'a> Parser<'a> {
                     let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
                     self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None)
                 }
+                AssocOp::DotDotDot => {
+                    let (lhs_span, rhs_span) = (lhs.span, rhs.span);
+                    let r = self.mk_range(Some(lhs), Some(rhs), RangeLimits::Closed);
+                    self.mk_expr(lhs_span.lo, rhs_span.hi, r, None)
+                }
                 AssocOp::As | AssocOp::Colon | AssocOp::DotDot => {
                     self.bug("As, Colon or DotDot branch reached")
                 }
@@ -3059,18 +3063,19 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse prefix-forms of range notation: `..expr` and `..`
+    /// Parse prefix-forms of range notation: `..expr`, `..`, `...expr`
     fn parse_prefix_range_expr(&mut self,
                                already_parsed_attrs: Option<ThinAttributes>)
                                -> PResult<'a, P<Expr>> {
-        debug_assert!(self.token == token::DotDot);
+        debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot);
+        let tok = self.token.clone();
         let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs));
         let lo = self.span.lo;
         let mut hi = self.span.hi;
         self.bump();
         let opt_end = if self.is_at_start_of_range_notation_rhs() {
-            // RHS must be parsed with more associativity than DotDot.
-            let next_prec = AssocOp::from_token(&token::DotDot).unwrap().precedence() + 1;
+            // RHS must be parsed with more associativity than the dots.
+            let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1;
             Some(try!(self.parse_assoc_expr_with(next_prec,
                                                  LhsExpr::NotYetParsed)
             .map(|x|{
@@ -3080,7 +3085,13 @@ impl<'a> Parser<'a> {
          } else {
             None
         };
-        let r = self.mk_range(None, opt_end);
+        let r = self.mk_range(None,
+                              opt_end,
+                              if tok == token::DotDot {
+                                  RangeLimits::HalfOpen
+                              } else {
+                                  RangeLimits::Closed
+                              });
         Ok(self.mk_expr(lo, hi, r, attrs))
     }
 
@@ -5093,20 +5104,17 @@ impl<'a> Parser<'a> {
                 VariantData::Unit(ast::DUMMY_NODE_ID)
             } else {
                 // If we see: `struct Foo<T> where T: Copy { ... }`
-                VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::Yes)),
-                                    ast::DUMMY_NODE_ID)
+                VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
             }
         // No `where` so: `struct Foo<T>;`
         } else if self.eat(&token::Semi) {
             VariantData::Unit(ast::DUMMY_NODE_ID)
         // Record-style struct definition
         } else if self.token == token::OpenDelim(token::Brace) {
-            VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::Yes)),
-                                ast::DUMMY_NODE_ID)
+            VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
         // Tuple-style struct definition with optional where-clause.
         } else if self.token == token::OpenDelim(token::Paren) {
-            let body = VariantData::Tuple(try!(self.parse_tuple_struct_body(ParsePub::Yes)),
-                                          ast::DUMMY_NODE_ID);
+            let body = VariantData::Tuple(try!(self.parse_tuple_struct_body()), ast::DUMMY_NODE_ID);
             generics.where_clause = try!(self.parse_where_clause());
             try!(self.expect(&token::Semi));
             body
@@ -5119,13 +5127,11 @@ impl<'a> Parser<'a> {
         Ok((class_name, ItemKind::Struct(vdata, generics), None))
     }
 
-    pub fn parse_record_struct_body(&mut self,
-                                    parse_pub: ParsePub)
-                                    -> PResult<'a, Vec<StructField>> {
+    pub fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
         let mut fields = Vec::new();
         if self.eat(&token::OpenDelim(token::Brace)) {
             while self.token != token::CloseDelim(token::Brace) {
-                fields.push(try!(self.parse_struct_decl_field(parse_pub)));
+                fields.push(try!(self.parse_struct_decl_field()));
             }
 
             self.bump();
@@ -5139,9 +5145,7 @@ impl<'a> Parser<'a> {
         Ok(fields)
     }
 
-    pub fn parse_tuple_struct_body(&mut self,
-                                   parse_pub: ParsePub)
-                                   -> PResult<'a, Vec<StructField>> {
+    pub fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
         // This is the case where we find `struct Foo<T>(T) where T: Copy;`
         // Unit like structs are handled in parse_item_struct function
         let fields = try!(self.parse_unspanned_seq(
@@ -5152,13 +5156,7 @@ impl<'a> Parser<'a> {
                 let attrs = try!(p.parse_outer_attributes());
                 let lo = p.span.lo;
                 let struct_field_ = ast::StructField_ {
-                    kind: UnnamedField (
-                        if parse_pub == ParsePub::Yes {
-                            try!(p.parse_visibility())
-                        } else {
-                            Visibility::Inherited
-                        }
-                    ),
+                    kind: UnnamedField(try!(p.parse_visibility())),
                     id: ast::DUMMY_NODE_ID,
                     ty: try!(p.parse_ty_sum()),
                     attrs: attrs,
@@ -5193,15 +5191,11 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse an element of a struct definition
-    fn parse_struct_decl_field(&mut self, parse_pub: ParsePub) -> PResult<'a, StructField> {
+    fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
 
         let attrs = try!(self.parse_outer_attributes());
 
         if self.eat_keyword(keywords::Pub) {
-            if parse_pub == ParsePub::No {
-                let span = self.last_span;
-                self.span_err(span, "`pub` is not allowed here");
-            }
             return self.parse_single_struct_field(Visibility::Public, attrs);
         }
 
@@ -5567,11 +5561,11 @@ impl<'a> Parser<'a> {
             if self.check(&token::OpenDelim(token::Brace)) {
                 // Parse a struct variant.
                 all_nullary = false;
-                struct_def = VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::No)),
+                struct_def = VariantData::Struct(try!(self.parse_record_struct_body()),
                                                  ast::DUMMY_NODE_ID);
             } else if self.check(&token::OpenDelim(token::Paren)) {
                 all_nullary = false;
-                struct_def = VariantData::Tuple(try!(self.parse_tuple_struct_body(ParsePub::No)),
+                struct_def = VariantData::Tuple(try!(self.parse_tuple_struct_body()),
                                                 ast::DUMMY_NODE_ID);
             } else if self.eat(&token::Eq) {
                 disr_expr = Some(try!(self.parse_expr()));
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 6593b3ea532..294cbf35895 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -196,7 +196,7 @@ impl Token {
             BinOp(Or)                   => true, // in lambda syntax
             OrOr                        => true, // in lambda syntax
             AndAnd                      => true, // double borrow
-            DotDot                      => true, // range notation
+            DotDot | DotDotDot          => true, // range notation
             ModSep                      => true,
             Interpolated(NtExpr(..))    => true,
             Interpolated(NtIdent(..))   => true,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index b4e08d65a0a..2cfed1f82f7 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2163,11 +2163,15 @@ impl<'a> State<'a> {
                 try!(self.print_expr(&index));
                 try!(word(&mut self.s, "]"));
             }
-            ast::ExprKind::Range(ref start, ref end) => {
+            ast::ExprKind::Range(ref start, ref end, limits) => {
                 if let &Some(ref e) = start {
                     try!(self.print_expr(&e));
                 }
-                try!(word(&mut self.s, ".."));
+                if limits == ast::RangeLimits::HalfOpen {
+                    try!(word(&mut self.s, ".."));
+                } else {
+                    try!(word(&mut self.s, "..."));
+                }
                 if let &Some(ref e) = end {
                     try!(self.print_expr(&e));
                 }
@@ -2273,6 +2277,10 @@ impl<'a> State<'a> {
                 try!(self.print_inner_attributes_inline(attrs));
                 try!(self.print_expr(&e));
                 try!(self.pclose());
+            },
+            ast::ExprKind::Try(ref e) => {
+                try!(self.print_expr(e));
+                try!(word(&mut self.s, "?"))
             }
         }
         try!(self.ann.post(self, NodeExpr(expr)));
diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs
index 6fb81bb6a76..df4eb1c9ed7 100644
--- a/src/libsyntax/util/parser.rs
+++ b/src/libsyntax/util/parser.rs
@@ -61,6 +61,8 @@ pub enum AssocOp {
     As,
     /// `..` range
     DotDot,
+    /// `...` range
+    DotDotDot,
     /// `:`
     Colon,
 }
@@ -102,6 +104,7 @@ impl AssocOp {
             Token::AndAnd => Some(LAnd),
             Token::OrOr => Some(LOr),
             Token::DotDot => Some(DotDot),
+            Token::DotDotDot => Some(DotDotDot),
             Token::Colon => Some(Colon),
             _ if t.is_keyword(keywords::As) => Some(As),
             _ => None
@@ -147,7 +150,7 @@ impl AssocOp {
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
             LAnd => 6,
             LOr => 5,
-            DotDot => 4,
+            DotDot | DotDotDot => 4,
             Inplace => 3,
             Assign | AssignOp(_) => 2,
         }
@@ -162,7 +165,7 @@ impl AssocOp {
             As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
             BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
             LAnd | LOr | Colon => Fixity::Left,
-            DotDot => Fixity::None
+            DotDot | DotDotDot => Fixity::None
         }
     }
 
@@ -171,7 +174,8 @@ impl AssocOp {
         match *self {
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
             Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract |
-            ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | Colon => false
+            ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
+            DotDot | DotDotDot | Colon => false
         }
     }
 
@@ -181,7 +185,7 @@ impl AssocOp {
             Assign | AssignOp(_) | Inplace => true,
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
             Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
-            LOr | DotDot | Colon => false
+            LOr | DotDot | DotDotDot | Colon => false
         }
     }
 
@@ -206,7 +210,7 @@ impl AssocOp {
             BitOr => Some(BinOpKind::BitOr),
             LAnd => Some(BinOpKind::And),
             LOr => Some(BinOpKind::Or),
-            Inplace | Assign | AssignOp(_) | As | DotDot | Colon => None
+            Inplace | Assign | AssignOp(_) | As | DotDot | DotDotDot | Colon => None
         }
     }
 }
diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs
index b0f4c2dcba5..8358af69b66 100644
--- a/src/libsyntax/util/parser_testing.rs
+++ b/src/libsyntax/util/parser_testing.rs
@@ -10,11 +10,11 @@
 
 use ast;
 use parse::{ParseSess,PResult,filemap_to_tts};
-use parse::new_parser_from_source_str;
+use parse::{lexer, new_parser_from_source_str};
 use parse::parser::Parser;
 use parse::token;
 use ptr::P;
-use str::char_at;
+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> {
@@ -87,69 +87,62 @@ pub fn strs_to_idents(ids: Vec<&str> ) -> Vec<ast::Ident> {
 
 /// Does the given string match the pattern? whitespace in the first string
 /// may be deleted or replaced with other whitespace to match the pattern.
-/// this function is Unicode-ignorant; fortunately, the careful design of
-/// UTF-8 mitigates this ignorance.  In particular, this function only collapses
-/// sequences of \n, \r, ' ', and \t, but it should otherwise tolerate Unicode
-/// chars. Unsurprisingly, it doesn't do NKF-normalization(?).
+/// This function is relatively Unicode-ignorant; fortunately, the careful design
+/// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?).
 pub fn matches_codepattern(a : &str, b : &str) -> bool {
-    let mut idx_a = 0;
-    let mut idx_b = 0;
+    let mut a_iter = a.chars().peekable();
+    let mut b_iter = b.chars().peekable();
+
     loop {
-        if idx_a == a.len() && idx_b == b.len() {
-            return true;
-        }
-        else if idx_a == a.len() {return false;}
-        else if idx_b == b.len() {
-            // maybe the stuff left in a is all ws?
-            if is_whitespace(char_at(a, idx_a)) {
-                return scan_for_non_ws_or_end(a,idx_a) == a.len();
-            } else {
-                return false;
+        let (a, b) = match (a_iter.peek(), b_iter.peek()) {
+            (None, None) => return true,
+            (None, _) => return false,
+            (Some(&a), None) => {
+                if is_pattern_whitespace(a) {
+                    break // trailing whitespace check is out of loop for borrowck
+                } else {
+                    return false
+                }
             }
-        }
-        // ws in both given and pattern:
-        else if is_whitespace(char_at(a, idx_a))
-           && is_whitespace(char_at(b, idx_b)) {
-            idx_a = scan_for_non_ws_or_end(a,idx_a);
-            idx_b = scan_for_non_ws_or_end(b,idx_b);
-        }
-        // ws in given only:
-        else if is_whitespace(char_at(a, idx_a)) {
-            idx_a = scan_for_non_ws_or_end(a,idx_a);
-        }
-        // *don't* silently eat ws in expected only.
-        else if char_at(a, idx_a) == char_at(b, idx_b) {
-            idx_a += 1;
-            idx_b += 1;
-        }
-        else {
-            return false;
+            (Some(&a), Some(&b)) => (a, b)
+        };
+
+        if is_pattern_whitespace(a) && is_pattern_whitespace(b) {
+            // skip whitespace for a and b
+            scan_for_non_ws_or_end(&mut a_iter);
+            scan_for_non_ws_or_end(&mut b_iter);
+        } else if is_pattern_whitespace(a) {
+            // skip whitespace for a
+            scan_for_non_ws_or_end(&mut a_iter);
+        } else if a == b {
+            a_iter.next();
+            b_iter.next();
+        } else {
+            return false
         }
     }
+
+    // check if a has *only* trailing whitespace
+    a_iter.all(is_pattern_whitespace)
 }
 
-/// Given a string and an index, return the first usize >= idx
-/// that is a non-ws-char or is outside of the legal range of
-/// the string.
-fn scan_for_non_ws_or_end(a : &str, idx: usize) -> usize {
-    let mut i = idx;
-    let len = a.len();
-    while (i < len) && (is_whitespace(char_at(a, i))) {
-        i += 1;
+/// Advances the given peekable `Iterator` until it reaches a non-whitespace character
+fn scan_for_non_ws_or_end<I: Iterator<Item= char>>(iter: &mut Peekable<I>) {
+    while lexer::is_pattern_whitespace(iter.peek().cloned()) {
+        iter.next();
     }
-    i
 }
 
-/// Copied from lexer.
-pub fn is_whitespace(c: char) -> bool {
-    return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+pub fn is_pattern_whitespace(c: char) -> bool {
+    lexer::is_pattern_whitespace(Some(c))
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
 
-    #[test] fn eqmodws() {
+    #[test]
+    fn eqmodws() {
         assert_eq!(matches_codepattern("",""),true);
         assert_eq!(matches_codepattern("","a"),false);
         assert_eq!(matches_codepattern("a",""),false);
@@ -160,5 +153,22 @@ mod tests {
         assert_eq!(matches_codepattern("a   b","a b"),true);
         assert_eq!(matches_codepattern("ab","a b"),false);
         assert_eq!(matches_codepattern("a   b","ab"),true);
+        assert_eq!(matches_codepattern(" a   b","ab"),true);
+    }
+
+    #[test]
+    fn pattern_whitespace() {
+        assert_eq!(matches_codepattern("","\x0C"), false);
+        assert_eq!(matches_codepattern("a b ","a   \u{0085}\n\t\r  b"),true);
+        assert_eq!(matches_codepattern("a b","a   \u{0085}\n\t\r  b "),false);
+    }
+
+    #[test]
+    fn non_pattern_whitespace() {
+        // These have the property 'White_Space' but not 'Pattern_White_Space'
+        assert_eq!(matches_codepattern("a b","a\u{2002}b"), false);
+        assert_eq!(matches_codepattern("a   b","a\u{2002}b"), false);
+        assert_eq!(matches_codepattern("\u{205F}a   b","ab"), false);
+        assert_eq!(matches_codepattern("a  \u{3000}b","ab"), false);
     }
 }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index f26610b8b8d..25aee09e26c 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -763,7 +763,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(main_expression);
             visitor.visit_expr(index_expression)
         }
-        ExprKind::Range(ref start, ref end) => {
+        ExprKind::Range(ref start, ref end, _) => {
             walk_list!(visitor, visit_expr, start);
             walk_list!(visitor, visit_expr, end);
         }
@@ -793,6 +793,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
                 visitor.visit_expr(&output.expr)
             }
         }
+        ExprKind::Try(ref subexpression) => {
+            visitor.visit_expr(subexpression)
+        }
     }
 
     visitor.visit_expr_post(expression)
diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml
index 96a84496b9c..ecbd5a9c0f5 100644
--- a/src/libtest/Cargo.toml
+++ b/src/libtest/Cargo.toml
@@ -11,4 +11,3 @@ crate-type = ["dylib", "rlib"]
 [dependencies]
 getopts = { path = "../libgetopts" }
 term = { path = "../libterm" }
-serialize = { path = "../libserialize" }
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 7536ab9c5af..11d2a3e65c8 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -42,8 +42,6 @@
 #![feature(staged_api)]
 
 extern crate getopts;
-extern crate serialize;
-extern crate serialize as rustc_serialize;
 extern crate term;
 extern crate libc;
 
@@ -56,7 +54,6 @@ use self::NamePadding::*;
 use self::OutputLocation::*;
 
 use stats::Stats;
-use serialize::Encodable;
 use std::boxed::FnBox;
 use term::Terminal;
 
@@ -215,7 +212,7 @@ pub struct TestDescAndFn {
     pub testfn: TestFn,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Copy)]
+#[derive(Clone, PartialEq, Debug, Copy)]
 pub struct Metric {
     value: f64,
     noise: f64,
diff --git a/src/test/auxiliary/empty.rs b/src/test/auxiliary/empty.rs
new file mode 100644
index 00000000000..30669470522
--- /dev/null
+++ b/src/test/auxiliary/empty.rs
@@ -0,0 +1,9 @@
+// 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.
diff --git a/src/test/auxiliary/issue13507.rs b/src/test/auxiliary/issue13507.rs
index 78d0394a6e5..4cb846b5186 100644
--- a/src/test/auxiliary/issue13507.rs
+++ b/src/test/auxiliary/issue13507.rs
@@ -14,26 +14,26 @@ pub mod testtypes {
     use std::any::TypeId;
 
     pub fn type_ids() -> Vec<TypeId> {
-        let mut ids = vec!();
-        ids.push(TypeId::of::<FooNil>());
-        ids.push(TypeId::of::<FooBool>());
-        ids.push(TypeId::of::<FooInt>());
-        ids.push(TypeId::of::<FooUint>());
-        ids.push(TypeId::of::<FooFloat>());
-        ids.push(TypeId::of::<FooEnum>());
-        ids.push(TypeId::of::<FooUniq>());
-        ids.push(TypeId::of::<FooPtr>());
-        ids.push(TypeId::of::<&'static FooTrait>());
-        ids.push(TypeId::of::<FooStruct>());
-        ids.push(TypeId::of::<FooTuple>());
-        ids
+        vec![
+            TypeId::of::<FooBool>(),
+            TypeId::of::<FooInt>(),
+            TypeId::of::<FooUint>(),
+            TypeId::of::<FooFloat>(),
+            TypeId::of::<FooStr>(),
+            TypeId::of::<FooArray>(),
+            TypeId::of::<FooSlice>(),
+            TypeId::of::<FooBox>(),
+            TypeId::of::<FooPtr>(),
+            TypeId::of::<FooRef>(),
+            TypeId::of::<FooFnPtr>(),
+            TypeId::of::<FooNil>(),
+            TypeId::of::<FooTuple>(),
+            TypeId::of::<FooTrait>(),
+            TypeId::of::<FooStruct>(),
+            TypeId::of::<FooEnum>()
+        ]
     }
 
-    // Tests ty_nil
-    pub type FooNil = ();
-
-    // Skipping ty_bot
-
     // Tests TyBool
     pub type FooBool = bool;
 
@@ -49,25 +49,26 @@ pub mod testtypes {
     // Tests TyFloat (does not test all variants of FloatTy)
     pub type FooFloat = f64;
 
-    // For TyStr, what kind of string should I use? &'static str? String? Raw str?
+    // Tests TyStr
+    pub type FooStr = str;
 
-    // Tests TyEnum
-    pub enum FooEnum {
-        VarA(usize),
-        VarB(usize, usize)
-    }
+    // Tests TyArray
+    pub type FooArray = [u8; 1];
 
-    // Tests TyBox (of u8)
-    pub type FooUniq = Box<u8>;
+    // Tests TySlice
+    pub type FooSlice = [u8];
 
-    // As with TyStr, what type should be used for TyArray?
+    // Tests TyBox (of u8)
+    pub type FooBox = Box<u8>;
 
     // Tests TyRawPtr
     pub type FooPtr = *const u8;
 
-    // Skipping TyRef
+    // Tests TyRef
+    pub type FooRef = &'static u8;
 
-    // Skipping TyBareFn (how do you get a bare function type, rather than proc or closure?)
+    // Tests TyFnPtr
+    pub type FooFnPtr = fn(u8) -> bool;
 
     // Tests TyTrait
     pub trait FooTrait {
@@ -80,14 +81,17 @@ pub mod testtypes {
         foo_field: usize
     }
 
+    // Tests TyEnum
+    pub enum FooEnum {
+        VarA(usize),
+        VarB(usize, usize)
+    }
+
     // Tests TyTuple
+    pub type FooNil = ();
     pub type FooTuple = (u8, i8, bool);
 
-    // Skipping ty_param
-
-    // Skipping ty_self
-
-    // Skipping ty_self
+    // Skipping TyParam
 
     // Skipping TyInfer
 
diff --git a/src/test/compile-fail/derive-no-std-not-supported.rs b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs
index 01c81a8bbce..01c81a8bbce 100644
--- a/src/test/compile-fail/derive-no-std-not-supported.rs
+++ b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs
diff --git a/src/test/compile-fail/dropck_tarena_cycle_checked.rs b/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs
index d36293a484d..d36293a484d 100644
--- a/src/test/compile-fail/dropck_tarena_cycle_checked.rs
+++ b/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs
diff --git a/src/test/compile-fail/dropck_tarena_unsound_drop.rs b/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs
index 6cbed34c7ad..6cbed34c7ad 100644
--- a/src/test/compile-fail/dropck_tarena_unsound_drop.rs
+++ b/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs
diff --git a/src/test/compile-fail/duplicate_entry_error.rs b/src/test/compile-fail/duplicate_entry_error.rs
index d39553a7267..ad5ea291599 100644
--- a/src/test/compile-fail/duplicate_entry_error.rs
+++ b/src/test/compile-fail/duplicate_entry_error.rs
@@ -8,14 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test for issue #31788
+// note-pattern: first defined in crate `std`.
 
-// error-pattern: duplicate entry for `panic_fmt`, first definition found in `std`
+// Test for issue #31788 and E0152
 
 #![feature(lang_items)]
 
 #[lang = "panic_fmt"]
 fn panic_fmt() -> ! {
+//~^ ERROR: duplicate lang item found: `panic_fmt`.
     loop {}
 }
 
diff --git a/src/test/compile-fail/feature-gate-try-operator.rs b/src/test/compile-fail/feature-gate-try-operator.rs
new file mode 100644
index 00000000000..184aa63b234
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-try-operator.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.
+
+macro_rules! id {
+    ($e:expr) => { $e }
+}
+
+fn main() {
+    id!(x?);  //~ error: the `?` operator is not stable (see issue #31436)
+    //~^ help: add #![feature(question_mark)] to the crate attributes to enable
+    y?;  //~ error: the `?` operator is not stable (see issue #31436)
+    //~^ help: add #![feature(question_mark)] to the crate attributes to enable
+}
diff --git a/src/test/compile-fail/fn-item-type.rs b/src/test/compile-fail/fn-item-type.rs
index 5015810ff47..2fbd1ddb1e6 100644
--- a/src/test/compile-fail/fn-item-type.rs
+++ b/src/test/compile-fail/fn-item-type.rs
@@ -11,23 +11,37 @@
 // Test that the types of distinct fn items are not compatible by
 // default. See also `run-pass/fn-item-type-*.rs`.
 
-fn foo(x: isize) -> isize { x * 2 }
-fn bar(x: isize) -> isize { x * 4 }
+fn foo<T>(x: isize) -> isize { x * 2 }
+fn bar<T>(x: isize) -> isize { x * 4 }
 
 fn eq<T>(x: T, y: T) { }
 
+trait Foo { fn foo() { /* this is a default fn */ } }
+impl<T> Foo for T { /* `foo` is still default here */ }
+
 fn main() {
-    let f = if true { foo } else { bar };
-    //~^ ERROR if and else have incompatible types
-    //~| expected `fn(isize) -> isize {foo}`
-    //~| found `fn(isize) -> isize {bar}`
-    //~| expected fn item,
-    //~| found a different fn item
-
-    eq(foo, bar);
+    eq(foo::<u8>, bar::<u8>);
     //~^ ERROR mismatched types
-    //~|  expected `fn(isize) -> isize {foo}`
-    //~|  found `fn(isize) -> isize {bar}`
+    //~|  expected `fn(isize) -> isize {foo::<u8>}`
+    //~|  found `fn(isize) -> isize {bar::<u8>}`
     //~|  expected fn item
     //~|  found a different fn item
+
+    eq(foo::<u8>, foo::<i8>);
+    //~^ ERROR mismatched types
+    //~|  expected `fn(isize) -> isize {foo::<u8>}`
+    //~|  found `fn(isize) -> isize {foo::<i8>}`
+
+    eq(bar::<String>, bar::<Vec<u8>>);
+    //~^ ERROR mismatched types
+    //~|  expected `fn(isize) -> isize {bar::<collections::string::String>}`
+    //~|  found `fn(isize) -> isize {bar::<collections::vec::Vec<u8>>}`
+    //~|  expected struct `collections::string::String`
+    //~|  found struct `collections::vec::Vec`
+
+    // Make sure we distinguish between trait methods correctly.
+    eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
+    //~^ ERROR mismatched types
+    //~|  expected `fn() {Foo::foo}`
+    //~|  found `fn() {Foo::foo}`
 }
diff --git a/src/test/compile-fail/invalid-intrinsic.rs b/src/test/compile-fail/invalid-intrinsic.rs
new file mode 100644
index 00000000000..2aa2546cb9f
--- /dev/null
+++ b/src/test/compile-fail/invalid-intrinsic.rs
@@ -0,0 +1,16 @@
+// 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.
+
+#![feature(intrinsics)]
+extern "rust-intrinsic" {
+    pub static breakpoint : unsafe extern "rust-intrinsic" fn();
+    //~^ ERROR intrinsic has wrong type
+}
+fn main() { unsafe { breakpoint(); } }
\ No newline at end of file
diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs
index f907be161fa..e1fe2d06993 100644
--- a/src/test/compile-fail/issue-13482-2.rs
+++ b/src/test/compile-fail/issue-13482-2.rs
@@ -17,7 +17,7 @@ fn main() {
     let y = match x {
         [] => None,
 //~^ ERROR mismatched types
-//~| expected `[_#0i; 2]`
+//~| expected `[_#1i; 2]`
 //~| found `[_#7t; 0]`
 //~| expected an array with a fixed size of 2 elements
 //~| found one with 0 elements
diff --git a/src/test/compile-fail/issue-17728.rs b/src/test/compile-fail/issue-17728.rs
index 83e52216be2..787eb7a3b88 100644
--- a/src/test/compile-fail/issue-17728.rs
+++ b/src/test/compile-fail/issue-17728.rs
@@ -107,7 +107,7 @@ impl Debug for Player {
 }
 
 fn str_to_direction(to_parse: &str) -> RoomDirection {
-    match to_parse {
+    match to_parse { //~ ERROR match arms have incompatible types
         "w" | "west" => RoomDirection::West,
         "e" | "east" => RoomDirection::East,
         "n" | "north" => RoomDirection::North,
@@ -116,7 +116,7 @@ fn str_to_direction(to_parse: &str) -> RoomDirection {
         "out" => RoomDirection::Out,
         "up" => RoomDirection::Up,
         "down" => RoomDirection::Down,
-        _ => None //~ ERROR mismatched types
+        _ => None //~ NOTE match arm with an incompatible type
     }
 }
 
diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs
index 256c5d8e6f7..9143a226a24 100644
--- a/src/test/compile-fail/issue-2149.rs
+++ b/src/test/compile-fail/issue-2149.rs
@@ -21,5 +21,5 @@ impl<A> vec_monad<A> for Vec<A> {
 }
 fn main() {
     ["hi"].bind(|x| [x] );
-    //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope
+    //~^ ERROR no method named `bind` found for type `[&'static str; 1]` in the current scope
 }
diff --git a/src/test/parse-fail/struct-variant-no-pub.rs b/src/test/compile-fail/issue-30730.rs
index 1824e32c425..82804bb7474 100644
--- a/src/test/parse-fail/struct-variant-no-pub.rs
+++ b/src/test/compile-fail/issue-30730.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,12 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
-
-enum Foo {
-    Bar {
-        pub a: isize //~ ERROR: `pub` is not allowed here
-    }
-}
-
+#![deny(warnings)] //~ NOTE: lint level defined here
+use std::thread; //~ ERROR: unused import
 fn main() {}
diff --git a/src/test/compile-fail/issue-31561.rs b/src/test/compile-fail/issue-31561.rs
new file mode 100644
index 00000000000..f8645c4d3a7
--- /dev/null
+++ b/src/test/compile-fail/issue-31561.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.
+
+enum Thing {
+    Foo(u8),
+    Bar,
+    Baz
+}
+
+fn main() {
+    let Thing::Foo(y) = Thing::Foo(1);
+    //~^ ERROR refutable pattern in local binding: `Bar` not covered
+}
diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs
index 0fee48a8c6c..3aab953eb79 100644
--- a/src/test/compile-fail/liveness-unused.rs
+++ b/src/test/compile-fail/liveness-unused.rs
@@ -12,6 +12,8 @@
 #![deny(unused_assignments)]
 #![allow(dead_code, non_camel_case_types, trivial_numeric_casts)]
 
+use std::ops::AddAssign;
+
 fn f1(x: isize) {
     //~^ ERROR unused variable: `x`
 }
@@ -100,5 +102,49 @@ fn f5c() {
     }
 }
 
+struct View<'a>(&'a mut [i32]);
+
+impl<'a> AddAssign<i32> for View<'a> {
+    fn add_assign(&mut self, rhs: i32) {
+        for lhs in self.0.iter_mut() {
+            *lhs += rhs;
+        }
+    }
+}
+
+fn f6() {
+    let mut array = [1, 2, 3];
+    let mut v = View(&mut array);
+
+    // ensure an error shows up for x even if lhs of an overloaded add assign
+
+    let x;
+    //~^ ERROR variable `x` is assigned to, but never used
+
+    *({
+        x = 0;  //~ ERROR value assigned to `x` is never read
+        &mut v
+    }) += 1;
+}
+
+
+struct MutRef<'a>(&'a mut i32);
+
+impl<'a> AddAssign<i32> for MutRef<'a> {
+    fn add_assign(&mut self, rhs: i32) {
+        *self.0 += rhs;
+    }
+}
+
+fn f7() {
+    let mut a = 1;
+    {
+        // `b` does not trigger unused_variables
+        let mut b = MutRef(&mut a);
+        b += 1;
+    }
+    drop(a);
+}
+
 fn main() {
 }
diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs
index b839902c683..e4ab5829f41 100644
--- a/src/test/compile-fail/range-1.rs
+++ b/src/test/compile-fail/range-1.rs
@@ -13,7 +13,7 @@
 pub fn main() {
     // Mixed types.
     let _ = 0u32..10i32;
-    //~^ ERROR start and end of range have incompatible types
+    //~^ ERROR mismatched types
 
     // Bool => does not implement iterator.
     for i in false..true {}
diff --git a/src/test/compile-fail/range-2.rs b/src/test/compile-fail/range-2.rs
index c9053328572..94967693ecf 100644
--- a/src/test/compile-fail/range-2.rs
+++ b/src/test/compile-fail/range-2.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -12,8 +12,10 @@
 
 pub fn main() {
     let r = {
-        &42..&42
-        //~^ ERROR borrowed value does not live long enough
-        //~^^ ERROR borrowed value does not live long enough
+        let a = 42;
+        let b = 42;
+        &a..&b
+        //~^ ERROR `a` does not live long enough
+        //~^^ ERROR `b` does not live long enough
     };
 }
diff --git a/src/test/compile-fail/range_inclusive_gate.rs b/src/test/compile-fail/range_inclusive_gate.rs
new file mode 100644
index 00000000000..deac152ec85
--- /dev/null
+++ b/src/test/compile-fail/range_inclusive_gate.rs
@@ -0,0 +1,25 @@
+// 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 that #![feature(inclusive_range)] is required.
+
+#![feature(inclusive_range_syntax)]
+// #![feature(inclusive_range)]
+
+pub fn main() {
+    let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ... { use std::intrinsics; 2 };
+    //~^ ERROR use of unstable library feature 'inclusive_range'
+    //~^^ ERROR core_intrinsics
+    //~^^^ ERROR core_intrinsics
+    //~^^^^ WARN unused_imports
+    //~^^^^^ WARN unused_imports
+}
+
+
diff --git a/src/test/compile-fail/trait-privacy.rs b/src/test/compile-fail/trait-privacy.rs
index a0d0014a064..5f9e8ba6c0a 100644
--- a/src/test/compile-fail/trait-privacy.rs
+++ b/src/test/compile-fail/trait-privacy.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
+#![feature(rustc_attrs, get_type_id)]
 #![allow(dead_code)]
 
 mod foo {
@@ -26,5 +26,10 @@ fn g() {
     ().f(); // Check that this does not trigger a privacy error
 }
 
+fn f() {
+    let error = ::std::thread::spawn(|| {}).join().unwrap_err();
+    error.get_type_id(); // Regression test for #21670
+}
+
 #[rustc_error]
 fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs
new file mode 100644
index 00000000000..3eae76f9492
--- /dev/null
+++ b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs
@@ -0,0 +1,51 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem;
+
+unsafe fn foo() -> (isize, *const (), Option<fn()>) {
+    let i = mem::transmute(bar);
+    //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
+    //~^^ WARN was previously accepted
+
+    let p = mem::transmute(foo);
+    //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
+    //~^^ WARN was previously accepted
+
+    let of = mem::transmute(main);
+    //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
+    //~^^ WARN was previously accepted
+
+    (i, p, of)
+}
+
+unsafe fn bar() {
+    mem::transmute::<_, *mut ()>(foo);
+    //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
+    //~^^ WARN was previously accepted
+
+    mem::transmute::<_, fn()>(bar);
+    //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
+    //~^^ WARN was previously accepted
+
+    // No error if a coercion would otherwise occur.
+    mem::transmute::<fn(), usize>(main);
+
+    // Error, still, if the resulting type is not pointer-sized.
+    mem::transmute::<_, u8>(main);
+    //~^ ERROR transmute called with differently sized types
+}
+
+fn main() {
+    unsafe {
+        foo();
+        bar();
+    }
+}
diff --git a/src/test/compile-fail/useless-pub.rs b/src/test/compile-fail/useless-pub.rs
index fb6cdf7fa59..268b937c291 100644
--- a/src/test/compile-fail/useless-pub.rs
+++ b/src/test/compile-fail/useless-pub.rs
@@ -18,4 +18,11 @@ impl E for A {
     pub fn foo(&self) {}             //~ ERROR: unnecessary visibility
 }
 
+enum Foo {
+    V1 { pub f: i32 }, //~ ERROR unnecessary visibility qualifier
+                       //| NOTE visibility qualifiers have no effect on variant fields
+    V2(pub i32), //~ ERROR unnecessary visibility qualifier
+                 //| NOTE visibility qualifiers have no effect on variant fields
+}
+
 fn main() {}
diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs
index 94055450bc6..1d5ebdbae3e 100644
--- a/src/test/compile-fail/variadic-ffi-3.rs
+++ b/src/test/compile-fail/variadic-ffi-3.rs
@@ -22,7 +22,7 @@ fn main() {
         let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
         //~^ ERROR: mismatched types
         //~| expected `unsafe extern "C" fn(isize, u8)`
-        //~| found `unsafe extern "C" fn(isize, u8, ...)`
+        //~| found `unsafe extern "C" fn(isize, u8, ...) {foo}`
         //~| expected non-variadic fn
         //~| found variadic function
 
diff --git a/src/test/parse-fail/issue-19096.rs b/src/test/parse-fail/issue-19096.rs
index 0d9a111045a..6ba0fb5f15b 100644
--- a/src/test/parse-fail/issue-19096.rs
+++ b/src/test/parse-fail/issue-19096.rs
@@ -12,5 +12,5 @@
 
 fn main() {
     let t = (42, 42);
-    t.0::<isize>; //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `::`
+    t.0::<isize>; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `::`
 }
diff --git a/src/test/parse-fail/issue-3036.rs b/src/test/parse-fail/issue-3036.rs
index 1946e984e5d..229b12136fc 100644
--- a/src/test/parse-fail/issue-3036.rs
+++ b/src/test/parse-fail/issue-3036.rs
@@ -15,4 +15,4 @@
 fn main()
 {
     let x = 3
-} //~ ERROR: expected one of `.`, `;`, or an operator, found `}`
+} //~ ERROR: expected one of `.`, `;`, `?`, or an operator, found `}`
diff --git a/src/test/parse-fail/macros-no-semicolon.rs b/src/test/parse-fail/macros-no-semicolon.rs
index 5931631ccee..1c55d70f607 100644
--- a/src/test/parse-fail/macros-no-semicolon.rs
+++ b/src/test/parse-fail/macros-no-semicolon.rs
@@ -12,6 +12,6 @@
 
 fn main() {
     assert_eq!(1, 2)
-    assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `assert_eq`
+    assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq`
     println!("hello");
 }
diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs
index b99d0493ff7..37b66601e70 100644
--- a/src/test/parse-fail/match-refactor-to-expr.rs
+++ b/src/test/parse-fail/match-refactor-to-expr.rs
@@ -14,7 +14,7 @@ fn main() {
     let foo =
         match //~ NOTE did you mean to remove this `match` keyword?
         Some(4).unwrap_or_else(5)
-        ; //~ ERROR expected one of `.`, `{`, or an operator, found `;`
+        ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;`
 
     println!("{}", foo)
 }
diff --git a/src/test/parse-fail/range-3.rs b/src/test/parse-fail/range-3.rs
index 284cdb8c653..95aa71b0cdf 100644
--- a/src/test/parse-fail/range-3.rs
+++ b/src/test/parse-fail/range-3.rs
@@ -14,5 +14,5 @@
 
 pub fn main() {
     let r = 1..2..3;
-    //~^ ERROR expected one of `.`, `;`, or an operator, found `..`
+    //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..`
 }
diff --git a/src/test/parse-fail/range-4.rs b/src/test/parse-fail/range-4.rs
index 69898612771..4500df116a2 100644
--- a/src/test/parse-fail/range-4.rs
+++ b/src/test/parse-fail/range-4.rs
@@ -14,5 +14,5 @@
 
 pub fn main() {
     let r = ..1..2;
-    //~^ ERROR expected one of `.`, `;`, or an operator, found `..`
+    //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..`
 }
diff --git a/src/test/parse-fail/range_inclusive.rs b/src/test/parse-fail/range_inclusive.rs
new file mode 100644
index 00000000000..5fd6f1834e0
--- /dev/null
+++ b/src/test/parse-fail/range_inclusive.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 that inclusive ranges with no end point don't parse.
+
+#![feature(inclusive_range_syntax, inclusive_range)]
+
+pub fn main() {
+    for _ in 1... {}
+} //~ ERROR expected one of
+
diff --git a/src/test/parse-fail/range_inclusive_gate.rs b/src/test/parse-fail/range_inclusive_gate.rs
new file mode 100644
index 00000000000..021b6dd3e26
--- /dev/null
+++ b/src/test/parse-fail/range_inclusive_gate.rs
@@ -0,0 +1,74 @@
+// 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 that #![feature(inclusive_range_syntax)] is required.
+
+// #![feature(inclusive_range_syntax, inclusive_range)]
+
+macro_rules! m {
+    () => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental
+}
+
+#[cfg(nope)]
+fn f() {}
+#[cfg(not(nope))]
+fn f() {
+    for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
+}
+
+#[cfg(nope)]
+macro_rules! n { () => {} }
+#[cfg(not(nope))]
+macro_rules! n {
+    () => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental
+}
+
+macro_rules! o {
+    () => {{
+        #[cfg(nope)]
+        fn g() {}
+        #[cfg(not(nope))]
+        fn g() {
+            for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
+        }
+
+        g();
+    }}
+}
+
+#[cfg(nope)]
+macro_rules! p { () => {} }
+#[cfg(not(nope))]
+macro_rules! p {
+    () => {{
+        #[cfg(nope)]
+        fn h() {}
+        #[cfg(not(nope))]
+        fn h() {
+            for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
+        }
+
+        h();
+    }}
+}
+
+pub fn main() {
+    for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
+    for _ in ...10 {} //~ ERROR inclusive range syntax is experimental
+
+    f(); // not allowed in cfg'ed functions
+
+    m!(); // not allowed in macros
+    n!(); // not allowed in cfg'ed macros
+    o!(); // not allowed in macros that output cfgs
+    p!(); // not allowed in cfg'ed macros that output cfgs
+}
+
+
diff --git a/src/test/parse-fail/raw-str-unbalanced.rs b/src/test/parse-fail/raw-str-unbalanced.rs
index ce8960edde1..5c09f68970b 100644
--- a/src/test/parse-fail/raw-str-unbalanced.rs
+++ b/src/test/parse-fail/raw-str-unbalanced.rs
@@ -12,5 +12,5 @@
 
 static s: &'static str =
     r#"
-      "## //~ ERROR expected one of `.`, `;`, or an operator, found `#`
+      "## //~ ERROR expected one of `.`, `;`, `?`, or an operator, found `#`
 ;
diff --git a/src/test/parse-fail/removed-syntax-mut-vec-expr.rs b/src/test/parse-fail/removed-syntax-mut-vec-expr.rs
index ab9ff7ac19e..301bd0e8b1c 100644
--- a/src/test/parse-fail/removed-syntax-mut-vec-expr.rs
+++ b/src/test/parse-fail/removed-syntax-mut-vec-expr.rs
@@ -13,5 +13,5 @@
 fn f() {
     let v = [mut 1, 2, 3, 4];
     //~^  ERROR expected identifier, found keyword `mut`
-    //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `;`, `]`, `{`, or an operator, found `1`
+    //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `;`, `?`, `]`, `{`, or an operator, found `1`
 }
diff --git a/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs b/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs
index ea686aeb6e0..2f637cf0b4e 100644
--- a/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs
+++ b/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs
@@ -13,5 +13,5 @@
 fn f() {
     let a_box = box mut 42;
     //~^  ERROR expected identifier, found keyword `mut`
-    //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, or an operator, found `42`
+    //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `42`
 }
diff --git a/src/test/parse-fail/removed-syntax-with-1.rs b/src/test/parse-fail/removed-syntax-with-1.rs
index e9de52c013b..156b172a944 100644
--- a/src/test/parse-fail/removed-syntax-with-1.rs
+++ b/src/test/parse-fail/removed-syntax-with-1.rs
@@ -18,5 +18,5 @@ fn removed_with() {
 
     let a = S { foo: (), bar: () };
     let b = S { foo: () with a };
-    //~^ ERROR expected one of `,`, `.`, `}`, or an operator, found `with`
+    //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
 }
diff --git a/src/test/parse-fail/struct-literal-in-for.rs b/src/test/parse-fail/struct-literal-in-for.rs
index e57298f7280..93098455560 100644
--- a/src/test/parse-fail/struct-literal-in-for.rs
+++ b/src/test/parse-fail/struct-literal-in-for.rs
@@ -23,7 +23,7 @@ impl Foo {
 fn main() {
     for x in Foo {
         x: 3    //~ ERROR expected type, found `3`
-    }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{`
+    }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
         println!("yo");
     }
 }
diff --git a/src/test/parse-fail/struct-literal-in-if.rs b/src/test/parse-fail/struct-literal-in-if.rs
index 6bf41b7a450..db6a360a567 100644
--- a/src/test/parse-fail/struct-literal-in-if.rs
+++ b/src/test/parse-fail/struct-literal-in-if.rs
@@ -23,7 +23,7 @@ impl Foo {
 fn main() {
     if Foo {
         x: 3    //~ ERROR expected type, found `3`
-    }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{`
+    }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
         println!("yo");
     }
 }
diff --git a/src/test/parse-fail/struct-literal-in-match-discriminant.rs b/src/test/parse-fail/struct-literal-in-match-discriminant.rs
index 679f4542824..7038cc798c4 100644
--- a/src/test/parse-fail/struct-literal-in-match-discriminant.rs
+++ b/src/test/parse-fail/struct-literal-in-match-discriminant.rs
@@ -20,6 +20,6 @@ fn main() {
     } {
         Foo {
             x: x
-        } => {} //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `=>`
+        } => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>`
     }
 }
diff --git a/src/test/parse-fail/struct-literal-in-while.rs b/src/test/parse-fail/struct-literal-in-while.rs
index b388aac2c54..75e4eb3de07 100644
--- a/src/test/parse-fail/struct-literal-in-while.rs
+++ b/src/test/parse-fail/struct-literal-in-while.rs
@@ -23,7 +23,7 @@ impl Foo {
 fn main() {
     while Foo {
         x: 3    //~ ERROR expected type, found `3`
-    }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{`
+    }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
         println!("yo");
     }
 }
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index 835f7fc96c6..0347631aeb3 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -86,8 +86,10 @@ pub fn id<T>(x: T) -> T { (x as T) }
 pub fn use_id() {
     let _ =
         ((id::<[i32; (3 as usize)]> as
-             fn([i32; 3]) -> [i32; 3] {id})(([(1 as i32), (2 as i32),
-                                              (3 as i32)] as [i32; 3])) as
+             fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
+                                                          (2 as i32),
+                                                          (3 as i32)] as
+                                                            [i32; 3])) as
             [i32; 3]);
 }
 fn main() { }
diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs
index 13cbdfe24d6..29063c5a607 100644
--- a/src/test/run-make/execution-engine/test.rs
+++ b/src/test/run-make/execution-engine/test.rs
@@ -18,7 +18,7 @@ extern crate rustc_front;
 extern crate rustc_lint;
 extern crate rustc_metadata;
 extern crate rustc_resolve;
-extern crate syntax;
+#[macro_use] extern crate syntax;
 
 use std::ffi::{CStr, CString};
 use std::mem::transmute;
@@ -230,7 +230,7 @@ fn compile_program(input: &str, sysroot: PathBuf)
 
         let id = "input".to_string();
 
-        let krate = driver::phase_1_parse_input(&sess, cfg, &input);
+        let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input));
 
         let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None)
             .expect("phase_2 returned `None`");
diff --git a/src/test/run-pass/conditional-debug-macro-off.rs b/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs
index c6beb5ba358..c6beb5ba358 100644
--- a/src/test/run-pass/conditional-debug-macro-off.rs
+++ b/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs
diff --git a/src/test/run-pass/deprecated-derive.rs b/src/test/run-pass-fulldeps/deprecated-derive.rs
index 69a7f888bbe..69a7f888bbe 100644
--- a/src/test/run-pass/deprecated-derive.rs
+++ b/src/test/run-pass-fulldeps/deprecated-derive.rs
diff --git a/src/test/run-pass/derive-no-std.rs b/src/test/run-pass-fulldeps/derive-no-std.rs
index 78e9da001f7..78e9da001f7 100644
--- a/src/test/run-pass/derive-no-std.rs
+++ b/src/test/run-pass-fulldeps/derive-no-std.rs
diff --git a/src/test/run-pass/deriving-encodable-decodable-box.rs b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs
index 328cc134f3b..328cc134f3b 100644
--- a/src/test/run-pass/deriving-encodable-decodable-box.rs
+++ b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs
diff --git a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs b/src/test/run-pass-fulldeps/deriving-encodable-decodable-cell-refcell.rs
index 6e5eb86c584..6e5eb86c584 100644
--- a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs
+++ b/src/test/run-pass-fulldeps/deriving-encodable-decodable-cell-refcell.rs
diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass-fulldeps/deriving-global.rs
index 10e8ddc41f3..10e8ddc41f3 100644
--- a/src/test/run-pass/deriving-global.rs
+++ b/src/test/run-pass-fulldeps/deriving-global.rs
diff --git a/src/test/run-pass/dropck_tarena_sound_drop.rs b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs
index db30bfbf747..db30bfbf747 100644
--- a/src/test/run-pass/dropck_tarena_sound_drop.rs
+++ b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs
diff --git a/src/test/run-pass/empty-struct-braces-derive.rs b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs
index 8d19209208d..8d19209208d 100644
--- a/src/test/run-pass/empty-struct-braces-derive.rs
+++ b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs
diff --git a/src/test/run-pass/extern-mod-syntax.rs b/src/test/run-pass-fulldeps/extern-mod-syntax.rs
index 37404ee7e69..37404ee7e69 100644
--- a/src/test/run-pass/extern-mod-syntax.rs
+++ b/src/test/run-pass-fulldeps/extern-mod-syntax.rs
diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass-fulldeps/issue-11881.rs
index 9da04f72355..9da04f72355 100644
--- a/src/test/run-pass/issue-11881.rs
+++ b/src/test/run-pass-fulldeps/issue-11881.rs
diff --git a/src/test/run-pass/issue-14021.rs b/src/test/run-pass-fulldeps/issue-14021.rs
index 907967d115d..907967d115d 100644
--- a/src/test/run-pass/issue-14021.rs
+++ b/src/test/run-pass-fulldeps/issue-14021.rs
diff --git a/src/test/run-pass/issue-15924.rs b/src/test/run-pass-fulldeps/issue-15924.rs
index 0c208773884..0c208773884 100644
--- a/src/test/run-pass/issue-15924.rs
+++ b/src/test/run-pass-fulldeps/issue-15924.rs
diff --git a/src/test/run-pass/issue-24972.rs b/src/test/run-pass-fulldeps/issue-24972.rs
index ae7eb84d3e8..ae7eb84d3e8 100644
--- a/src/test/run-pass/issue-24972.rs
+++ b/src/test/run-pass-fulldeps/issue-24972.rs
diff --git a/src/test/run-pass/issue-2804.rs b/src/test/run-pass-fulldeps/issue-2804.rs
index a2b4e218a07..a2b4e218a07 100644
--- a/src/test/run-pass/issue-2804.rs
+++ b/src/test/run-pass-fulldeps/issue-2804.rs
diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass-fulldeps/issue-4016.rs
index bc3fa162e02..bc3fa162e02 100644
--- a/src/test/run-pass/issue-4016.rs
+++ b/src/test/run-pass-fulldeps/issue-4016.rs
diff --git a/src/test/run-pass/issue-4036.rs b/src/test/run-pass-fulldeps/issue-4036.rs
index ae7bb8a6842..ae7bb8a6842 100644
--- a/src/test/run-pass/issue-4036.rs
+++ b/src/test/run-pass-fulldeps/issue-4036.rs
diff --git a/src/test/run-pass/logging-enabled-debug.rs b/src/test/run-pass-fulldeps/logging-enabled-debug.rs
index 3ae4884ce47..3ae4884ce47 100644
--- a/src/test/run-pass/logging-enabled-debug.rs
+++ b/src/test/run-pass-fulldeps/logging-enabled-debug.rs
diff --git a/src/test/run-pass/logging-enabled.rs b/src/test/run-pass-fulldeps/logging-enabled.rs
index 2975835a271..2975835a271 100644
--- a/src/test/run-pass/logging-enabled.rs
+++ b/src/test/run-pass-fulldeps/logging-enabled.rs
diff --git a/src/test/run-pass/logging-right-crate.rs b/src/test/run-pass-fulldeps/logging-right-crate.rs
index 7caeeb40124..7caeeb40124 100644
--- a/src/test/run-pass/logging-right-crate.rs
+++ b/src/test/run-pass-fulldeps/logging-right-crate.rs
diff --git a/src/test/run-pass/logging-separate-lines.rs b/src/test/run-pass-fulldeps/logging-separate-lines.rs
index 09759326afd..09759326afd 100644
--- a/src/test/run-pass/logging-separate-lines.rs
+++ b/src/test/run-pass-fulldeps/logging-separate-lines.rs
diff --git a/src/test/run-pass/placement-new-arena.rs b/src/test/run-pass-fulldeps/placement-new-arena.rs
index 7ac624e6814..7ac624e6814 100644
--- a/src/test/run-pass/placement-new-arena.rs
+++ b/src/test/run-pass-fulldeps/placement-new-arena.rs
diff --git a/src/test/run-pass/regions-mock-tcx.rs b/src/test/run-pass-fulldeps/regions-mock-tcx.rs
index ed3cec465ef..ed3cec465ef 100644
--- a/src/test/run-pass/regions-mock-tcx.rs
+++ b/src/test/run-pass-fulldeps/regions-mock-tcx.rs
diff --git a/src/test/run-pass/rust-log-filter.rs b/src/test/run-pass-fulldeps/rust-log-filter.rs
index 306d24e3177..306d24e3177 100644
--- a/src/test/run-pass/rust-log-filter.rs
+++ b/src/test/run-pass-fulldeps/rust-log-filter.rs
diff --git a/src/test/run-pass/augmented-assignments.rs b/src/test/run-pass/augmented-assignments.rs
index 8c9ebcd274a..3ed9e8548dc 100644
--- a/src/test/run-pass/augmented-assignments.rs
+++ b/src/test/run-pass/augmented-assignments.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(unused_assignments)]
+
 use std::mem;
 use std::ops::{
     AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, Index, MulAssign, RemAssign,
@@ -27,6 +29,8 @@ impl Slice {
     }
 }
 
+struct View<'a>(&'a mut [i32]);
+
 fn main() {
     let mut x = Int(1);
 
@@ -78,6 +82,12 @@ fn main() {
     assert_eq!(array[0], 1);
     assert_eq!(array[1], 2);
     assert_eq!(array[2], 3);
+
+    // sized indirection
+    // check that this does *not* trigger the unused_assignments lint
+    let mut array = [0, 1, 2];
+    let mut view = View(&mut array);
+    view += 1;
 }
 
 impl AddAssign for Int {
@@ -159,3 +169,11 @@ impl AddAssign<i32> for Slice {
         }
     }
 }
+
+impl<'a> AddAssign<i32> for View<'a> {
+    fn add_assign(&mut self, rhs: i32) {
+        for lhs in self.0.iter_mut() {
+            *lhs += rhs;
+        }
+    }
+}
diff --git a/src/test/run-pass/coerce-unify.rs b/src/test/run-pass/coerce-unify.rs
new file mode 100644
index 00000000000..3d690146931
--- /dev/null
+++ b/src/test/run-pass/coerce-unify.rs
@@ -0,0 +1,77 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that coercions can unify if-else, match arms and array elements.
+
+// Try to construct if-else chains, matches and arrays out of given expressions.
+macro_rules! check {
+    ($last:expr $(, $rest:expr)+) => {
+        // Last expression comes first because of whacky ifs and matches.
+        let _ = $(if false { $rest })else+ else { $last };
+
+        let _ = match 0 { $(_ if false => $rest,)+ _ => $last };
+
+        let _ = [$($rest,)+ $last];
+    }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 2 types.
+macro_rules! check2 {
+    ($a:expr, $b:expr) => {
+        check!($a, $b);
+        check!($b, $a);
+
+        check!($a, $a, $b);
+        check!($a, $b, $a);
+        check!($a, $b, $b);
+
+        check!($b, $a, $a);
+        check!($b, $a, $b);
+        check!($b, $b, $a);
+    }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 3 types.
+macro_rules! check3 {
+    ($a:expr, $b:expr, $c:expr) => {
+        // Delegate to check2 for cases where a type repeats.
+        check2!($a, $b);
+        check2!($b, $c);
+        check2!($a, $c);
+
+        // Check the remaining cases, i.e. permutations of ($a, $b, $c).
+        check!($a, $b, $c);
+        check!($a, $c, $b);
+        check!($b, $a, $c);
+        check!($b, $c, $a);
+        check!($c, $a, $b);
+        check!($c, $b, $a);
+    }
+}
+
+use std::mem::size_of;
+
+fn foo() {}
+fn bar() {}
+
+pub fn main() {
+    check3!(foo, bar, foo as fn());
+    check3!(size_of::<u8>, size_of::<u16>, size_of::<usize> as fn() -> usize);
+
+    let s = String::from("bar");
+    check2!("foo", &s);
+
+    let a = [1, 2, 3];
+    let v = vec![1, 2, 3];
+    check2!(&a[..], &v);
+
+    // Make sure in-array coercion still works.
+    let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)];
+}
diff --git a/src/test/run-pass/empty-type-parameter-list.rs b/src/test/run-pass/empty-type-parameter-list.rs
new file mode 100644
index 00000000000..7af2844d564
--- /dev/null
+++ b/src/test/run-pass/empty-type-parameter-list.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.
+
+// Test that empty type parameter list (<>) is synonymous with
+// no type parameters at all
+
+struct S<>;
+trait T<> {}
+enum E<> { V }
+impl<> T<> for S<> {}
+impl T for E {}
+fn foo<>() {}
+fn bar() {}
+
+fn main() {
+    let _ = S;
+    let _ = S::<>;
+    let _ = E::V;
+    let _ = E::<>::V;
+    foo();
+    foo::<>();
+
+    // Test that we can supply <> to non generic things
+    bar::<>();
+    let _: i32<>;
+}
diff --git a/src/test/run-pass/enum-clike-ffi-as-int.rs b/src/test/run-pass/enum-clike-ffi-as-int.rs
index 8be3634c88a..fdaad9e1fab 100644
--- a/src/test/run-pass/enum-clike-ffi-as-int.rs
+++ b/src/test/run-pass/enum-clike-ffi-as-int.rs
@@ -25,16 +25,17 @@
 
 #[repr(u32)]
 enum Foo {
-  A = 0,
-  B = 23
+    A = 0,
+    B = 23
 }
 
 #[inline(never)]
 extern "C" fn foo(_x: usize) -> Foo { Foo::B }
 
 pub fn main() {
-  unsafe {
-    let f: extern "C" fn(usize) -> u32 = ::std::mem::transmute(foo);
-    assert_eq!(f(0xDEADBEEF), Foo::B as u32);
-  }
+    unsafe {
+        let f: extern "C" fn(usize) -> u32 =
+            ::std::mem::transmute(foo as extern "C" fn(usize) -> Foo);
+        assert_eq!(f(0xDEADBEEF), Foo::B as u32);
+    }
 }
diff --git a/src/test/run-pass/fn-item-type-zero-sized.rs b/src/test/run-pass/fn-item-type-zero-sized.rs
new file mode 100644
index 00000000000..5fdaf083d07
--- /dev/null
+++ b/src/test/run-pass/fn-item-type-zero-sized.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.
+
+// Test that fn item types are zero-sized.
+
+use std::mem::{size_of, size_of_val};
+
+fn main() {
+    assert_eq!(size_of_val(&main), 0);
+
+    let (a, b) = (size_of::<u8>, size_of::<u16>);
+    assert_eq!(size_of_val(&a), 0);
+    assert_eq!(size_of_val(&b), 0);
+    assert_eq!((a(), b()), (1, 2));
+}
diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs
index 91ec3e85404..084b7a166cd 100644
--- a/src/test/run-pass/issue-13507-2.rs
+++ b/src/test/run-pass/issue-13507-2.rs
@@ -19,23 +19,29 @@ use issue13507::testtypes;
 use std::any::TypeId;
 
 pub fn type_ids() -> Vec<TypeId> {
-    let mut ids = vec!();
-    ids.push(TypeId::of::<testtypes::FooNil>());
-    ids.push(TypeId::of::<testtypes::FooBool>());
-    ids.push(TypeId::of::<testtypes::FooInt>());
-    ids.push(TypeId::of::<testtypes::FooUint>());
-    ids.push(TypeId::of::<testtypes::FooFloat>());
-    ids.push(TypeId::of::<testtypes::FooEnum>());
-    ids.push(TypeId::of::<testtypes::FooUniq>());
-    ids.push(TypeId::of::<testtypes::FooPtr>());
-    ids.push(TypeId::of::<&'static testtypes::FooTrait>());
-    ids.push(TypeId::of::<testtypes::FooStruct>());
-    ids.push(TypeId::of::<testtypes::FooTuple>());
-    ids
+    use issue13507::testtypes::*;
+    vec![
+        TypeId::of::<FooBool>(),
+        TypeId::of::<FooInt>(),
+        TypeId::of::<FooUint>(),
+        TypeId::of::<FooFloat>(),
+        TypeId::of::<FooStr>(),
+        TypeId::of::<FooArray>(),
+        TypeId::of::<FooSlice>(),
+        TypeId::of::<FooBox>(),
+        TypeId::of::<FooPtr>(),
+        TypeId::of::<FooRef>(),
+        TypeId::of::<FooFnPtr>(),
+        TypeId::of::<FooNil>(),
+        TypeId::of::<FooTuple>(),
+        TypeId::of::<FooTrait>(),
+        TypeId::of::<FooStruct>(),
+        TypeId::of::<FooEnum>()
+    ]
 }
 
 pub fn main() {
-    let othercrate = testtypes::type_ids();
+    let othercrate = issue13507::testtypes::type_ids();
     let thiscrate = type_ids();
     assert_eq!(thiscrate, othercrate);
 }
diff --git a/src/test/run-pass/mir_refs_correct.rs b/src/test/run-pass/mir_refs_correct.rs
index 93953e3f58a..67baf2f9c49 100644
--- a/src/test/run-pass/mir_refs_correct.rs
+++ b/src/test/run-pass/mir_refs_correct.rs
@@ -204,48 +204,41 @@ fn t24() -> fn(u8) -> S {
     C4
 }
 
-fn main(){
-    unsafe {
-        assert_eq!(t1()(), regular());
-
-        assert!(::std::mem::transmute::<_, *mut ()>(t2()) ==
-                ::std::mem::transmute::<_, *mut ()>(E::U));
-        assert!(::std::mem::transmute::<_, *mut ()>(t3()) ==
-                ::std::mem::transmute::<_, *mut ()>(S));
-
-        assert_eq!(t4()(), S::hey());
-        let s = S(42);
-        assert_eq!(t5()(&s), <S as X>::hoy(&s));
-
-
-        assert_eq!(t6()(), ext::regular_fn());
-        assert!(::std::mem::transmute::<_, *mut ()>(t7()) ==
-                ::std::mem::transmute::<_, *mut ()>(ext::E::U));
-        assert!(::std::mem::transmute::<_, *mut ()>(t8()) ==
-                ::std::mem::transmute::<_, *mut ()>(ext::S));
-
-        assert_eq!(t9()(), ext::S::hey());
-        let sext = ext::S(6);
-        assert_eq!(t10()(&sext), <ext::S as ext::X>::hoy(&sext));
-
-        let p = parametric::<u8>;
-        assert!(::std::mem::transmute::<_, *mut ()>(t11()) ==
-                ::std::mem::transmute::<_, *mut ()>(p));
-
-        assert_eq!(t12(), C);
-        assert_eq!(t13(), C2);
-        assert_eq!(t13_2(), C3);
-
-        assert_eq!(t14()(), <S as X>::hoy2());
-        assert_eq!(t15()(&s), S::hey2(&s));
-        assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32));
-        assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64));
-        assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64));
-        assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32));
-        assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38));
-        assert_eq!(t21(), Unit);
-        assert_eq!(t22(), None);
-        assert_eq!(t23(), (CEnum::A, CEnum::B));
-        assert_eq!(t24(), C4);
-    }
+fn main() {
+    assert_eq!(t1()(), regular());
+
+    assert_eq!(t2() as *mut (), E::U as *mut ());
+    assert_eq!(t3() as *mut (), S as *mut ());
+
+    assert_eq!(t4()(), S::hey());
+    let s = S(42);
+    assert_eq!(t5()(&s), <S as X>::hoy(&s));
+
+
+    assert_eq!(t6()(), ext::regular_fn());
+    assert_eq!(t7() as *mut (), ext::E::U as *mut ());
+    assert_eq!(t8() as *mut (), ext::S as *mut ());
+
+    assert_eq!(t9()(), ext::S::hey());
+    let sext = ext::S(6);
+    assert_eq!(t10()(&sext), <ext::S as ext::X>::hoy(&sext));
+
+    let p = parametric::<u8>;
+    assert_eq!(t11() as *mut (), p as *mut ());
+
+    assert_eq!(t12(), C);
+    assert_eq!(t13(), C2);
+    assert_eq!(t13_2(), C3);
+
+    assert_eq!(t14()(), <S as X>::hoy2());
+    assert_eq!(t15()(&s), S::hey2(&s));
+    assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32));
+    assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64));
+    assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64));
+    assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32));
+    assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38));
+    assert_eq!(t21(), Unit);
+    assert_eq!(t22(), None);
+    assert_eq!(t23(), (CEnum::A, CEnum::B));
+    assert_eq!(t24(), C4);
 }
diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs
index 224111900d6..2b7cf6c6682 100644
--- a/src/test/run-pass/nullable-pointer-ffi-compat.rs
+++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs
@@ -24,13 +24,14 @@
 use std::mem;
 
 #[inline(never)]
-extern "C" fn foo<'a>(x: &'a isize) -> Option<&'a isize> { Some(x) }
+extern "C" fn foo(x: &isize) -> Option<&isize> { Some(x) }
 
 static FOO: isize = 0xDEADBEE;
 
 pub fn main() {
     unsafe {
-        let f: for<'a> extern "C" fn(&'a isize) -> &'a isize = mem::transmute(foo);
+        let f: extern "C" fn(&isize) -> &isize =
+            mem::transmute(foo as extern "C" fn(&isize) -> Option<&isize>);
         assert_eq!(*f(&FOO), FOO);
     }
 }
diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs
index cfd3bb49f34..dffdcfe0af5 100644
--- a/src/test/run-pass/nullable-pointer-iotareduction.rs
+++ b/src/test/run-pass/nullable-pointer-iotareduction.rs
@@ -12,8 +12,6 @@
 #![allow(unknown_features)]
 #![feature(box_syntax)]
 
-use std::{option, mem};
-
 // Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions,
 // which "says that a destructor applied to an object built from a constructor
 // behaves as expected".  -- http://coq.inria.fr/doc/Reference-Manual006.html
@@ -43,9 +41,9 @@ macro_rules! check_option {
         check_option!($e, $T, |ptr| assert_eq!(*ptr, $e));
     }};
     ($e:expr, $T:ty, |$v:ident| $chk:expr) => {{
-        assert!(option::Option::None::<$T>.is_none());
+        assert!(None::<$T>.is_none());
         let e = $e;
-        let s_ = option::Option::Some::<$T>(e);
+        let s_ = Some::<$T>(e);
         let $v = s_.as_ref().unwrap();
         $chk
     }}
@@ -78,9 +76,8 @@ pub fn main() {
     check_type!(&17, &isize);
     check_type!(box 18, Box<isize>);
     check_type!("foo".to_string(), String);
-    check_type!(vec!(20, 22), Vec<isize> );
-    let mint: usize = unsafe { mem::transmute(main) };
+    check_type!(vec!(20, 22), Vec<isize>);
     check_type!(main, fn(), |pthing| {
-        assert_eq!(mint, unsafe { mem::transmute(*pthing) })
+        assert_eq!(main as fn(), *pthing as fn())
     });
 }
diff --git a/src/test/run-pass/parser-unicode-whitespace.rs b/src/test/run-pass/parser-unicode-whitespace.rs
new file mode 100644
index 00000000000..837bb8339e1
--- /dev/null
+++ b/src/test/run-pass/parser-unicode-whitespace.rs
@@ -0,0 +1,22 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+// Beware editing: it has numerous whitespace characters which are important.
+// It contains one ranges from the 'PATTERN_WHITE_SPACE' property outlined in
+// http://unicode.org/Public/UNIDATA/PropList.txt
+//
+// The characters in the first expression of the assertion can be generated
+// from: "4\u{0C}+\n\t\r7\t*\u{20}2\u{85}/\u{200E}3\u{200F}*\u{2028}2\u{2029}"
+pub fn main() {
+assert_eq!(4+
+
+7   * 2…/‎3‏*
2
, 4 + 7 * 2 / 3 * 2);
+}
diff --git a/src/test/run-pass/range.rs b/src/test/run-pass/range.rs
index 24261772add..4c249bbe1f7 100644
--- a/src/test/run-pass/range.rs
+++ b/src/test/run-pass/range.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -44,6 +44,7 @@ pub fn main() {
     let _ = 0_usize..4+4-3;
     let _ = 0..foo();
 
+    let _ = { &42..&100 }; // references to literals are OK
     let _ = ..42_usize;
 
     // Test we can use two different types with a common supertype.
diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs
new file mode 100644
index 00000000000..07233a43b88
--- /dev/null
+++ b/src/test/run-pass/range_inclusive.rs
@@ -0,0 +1,129 @@
+// 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.
+
+// Test inclusive range syntax.
+
+#![feature(inclusive_range_syntax, inclusive_range, step_by)]
+
+use std::ops::{RangeInclusive, RangeToInclusive};
+
+fn foo() -> isize { 42 }
+
+// Test that range syntax works in return statements
+fn return_range_to() -> RangeToInclusive<i32> { return ...1; }
+
+pub fn main() {
+    let mut count = 0;
+    for i in 0_usize...10 {
+        assert!(i >= 0 && i <= 10);
+        count += i;
+    }
+    assert_eq!(count, 55);
+
+    let mut count = 0;
+    let mut range = 0_usize...10;
+    for i in range {
+        assert!(i >= 0 && i <= 10);
+        count += i;
+    }
+    assert_eq!(count, 55);
+
+    let mut count = 0;
+    for i in (0_usize...10).step_by(2) {
+        assert!(i >= 0 && i <= 10 && i % 2 == 0);
+        count += i;
+    }
+    assert_eq!(count, 30);
+
+    let _ = 0_usize...4+4-3;
+    let _ = 0...foo();
+
+    let _ = { &42...&100 }; // references to literals are OK
+    let _ = ...42_usize;
+
+    // Test we can use two different types with a common supertype.
+    let x = &42;
+    {
+        let y = 42;
+        let _ = x...&y;
+    }
+
+    // test collection indexing
+    let vec = (0...10).collect::<Vec<_>>();
+    let slice: &[_] = &*vec;
+    let string = String::from("hello world");
+    let stir = "hello world";
+
+    assert_eq!(&vec[3...6], &[3, 4, 5, 6]);
+    assert_eq!(&vec[ ...6], &[0, 1, 2, 3, 4, 5, 6]);
+
+    assert_eq!(&slice[3...6], &[3, 4, 5, 6]);
+    assert_eq!(&slice[ ...6], &[0, 1, 2, 3, 4, 5, 6]);
+
+    assert_eq!(&string[3...6], "lo w");
+    assert_eq!(&string[ ...6], "hello w");
+
+    assert_eq!(&stir[3...6], "lo w");
+    assert_eq!(&stir[ ...6], "hello w");
+
+    // test the size hints and emptying
+    let mut long = 0...255u8;
+    let mut short = 42...42;
+    assert_eq!(long.size_hint(), (256, Some(256)));
+    assert_eq!(short.size_hint(), (1, Some(1)));
+    long.next();
+    short.next();
+    assert_eq!(long.size_hint(), (255, Some(255)));
+    assert_eq!(short.size_hint(), (0, Some(0)));
+    assert_eq!(short, RangeInclusive::Empty { at: 42 });
+
+    assert_eq!(long.len(), 255);
+    assert_eq!(short.len(), 0);
+
+    // test iterating backwards
+    assert_eq!(long.next_back(), Some(255));
+    assert_eq!(long.next_back(), Some(254));
+    assert_eq!(long.next_back(), Some(253));
+    assert_eq!(long.next(), Some(1));
+    assert_eq!(long.next(), Some(2));
+    assert_eq!(long.next_back(), Some(252));
+    for i in 3...251 {
+        assert_eq!(long.next(), Some(i));
+    }
+    assert_eq!(long, RangeInclusive::Empty { at: 251 });
+
+    // check underflow
+    let mut narrow = 1...0;
+    assert_eq!(narrow.next_back(), None);
+    assert_eq!(narrow, RangeInclusive::Empty { at: 0 });
+    let mut zero = 0u8...0;
+    assert_eq!(zero.next_back(), Some(0));
+    assert_eq!(zero.next_back(), None);
+    assert_eq!(zero, RangeInclusive::Empty { at: 0 });
+    let mut high = 255u8...255;
+    assert_eq!(high.next_back(), Some(255));
+    assert_eq!(high.next_back(), None);
+    assert_eq!(high, RangeInclusive::Empty { at: 255 });
+
+    // what happens if you have a nonsense range?
+    let mut nonsense = 10...5;
+    assert_eq!(nonsense.next(), None);
+    assert_eq!(nonsense, RangeInclusive::Empty { at: 10 });
+
+    // conversion
+    assert_eq!(0...9, (0..10).into());
+    assert_eq!(0...0, (0..1).into());
+    assert_eq!(RangeInclusive::Empty { at: 1 }, (1..0).into());
+
+    // output
+    assert_eq!(format!("{:?}", 0...10), "0...10");
+    assert_eq!(format!("{:?}", ...10), "...10");
+    assert_eq!(format!("{:?}", long), "[empty range @ 251]");
+}
diff --git a/src/test/run-pass/range_inclusive_gate.rs b/src/test/run-pass/range_inclusive_gate.rs
new file mode 100644
index 00000000000..5e0ec19d6b3
--- /dev/null
+++ b/src/test/run-pass/range_inclusive_gate.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.
+
+// Test that you only need the syntax gate if you don't mention the structs.
+
+#![feature(inclusive_range_syntax)]
+
+fn main() {
+    let mut count = 0;
+    for i in 0_usize...10 {
+        assert!(i >= 0 && i <= 10);
+        count += i;
+    }
+    assert_eq!(count, 55);
+}
+
diff --git a/src/test/run-pass/transmute-from-fn-item-types.rs b/src/test/run-pass/transmute-from-fn-item-types.rs
new file mode 100644
index 00000000000..574a90e2ad6
--- /dev/null
+++ b/src/test/run-pass/transmute-from-fn-item-types.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.
+
+#![allow(transmute_from_fn_item_types)]
+
+use std::mem;
+
+fn main() {
+    unsafe {
+        let u = mem::transmute(main);
+        let p = mem::transmute(main);
+        let f = mem::transmute(main);
+        let tuple: (usize, *mut (), fn()) = (u, p, f);
+        assert_eq!(mem::transmute::<_, [usize; 3]>(tuple), [main as usize; 3]);
+
+        mem::transmute::<_, usize>(main);
+        mem::transmute::<_, *mut ()>(main);
+        mem::transmute::<_, fn()>(main);
+    }
+}
diff --git a/src/test/run-pass/try-operator-hygiene.rs b/src/test/run-pass/try-operator-hygiene.rs
new file mode 100644
index 00000000000..233c03df4e5
--- /dev/null
+++ b/src/test/run-pass/try-operator-hygiene.rs
@@ -0,0 +1,34 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// `expr?` expands to:
+//
+// match expr {
+//     Ok(val) => val,
+//     Err(err) => return From::from(err),
+// }
+//
+// This test verifies that the expansion is hygienic, i.e. it's not affected by other `val` and
+// `err` bindings that may be in scope.
+
+#![feature(question_mark)]
+
+use std::num::ParseIntError;
+
+fn main() {
+    assert_eq!(parse(), Ok(1));
+}
+
+fn parse() -> Result<i32, ParseIntError> {
+    const val: char = 'a';
+    const err: char = 'b';
+
+    Ok("1".parse::<i32>()?)
+}
diff --git a/src/test/run-pass/try-operator.rs b/src/test/run-pass/try-operator.rs
new file mode 100644
index 00000000000..de5ccf09c59
--- /dev/null
+++ b/src/test/run-pass/try-operator.rs
@@ -0,0 +1,200 @@
+// 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(question_mark)]
+
+use std::fs::File;
+use std::io::{Read, self};
+use std::num::ParseIntError;
+use std::str::FromStr;
+
+fn on_method() -> Result<i32, ParseIntError> {
+    Ok("1".parse::<i32>()? + "2".parse::<i32>()?)
+}
+
+fn in_chain() -> Result<String, ParseIntError> {
+    Ok("3".parse::<i32>()?.to_string())
+}
+
+fn on_call() -> Result<i32, ParseIntError> {
+    fn parse<T: FromStr>(s: &str) -> Result<T, T::Err> {
+        s.parse()
+    }
+
+    Ok(parse("4")?)
+}
+
+fn nested() -> Result<i32, ParseIntError> {
+    Ok("5".parse::<i32>()?.to_string().parse()?)
+}
+
+fn on_path() -> Result<i32, ParseIntError> {
+    let x = "6".parse::<i32>();
+
+    Ok(x?)
+}
+
+fn on_macro() -> Result<i32, ParseIntError> {
+    macro_rules! id {
+        ($e:expr) => { $e }
+    }
+
+    Ok(id!("7".parse::<i32>())?)
+}
+
+fn on_parens() -> Result<i32, ParseIntError> {
+    let x = "8".parse::<i32>();
+
+    Ok((x)?)
+}
+
+fn on_block() -> Result<i32, ParseIntError> {
+    let x = "9".parse::<i32>();
+
+    Ok({x}?)
+}
+
+fn on_field() -> Result<i32, ParseIntError> {
+    struct Pair<A, B> { a: A, b: B }
+
+    let x = Pair { a: "10".parse::<i32>(), b: 0 };
+
+    Ok(x.a?)
+}
+
+fn on_tuple_field() -> Result<i32, ParseIntError> {
+    let x = ("11".parse::<i32>(), 0);
+
+    Ok(x.0?)
+}
+
+fn on_try() -> Result<i32, ParseIntError> {
+    let x = "12".parse::<i32>().map(|i| i.to_string().parse::<i32>());
+
+    Ok(x??)
+}
+
+fn on_binary_op() -> Result<i32, ParseIntError> {
+    let x = 13 - "14".parse::<i32>()?;
+    let y = "15".parse::<i32>()? - 16;
+    let z = "17".parse::<i32>()? - "18".parse::<i32>()?;
+
+    Ok(x + y + z)
+}
+
+fn on_index() -> Result<i32, ParseIntError> {
+    let x = [19];
+    let y = "0".parse::<usize>();
+
+    Ok(x[y?])
+}
+
+fn on_args() -> Result<i32, ParseIntError> {
+    fn sub(x: i32, y: i32) -> i32 { x - y }
+
+    let x = "20".parse();
+    let y = "21".parse();
+
+    Ok(sub(x?, y?))
+}
+
+fn on_if() -> Result<i32, ParseIntError> {
+    Ok(if true {
+        "22".parse::<i32>()
+    } else {
+        "23".parse::<i32>()
+    }?)
+}
+
+fn on_if_let() -> Result<i32, ParseIntError> {
+    Ok(if let Ok(..) = "24".parse::<i32>() {
+        "25".parse::<i32>()
+    } else {
+        "26".parse::<i32>()
+    }?)
+}
+
+fn on_match() -> Result<i32, ParseIntError> {
+    Ok(match "27".parse::<i32>() {
+        Err(..) => "28".parse::<i32>(),
+        Ok(..) => "29".parse::<i32>(),
+    }?)
+}
+
+fn tight_binding() -> Result<bool, ()> {
+    fn ok<T>(x: T) -> Result<T, ()> { Ok(x) }
+
+    let x = ok(true);
+    Ok(!x?)
+}
+
+// just type check
+fn merge_error() -> Result<i32, Error> {
+    let mut s = String::new();
+
+    File::open("foo.txt")?.read_to_string(&mut s)?;
+
+    Ok(s.parse::<i32>()? + 1)
+}
+
+fn main() {
+    assert_eq!(Ok(3), on_method());
+
+    assert_eq!(Ok("3".to_string()), in_chain());
+
+    assert_eq!(Ok(4), on_call());
+
+    assert_eq!(Ok(5), nested());
+
+    assert_eq!(Ok(6), on_path());
+
+    assert_eq!(Ok(7), on_macro());
+
+    assert_eq!(Ok(8), on_parens());
+
+    assert_eq!(Ok(9), on_block());
+
+    assert_eq!(Ok(10), on_field());
+
+    assert_eq!(Ok(11), on_tuple_field());
+
+    assert_eq!(Ok(12), on_try());
+
+    assert_eq!(Ok(-3), on_binary_op());
+
+    assert_eq!(Ok(19), on_index());
+
+    assert_eq!(Ok(-1), on_args());
+
+    assert_eq!(Ok(22), on_if());
+
+    assert_eq!(Ok(25), on_if_let());
+
+    assert_eq!(Ok(29), on_match());
+
+    assert_eq!(Ok(false), tight_binding());
+}
+
+enum Error {
+    Io(io::Error),
+    Parse(ParseIntError),
+}
+
+impl From<io::Error> for Error {
+    fn from(e: io::Error) -> Error {
+        Error::Io(e)
+    }
+}
+
+impl From<ParseIntError> for Error {
+    fn from(e: ParseIntError) -> Error {
+        Error::Parse(e)
+    }
+}
diff --git a/src/test/rustdoc/issue-15347.rs b/src/test/rustdoc/issue-15347.rs
index 97c37bbc1ed..266a3089194 100644
--- a/src/test/rustdoc/issue-15347.rs
+++ b/src/test/rustdoc/issue-15347.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags:--no-defaults --passes "collapse-docs" --passes "unindent-comments"
+// compile-flags:--no-defaults --passes collapse-docs --passes unindent-comments
 
 // @has issue_15347/fn.foo.html
 #[doc(hidden)]
diff --git a/src/test/rustdoc/issue-27104.rs b/src/test/rustdoc/issue-27104.rs
new file mode 100644
index 00000000000..5fa093d8f29
--- /dev/null
+++ b/src/test/rustdoc/issue-27104.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.
+
+// compile-flags:--no-defaults --passes strip-priv-imports
+// aux-build:empty.rs
+// ignore-cross-compile
+
+// @has issue_27104/index.html
+// @!has - 'extern crate std'
+// @!has - 'use std::prelude::'
+
+// @has - 'pub extern crate empty'
+pub extern crate empty;