about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Cargo.lock63
-rw-r--r--src/Cargo.toml1
-rw-r--r--src/bootstrap/bin/rustc.rs16
-rw-r--r--src/bootstrap/bootstrap.py33
-rw-r--r--src/bootstrap/builder.rs14
-rw-r--r--src/bootstrap/channel.rs2
-rw-r--r--src/bootstrap/compile.rs2
-rw-r--r--src/bootstrap/flags.rs12
-rw-r--r--src/bootstrap/test.rs46
-rw-r--r--src/bootstrap/tool.rs2
-rw-r--r--src/doc/grammar.md23
-rw-r--r--src/doc/rustc/src/lints/listing/deny-by-default.md37
-rw-r--r--src/doc/rustdoc/src/documentation-tests.md16
-rw-r--r--src/doc/tutorial.md2
-rw-r--r--src/liballoc/Cargo.toml2
-rw-r--r--src/liballoc/alloc.rs47
-rw-r--r--src/liballoc/lib.rs10
-rw-r--r--src/liballoc/slice.rs13
-rw-r--r--src/liballoc/str.rs7
-rw-r--r--src/liballoc/tests/lib.rs1
-rw-r--r--src/liballoc/vec.rs3
-rw-r--r--src/liballoc_jemalloc/lib.rs7
-rw-r--r--src/liballoc_system/lib.rs27
-rw-r--r--src/libarena/lib.rs1
-rw-r--r--src/libcore/Cargo.toml2
-rw-r--r--src/libcore/clone.rs1
-rw-r--r--src/libcore/internal_macros.rs14
-rw-r--r--src/libcore/intrinsics.rs195
-rw-r--r--src/libcore/lib.rs19
-rw-r--r--src/libcore/marker.rs1
-rw-r--r--src/libcore/num/f32.rs4
-rw-r--r--src/libcore/num/f64.rs4
-rw-r--r--src/libcore/num/mod.rs2
-rw-r--r--src/libcore/ops/range.rs38
-rw-r--r--src/libcore/option.rs36
-rw-r--r--src/libcore/prelude/v1.rs10
-rw-r--r--src/libcore/ptr.rs640
-rw-r--r--src/libcore/slice/mod.rs1153
-rw-r--r--src/libcore/str/mod.rs590
-rw-r--r--src/libcore/tests/lib.rs4
-rw-r--r--src/libcore/tests/num/uint_macros.rs1
-rw-r--r--src/libcore/tests/ptr.rs89
-rw-r--r--src/libcore/tests/slice.rs34
-rw-r--r--src/libfmt_macros/lib.rs82
-rw-r--r--src/libproc_macro/lib.rs2
-rw-r--r--src/librustc/hir/lowering.rs1
-rw-r--r--src/librustc/hir/print.rs4
-rw-r--r--src/librustc/ich/impls_syntax.rs10
-rw-r--r--src/librustc/ich/impls_ty.rs5
-rw-r--r--src/librustc/infer/region_constraints/mod.rs7
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/lint/builtin.rs16
-rw-r--r--src/librustc/middle/cstore.rs3
-rw-r--r--src/librustc/middle/lang_items.rs3
-rw-r--r--src/librustc/middle/liveness.rs106
-rw-r--r--src/librustc/middle/region.rs78
-rw-r--r--src/librustc/mir/interpret/error.rs15
-rw-r--r--src/librustc/mir/interpret/mod.rs71
-rw-r--r--src/librustc/mir/interpret/value.rs26
-rw-r--r--src/librustc/mir/mod.rs2
-rw-r--r--src/librustc/session/config.rs4
-rw-r--r--src/librustc/traits/error_reporting.rs10
-rw-r--r--src/librustc/traits/fulfill.rs25
-rw-r--r--src/librustc/traits/project.rs145
-rw-r--r--src/librustc/ty/sty.rs11
-rw-r--r--src/librustc/ty/util.rs151
-rw-r--r--src/librustc_allocator/expand.rs3
-rw-r--r--src/librustc_codegen_llvm/abi.rs8
-rw-r--r--src/librustc_codegen_llvm/back/link.rs27
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs17
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs12
-rw-r--r--src/librustc_codegen_llvm/lib.rs1
-rw-r--r--src/librustc_codegen_llvm/mir/constant.rs56
-rw-r--r--src/librustc_codegen_llvm/mir/operand.rs12
-rw-r--r--src/librustc_codegen_llvm/type_of.rs10
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs136
-rw-r--r--src/librustc_data_structures/Cargo.toml2
-rw-r--r--src/librustc_data_structures/bitvec.rs37
-rw-r--r--src/librustc_data_structures/snapshot_map/mod.rs6
-rw-r--r--src/librustc_driver/lib.rs3
-rw-r--r--src/librustc_lint/lib.rs8
-rw-r--r--src/librustc_metadata/creader.rs24
-rw-r--r--src/librustc_metadata/cstore.rs5
-rw-r--r--src/librustc_metadata/cstore_impl.rs9
-rw-r--r--src/librustc_metadata/encoder.rs3
-rw-r--r--src/librustc_metadata/schema.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs13
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs10
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/dfs.rs265
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs257
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/values.rs108
-rw-r--r--src/librustc_mir/hair/cx/mod.rs6
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs2
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs5
-rw-r--r--src/librustc_mir/interpret/cast.rs4
-rw-r--r--src/librustc_mir/interpret/const_eval.rs220
-rw-r--r--src/librustc_mir/interpret/eval_context.rs73
-rw-r--r--src/librustc_mir/interpret/machine.rs3
-rw-r--r--src/librustc_mir/interpret/memory.rs169
-rw-r--r--src/librustc_mir/interpret/place.rs20
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs2
-rw-r--r--src/librustc_mir/lib.rs14
-rw-r--r--src/librustc_mir/monomorphize/collector.rs2
-rw-r--r--src/librustc_mir/transform/promote_consts.rs162
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs70
-rw-r--r--src/librustc_mir/util/pretty.rs8
-rw-r--r--src/librustc_passes/ast_validation.rs6
-rw-r--r--src/librustc_passes/loops.rs2
-rw-r--r--src/librustc_plugin/registry.rs8
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs3
-rw-r--r--src/librustc_resolve/check_unused.rs4
-rw-r--r--src/librustc_resolve/lib.rs73
-rw-r--r--src/librustc_resolve/macros.rs18
-rw-r--r--src/librustc_resolve/resolve_imports.rs51
-rw-r--r--src/librustc_target/abi/mod.rs2
-rw-r--r--src/librustc_target/lib.rs1
-rw-r--r--src/librustc_target/spec/linux_musl_base.rs11
-rw-r--r--src/librustc_target/spec/mod.rs35
-rw-r--r--src/librustc_traits/normalize_projection_ty.rs10
-rw-r--r--src/librustc_typeck/check/autoderef.rs28
-rw-r--r--src/librustc_typeck/check/intrinsic.rs5
-rw-r--r--src/librustc_typeck/diagnostics.rs26
-rw-r--r--src/librustc_typeck/lib.rs31
-rw-r--r--src/librustdoc/clean/auto_trait.rs51
-rw-r--r--src/librustdoc/clean/inline.rs8
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/libstd/alloc.rs61
-rw-r--r--src/libstd/f32.rs12
-rw-r--r--src/libstd/f64.rs12
-rw-r--r--src/libstd/lib.rs9
-rw-r--r--src/libsyntax/ast.rs3
-rw-r--r--src/libsyntax/ext/base.rs31
-rw-r--r--src/libsyntax/ext/derive.rs3
-rw-r--r--src/libsyntax/ext/expand.rs25
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs9
-rw-r--r--src/libsyntax/lib.rs3
-rw-r--r--src/libsyntax/parse/lexer/comments.rs14
-rw-r--r--src/libsyntax/parse/lexer/mod.rs108
-rw-r--r--src/libsyntax/parse/token.rs50
-rw-r--r--src/libsyntax/print/pprust.rs2
-rw-r--r--src/libsyntax/std_inject.rs3
-rw-r--r--src/libsyntax/str.rs1
-rw-r--r--src/libsyntax/test.rs3
-rw-r--r--src/libsyntax_ext/asm.rs21
-rw-r--r--src/libsyntax_ext/format.rs9
-rw-r--r--src/libsyntax_ext/lib.rs8
-rw-r--r--src/libsyntax_ext/proc_macro_registrar.rs3
-rw-r--r--src/libsyntax_pos/edition.rs (renamed from src/libsyntax/edition.rs)2
-rw-r--r--src/libsyntax_pos/hygiene.rs13
-rw-r--r--src/libsyntax_pos/lib.rs25
-rw-r--r--src/libsyntax_pos/symbol.rs69
-rw-r--r--src/libtest/formatters/pretty.rs4
-rw-r--r--src/libtest/formatters/terse.rs4
m---------src/llvm0
-rw-r--r--src/rtstartup/rsbegin.rs31
-rw-r--r--src/rustc/Cargo.toml2
-rw-r--r--src/rustllvm/llvm-rebuild-trigger2
-rw-r--r--src/stage0.txt2
-rw-r--r--src/test/COMPILER_TESTS.md10
-rw-r--r--src/test/codegen/function-arguments.rs10
-rw-r--r--src/test/codegen/link_section.rs8
-rw-r--r--src/test/compile-fail/array_const_index-0.rs5
-rw-r--r--src/test/compile-fail/array_const_index-1.rs5
-rw-r--r--src/test/compile-fail/const-slice-oob.rs5
-rw-r--r--src/test/compile-fail/eval-enum.rs4
-rw-r--r--src/test/compile-fail/issue-38293.rs10
-rw-r--r--src/test/incremental/warnings-reemitted.rs1
-rw-r--r--src/test/mir-opt/end_region_destruction_extents_1.rs8
-rw-r--r--src/test/mir-opt/match_false_edges.rs3
-rw-r--r--src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs7
-rw-r--r--src/test/run-fail/overflowing-add.rs2
-rw-r--r--src/test/run-fail/overflowing-mul.rs2
-rw-r--r--src/test/run-fail/overflowing-neg.rs2
-rw-r--r--src/test/run-fail/overflowing-sub.rs2
-rw-r--r--src/test/run-make-fulldeps/issue-36710/Makefile12
-rw-r--r--src/test/run-make-fulldeps/tools.mk2
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/plugin_args.rs2
-rw-r--r--src/test/run-pass/auxiliary/edition-kw-macro-2015.rs38
-rw-r--r--src/test/run-pass/auxiliary/edition-kw-macro-2018.rs38
-rw-r--r--src/test/run-pass/edition-keywords-2015-2015.rs43
-rw-r--r--src/test/run-pass/edition-keywords-2015-2018.rs43
-rw-r--r--src/test/run-pass/edition-keywords-2018-2015.rs43
-rw-r--r--src/test/run-pass/edition-keywords-2018-2018.rs43
-rw-r--r--src/test/run-pass/issue-49955-2.rs26
-rw-r--r--src/test/run-pass/issue-49955.rs30
-rw-r--r--src/test/run-pass/nll/get_default.rs31
-rw-r--r--src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs25
-rw-r--r--src/test/rustdoc/auto-impl-primitive.rs17
-rw-r--r--src/test/ui/E0508.ast.nll.stderr9
-rw-r--r--src/test/ui/E0508.ast.stderr12
-rw-r--r--src/test/ui/E0508.mir.stderr9
-rw-r--r--src/test/ui/E0508.rs20
-rw-r--r--src/test/ui/auxiliary/edition-kw-macro-2015.rs38
-rw-r--r--src/test/ui/auxiliary/edition-kw-macro-2018.rs38
-rw-r--r--src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr15
-rw-r--r--src/test/ui/const-eval-overflow-2.rs2
-rw-r--r--src/test/ui/const-eval-overflow-4.rs2
-rw-r--r--src/test/ui/const-eval-overflow-4.stderr6
-rw-r--r--src/test/ui/const-eval/conditional_array_execution.rs1
-rw-r--r--src/test/ui/const-eval/conditional_array_execution.stderr12
-rw-r--r--src/test/ui/const-eval/issue-43197.rs1
-rw-r--r--src/test/ui/const-eval/issue-43197.stderr18
-rw-r--r--src/test/ui/const-eval/issue-44578.rs1
-rw-r--r--src/test/ui/const-eval/issue-44578.stderr10
-rw-r--r--src/test/ui/const-eval/issue-50706.rs47
-rw-r--r--src/test/ui/const-eval/promoted_errors.rs2
-rw-r--r--src/test/ui/const-eval/promoted_errors.stderr22
-rw-r--r--src/test/ui/const-eval/pub_const_err.rs1
-rw-r--r--src/test/ui/const-eval/pub_const_err.stderr14
-rw-r--r--src/test/ui/const-eval/pub_const_err_bin.rs1
-rw-r--r--src/test/ui/const-eval/pub_const_err_bin.stderr14
-rw-r--r--src/test/ui/const-len-underflow-separate-spans.rs2
-rw-r--r--src/test/ui/const-len-underflow-separate-spans.stderr6
-rw-r--r--src/test/ui/edition-keywords-2015-2015-expansion.rs27
-rw-r--r--src/test/ui/edition-keywords-2015-2015-parsing.rs32
-rw-r--r--src/test/ui/edition-keywords-2015-2015-parsing.stderr14
-rw-r--r--src/test/ui/edition-keywords-2015-2018-expansion.rs24
-rw-r--r--src/test/ui/edition-keywords-2015-2018-expansion.stderr10
-rw-r--r--src/test/ui/edition-keywords-2015-2018-parsing.rs32
-rw-r--r--src/test/ui/edition-keywords-2015-2018-parsing.stderr14
-rw-r--r--src/test/ui/edition-keywords-2018-2015-expansion.rs27
-rw-r--r--src/test/ui/edition-keywords-2018-2015-parsing.rs32
-rw-r--r--src/test/ui/edition-keywords-2018-2015-parsing.stderr32
-rw-r--r--src/test/ui/edition-keywords-2018-2018-expansion.rs24
-rw-r--r--src/test/ui/edition-keywords-2018-2018-expansion.stderr10
-rw-r--r--src/test/ui/edition-keywords-2018-2018-parsing.rs32
-rw-r--r--src/test/ui/edition-keywords-2018-2018-parsing.stderr32
-rw-r--r--src/test/ui/error-codes/E0080.stderr8
-rw-r--r--src/test/ui/error-codes/E0646.rs (renamed from src/test/run-pass/align-offset-sign.rs)9
-rw-r--r--src/test/ui/error-codes/E0646.stderr9
-rw-r--r--src/test/ui/error-codes/E0647.rs (renamed from src/test/run-make-fulldeps/issue-36710/foo.cpp)18
-rw-r--r--src/test/ui/error-codes/E0647.stderr11
-rw-r--r--src/test/ui/fmt/format-string-error.rs11
-rw-r--r--src/test/ui/fmt/format-string-error.stderr44
-rw-r--r--src/test/ui/imports/rfc-1560-warning-cycle.rs6
-rw-r--r--src/test/ui/imports/rfc-1560-warning-cycle.stderr25
-rw-r--r--src/test/ui/issue-50714-1.rs22
-rw-r--r--src/test/ui/issue-50714-1.stderr11
-rw-r--r--src/test/ui/issue-50714.rs14
-rw-r--r--src/test/ui/issue-50714.stderr9
-rw-r--r--src/test/ui/issue-50761.rs33
-rw-r--r--src/test/ui/issue-50802.rs (renamed from src/test/run-make-fulldeps/issue-36710/foo.rs)10
-rw-r--r--src/test/ui/issue-50802.stderr9
-rw-r--r--src/test/ui/label_break_value_continue.rs1
-rw-r--r--src/test/ui/label_break_value_continue.stderr8
-rw-r--r--src/test/ui/label_break_value_unlabeled_break.rs1
-rw-r--r--src/test/ui/label_break_value_unlabeled_break.stderr4
-rw-r--r--src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs9
-rw-r--r--src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr36
-rw-r--r--src/test/ui/lint/unused_labels.rs96
-rw-r--r--src/test/ui/lint/unused_labels.stderr63
-rw-r--r--src/test/ui/loops-reject-duplicate-labels-2.rs1
-rw-r--r--src/test/ui/loops-reject-duplicate-labels-2.stderr18
-rw-r--r--src/test/ui/loops-reject-duplicate-labels.rs1
-rw-r--r--src/test/ui/loops-reject-duplicate-labels.stderr18
-rw-r--r--src/test/ui/nll/get_default.nll.stderr54
-rw-r--r--src/test/ui/nll/get_default.rs6
-rw-r--r--src/test/ui/nll/get_default.stderr54
-rw-r--r--src/test/ui/suggestions/suggest-labels.rs2
m---------src/tools/clippy25
-rw-r--r--src/tools/compiletest/src/common.rs3
-rw-r--r--src/tools/compiletest/src/main.rs6
-rw-r--r--src/tools/compiletest/src/runtest.rs98
m---------src/tools/rls0
-rw-r--r--src/tools/rustdoc/Cargo.toml2
m---------src/tools/rustfmt28
268 files changed, 4303 insertions, 4325 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 00cc530e632..8c2d8fc989b 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -288,12 +288,12 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.0.200"
+version = "0.0.202"
 dependencies = [
  "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "clippy-mini-macro-test 0.2.0",
- "clippy_lints 0.0.200",
+ "clippy_lints 0.0.202",
  "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -311,6 +311,27 @@ version = "0.2.0"
 [[package]]
 name = "clippy_lints"
 version = "0.0.200"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "clippy_lints"
+version = "0.0.202"
 dependencies = [
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -588,7 +609,7 @@ dependencies = [
 
 [[package]]
 name = "ena"
-version = "0.9.2"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1478,16 +1499,17 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.0.13"
+version = "2.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1623,7 +1645,7 @@ version = "0.128.0"
 dependencies = [
  "cargo 0.29.0",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy_lints 0.0.200",
+ "clippy_lints 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1632,12 +1654,12 @@ dependencies = [
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-rustc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustfmt-nightly 0.7.0",
@@ -1645,6 +1667,7 @@ dependencies = [
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1678,7 +1701,7 @@ dependencies = [
 
 [[package]]
 name = "rls-rustc"
-version = "0.2.2"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -1696,7 +1719,7 @@ name = "rls-vfs"
 version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1748,7 +1771,7 @@ version = "128.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1955,7 +1978,7 @@ name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2738,14 +2761,6 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "toml"
 version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -2984,6 +2999,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
 "checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873"
 "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
+"checksum clippy_lints 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)" = "d2432663f6bdb90255dcf9df5ca504f99b575bb471281591138f62f9d31f863b"
 "checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c"
 "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
 "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
@@ -3005,7 +3021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
 "checksum elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4511b63d69dd5d31e8e29aed2c132c413f87acea8035d0584801feaab9dd1f0f"
-"checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834"
+"checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621"
 "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "be27f8ea102a7182093a80d98f0b78623b580eda8791cbe8e2345fe6e57567a6"
@@ -3098,7 +3114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
-"checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d"
+"checksum racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "e713729f45f12df5c5e182d39506766f76c09133fb661d3622e0ddf8078911c2"
 "checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9"
 "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
 "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
@@ -3114,7 +3130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da9794cd1f80f2cb888c00641a32f9855d0226c954ee31cef145784914c7142e"
 "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
 "checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988"
-"checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea"
+"checksum rls-rustc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ed5342b2bbbe8663c04600af506c8902b6b4d3e627b006eb1bd65aa14805f4d"
 "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
 "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb"
 "checksum rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7374a2b466e6e3ce489e045302e304849355faf7fd033d4d95e6e86e48c313b4"
@@ -3171,7 +3187,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
 "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
-"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
 "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
 "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8"
 "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
diff --git a/src/Cargo.toml b/src/Cargo.toml
index 1518e8d910f..7504b43e20c 100644
--- a/src/Cargo.toml
+++ b/src/Cargo.toml
@@ -64,4 +64,3 @@ cargo = { path = "tools/cargo" }
 # RLS depends on `rustfmt` from crates.io, so we put this in a `[patch]` section
 # for crates.io
 rustfmt-nightly = { path = "tools/rustfmt" }
-clippy_lints = { path = "tools/clippy/clippy_lints" }
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 76d0e6e28ae..6f27402233f 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -268,15 +268,6 @@ fn main() {
         if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
             cmd.arg(format!("-Clinker={}", host_linker));
         }
-
-        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
-            if s == "true" {
-                cmd.arg("-C").arg("target-feature=+crt-static");
-            }
-            if s == "false" {
-                cmd.arg("-C").arg("target-feature=-crt-static");
-            }
-        }
     }
 
     if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() {
@@ -297,7 +288,12 @@ fn main() {
     }
 
     if verbose > 1 {
-        eprintln!("rustc command: {:?}", cmd);
+        eprintln!(
+            "rustc command: {:?}={:?} {:?}",
+            bootstrap::util::dylib_path_var(),
+            env::join_paths(&dylib_path).unwrap(),
+            cmd,
+        );
         eprintln!("sysroot: {:?}", sysroot);
         eprintln!("libdir: {:?}", libdir);
     }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 28f5192f2cd..487440becf6 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -489,7 +489,7 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, self.build, "stage0")
 
-    def get_toml(self, key, section=None):
+    def get_toml(self, key):
         """Returns the value of the given key in config.toml, otherwise returns None
 
         >>> rb = RustBuild()
@@ -501,29 +501,12 @@ class RustBuild(object):
 
         >>> rb.get_toml("key3") is None
         True
-
-        Optionally also matches the section the key appears in
-
-        >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
-        >>> rb.get_toml('key', 'a')
-        'value1'
-        >>> rb.get_toml('key', 'b')
-        'value2'
-        >>> rb.get_toml('key', 'c') is None
-        True
         """
-
-        cur_section = None
         for line in self.config_toml.splitlines():
-            section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
-            if section_match is not None:
-                cur_section = section_match.group(1)
-
             match = re.match(r'^{}\s*=(.*)$'.format(key), line)
             if match is not None:
                 value = match.group(1)
-                if section is None or section == cur_section:
-                    return self.get_string(value) or value.strip()
+                return self.get_string(value) or value.strip()
         return None
 
     def cargo(self):
@@ -606,17 +589,7 @@ class RustBuild(object):
         env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
             (os.pathsep + env["LIBRARY_PATH"]) \
             if "LIBRARY_PATH" in env else ""
-        env["RUSTFLAGS"] = "-Cdebuginfo=2 "
-
-        build_section = "target.{}".format(self.build_triple())
-        target_features = []
-        if self.get_toml("crt-static", build_section) == "true":
-            target_features += ["+crt-static"]
-        elif self.get_toml("crt-static", build_section) == "false":
-            target_features += ["-crt-static"]
-        if target_features:
-            env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " "
-
+        env["RUSTFLAGS"] = "-Cdebuginfo=2"
         env["PATH"] = os.path.join(self.bin_root(), "bin") + \
             os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index cc1e66332a3..84d29400669 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -584,11 +584,10 @@ impl<'a> Builder<'a> {
             cargo.env("RUST_CHECK", "1");
         }
 
-        // If we were invoked from `make` then that's already got a jobserver
-        // set up for us so no need to tell Cargo about jobs all over again.
-        if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() {
-             cargo.arg("-j").arg(self.jobs().to_string());
-        }
+        cargo.arg("-j").arg(self.jobs().to_string());
+        // Remove make-related flags to ensure Cargo can correctly set things up
+        cargo.env_remove("MAKEFLAGS");
+        cargo.env_remove("MFLAGS");
 
         // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
         // Force cargo to output binaries with disambiguating hashes in the name
@@ -698,10 +697,6 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTC_CRT_STATIC", x.to_string());
         }
 
-        if let Some(x) = self.crt_static(compiler.host) {
-            cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
-        }
-
         // Enable usage of unstable features
         cargo.env("RUSTC_BOOTSTRAP", "1");
         self.add_rust_test_threads(&mut cargo);
@@ -1461,6 +1456,7 @@ mod __test {
             rustc_args: vec![],
             fail_fast: true,
             doc_tests: DocTests::No,
+            bless: false,
         };
 
         let build = Build::new(config);
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index 3453933a965..a2495f68c1f 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -24,7 +24,7 @@ use Build;
 use config::Config;
 
 // The version number
-pub const CFG_RELEASE_NUM: &str = "1.27.0";
+pub const CFG_RELEASE_NUM: &str = "1.28.0";
 
 pub struct GitInfo {
     inner: Option<Info>,
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 8e0227f8fe1..231ed9d40d2 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -972,7 +972,7 @@ impl Step for Assemble {
 
         // Link the compiler binary itself into place
         let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host);
-        let rustc = out_dir.join(exe("rustc", &*host));
+        let rustc = out_dir.join(exe("rustc_binary", &*host));
         let bindir = sysroot.join("bin");
         t!(fs::create_dir_all(&bindir));
         let compiler = builder.rustc(target_compiler);
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 5315a3028ff..90dd5d819b0 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -59,6 +59,8 @@ pub enum Subcommand {
     },
     Test {
         paths: Vec<PathBuf>,
+        /// Whether to automatically update stderr/stdout files
+        bless: bool,
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
@@ -173,6 +175,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
                 );
                 opts.optflag("", "no-doc", "do not run doc tests");
                 opts.optflag("", "doc", "only run doc tests");
+                opts.optflag("", "bless", "update all stderr/stdout files of failing ui tests");
             },
             "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
             "clean" => { opts.optflag("", "all", "clean all build artifacts"); },
@@ -258,6 +261,7 @@ Arguments:
         ./x.py test src/test/run-pass
         ./x.py test src/libstd --test-args hash_map
         ./x.py test src/libstd --stage 0
+        ./x.py test src/test/ui --bless
 
     If no arguments are passed then the complete artifacts for that stage are
     compiled and tested.
@@ -322,6 +326,7 @@ Arguments:
             "test" => {
                 Subcommand::Test {
                     paths,
+                    bless: matches.opt_present("bless"),
                     test_args: matches.opt_strs("test-args"),
                     rustc_args: matches.opt_strs("rustc-args"),
                     fail_fast: !matches.opt_present("no-fail-fast"),
@@ -424,6 +429,13 @@ impl Subcommand {
             _ => DocTests::Yes,
         }
     }
+
+    pub fn bless(&self) -> bool {
+        match *self {
+            Subcommand::Test { bless, .. } => bless,
+            _ => false,
+        }
+    }
 }
 
 fn split(s: Vec<String>) -> Vec<String> {
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 1f81a617237..7a4924f03c8 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -47,6 +47,16 @@ pub enum TestKind {
     Bench,
 }
 
+impl From<Kind> for TestKind {
+    fn from(kind: Kind) -> Self {
+        match kind {
+            Kind::Test => TestKind::Test,
+            Kind::Bench => TestKind::Bench,
+            _ => panic!("unexpected kind in crate: {:?}", kind)
+        }
+    }
+}
+
 impl TestKind {
     // Return the cargo subcommand for this test kind
     fn subcommand(self) -> &'static str {
@@ -951,6 +961,10 @@ impl Step for Compiletest {
         cmd.arg("--host").arg(&*compiler.host);
         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
 
+        if builder.config.cmd.bless() {
+            cmd.arg("--bless");
+        }
+
         if let Some(ref nodejs) = builder.config.nodejs {
             cmd.arg("--nodejs").arg(nodejs);
         }
@@ -1342,13 +1356,7 @@ impl Step for CrateLibrustc {
 
         for krate in builder.in_tree_crates("rustc-main") {
             if run.path.ends_with(&krate.path) {
-                let test_kind = if builder.kind == Kind::Test {
-                    TestKind::Test
-                } else if builder.kind == Kind::Bench {
-                    TestKind::Bench
-                } else {
-                    panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-                };
+                let test_kind = builder.kind.into();
 
                 builder.ensure(CrateLibrustc {
                     compiler,
@@ -1394,13 +1402,7 @@ impl Step for CrateNotDefault {
         let builder = run.builder;
         let compiler = builder.compiler(builder.top_stage, run.host);
 
-        let test_kind = if builder.kind == Kind::Test {
-            TestKind::Test
-        } else if builder.kind == Kind::Bench {
-            TestKind::Bench
-        } else {
-            panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-        };
+        let test_kind = builder.kind.into();
 
         builder.ensure(CrateNotDefault {
             compiler,
@@ -1461,13 +1463,7 @@ impl Step for Crate {
         let compiler = builder.compiler(builder.top_stage, run.host);
 
         let make = |mode: Mode, krate: &CargoCrate| {
-            let test_kind = if builder.kind == Kind::Test {
-                TestKind::Test
-            } else if builder.kind == Kind::Bench {
-                TestKind::Bench
-            } else {
-                panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-            };
+            let test_kind = builder.kind.into();
 
             builder.ensure(Crate {
                 compiler,
@@ -1625,13 +1621,7 @@ impl Step for CrateRustdoc {
     fn make_run(run: RunConfig) {
         let builder = run.builder;
 
-        let test_kind = if builder.kind == Kind::Test {
-            TestKind::Test
-        } else if builder.kind == Kind::Bench {
-            TestKind::Bench
-        } else {
-            panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-        };
+        let test_kind = builder.kind.into();
 
         builder.ensure(CrateRustdoc {
             host: run.host,
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 4b6e266f1e5..29f37b36e2a 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -431,7 +431,7 @@ impl Step for Rustdoc {
         // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
         // rustdoc a different name.
         let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target)
-            .join(exe("rustdoc-tool-binary", &target_compiler.host));
+            .join(exe("rustdoc_tool_binary", &target_compiler.host));
 
         // don't create a stage0-sysroot/bin directory.
         if target_compiler.stage > 0 {
diff --git a/src/doc/grammar.md b/src/doc/grammar.md
index 78432b6a965..ee9135b6578 100644
--- a/src/doc/grammar.md
+++ b/src/doc/grammar.md
@@ -101,29 +101,24 @@ properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and
 
 ### Identifiers
 
-The `ident` production is any nonempty Unicode[^non_ascii_idents] string of
+The `ident` production is any nonempty Unicode string of
 the following form:
 
-[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature
-  gated. This is expected to improve soon.
+- The first character is in one of the following ranges `U+0041` to `U+005A`
+("A" to "Z"), `U+0061` to `U+007A` ("a" to "z"), or `U+005F` ("\_").
+- The remaining characters are in the range `U+0030` to `U+0039` ("0" to "9"),
+or any of the prior valid initial characters.
 
-- The first character has property `XID_start`
-- The remaining characters have property `XID_continue`
-
-that does _not_ occur in the set of [keywords](#keywords).
-
-> **Note**: `XID_start` and `XID_continue` as character properties cover the
-> character ranges used to form the more familiar C and Java language-family
-> identifiers.
+as long as the identifier does _not_ occur in the set of [keywords](#keywords).
 
 ### Delimiter-restricted productions
 
 Some productions are defined by exclusion of particular Unicode characters:
 
 - `non_null` is any single Unicode character aside from `U+0000` (null)
-- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
-- `non_single_quote` is `non_null` restricted to exclude `U+0027`  (`'`)
-- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
+- `non_eol` is any single Unicode character aside from `U+000A` (`'\n'`)
+- `non_single_quote` is any single Unicode character aside from `U+0027`  (`'`)
+- `non_double_quote` is any single Unicode character aside from `U+0022` (`"`)
 
 ## Comments
 
diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md
index ef76295f04d..3a85a40fd1f 100644
--- a/src/doc/rustc/src/lints/listing/deny-by-default.md
+++ b/src/doc/rustc/src/lints/listing/deny-by-default.md
@@ -91,43 +91,6 @@ The legacy_directory_ownership warning is issued when
 The warning can be fixed by renaming the parent module to "mod.rs" and moving
 it into its own directory if appropriate.
 
-## legacy-imports
-
-This lint detects names that resolve to ambiguous glob imports. Some example
-code that triggers this lint:
-
-```rust,ignore
-pub struct Foo;
-
-mod bar {
-    struct Foo;
-
-    mod baz {
-        use *;
-        use bar::*;
-        fn f(_: Foo) {}
-    }
-}
-```
-
-This will produce:
-
-```text
-error: `Foo` is ambiguous
- --> src/main.rs:9:17
-  |
-7 |         use *;
-  |             - `Foo` could refer to the name imported here
-8 |         use bar::*;
-  |             ------ `Foo` could also refer to the name imported here
-9 |         fn f(_: Foo) {}
-  |                 ^^^
-  |
-  = note: #[deny(legacy_imports)] on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #38260 <https://github.com/rust-lang/rust/issues/38260>
-```
-
 
 ## missing-fragment-specifier
 
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
index 3098587a8a4..fd7d1713ca5 100644
--- a/src/doc/rustdoc/src/documentation-tests.md
+++ b/src/doc/rustdoc/src/documentation-tests.md
@@ -268,10 +268,10 @@ not actually pass as a test.
 # fn foo() {}
 ```
 
-`compile_fail` tells `rustdoc` that the compilation should fail. If it
-compiles, then the test will fail. However please note that code failing
-with the current Rust release may work in a future release, as new features
-are added.
+The `no_run` attribute will compile your code, but not run it. This is
+important for examples such as "Here's how to retrieve a web page,"
+which you would want to ensure compiles, but might be run in a test
+environment that has no network access.
 
 ```text
 /// ```compile_fail
@@ -280,7 +280,7 @@ are added.
 /// ```
 ```
 
-The `no_run` attribute will compile your code, but not run it. This is
-important for examples such as "Here's how to retrieve a web page,"
-which you would want to ensure compiles, but might be run in a test
-environment that has no network access.
+`compile_fail` tells `rustdoc` that the compilation should fail. If it
+compiles, then the test will fail. However please note that code failing
+with the current Rust release may work in a future release, as new features
+are added.
diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md
index 87f3a0c765c..320283f31b5 100644
--- a/src/doc/tutorial.md
+++ b/src/doc/tutorial.md
@@ -1,3 +1,3 @@
 % The Rust Tutorial
 
-This tutorial has been deprecated in favor of [the Book](book/index.html). Go check that out instead!
+This tutorial has been deprecated in favor of [the Book](book/index.html), which is available free online and in dead tree form. Go check that out instead!
diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml
index 6383bd1e941..ada21e04b30 100644
--- a/src/liballoc/Cargo.toml
+++ b/src/liballoc/Cargo.toml
@@ -2,6 +2,8 @@
 authors = ["The Rust Project Developers"]
 name = "alloc"
 version = "0.0.0"
+autotests = false
+autobenches = false
 
 [lib]
 name = "alloc"
diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs
index 09d16b26520..79607b06f94 100644
--- a/src/liballoc/alloc.rs
+++ b/src/liballoc/alloc.rs
@@ -22,28 +22,6 @@ use core::usize;
 #[doc(inline)]
 pub use core::alloc::*;
 
-#[cfg(stage0)]
-extern "Rust" {
-    #[allocator]
-    #[rustc_allocator_nounwind]
-    fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
-    #[cold]
-    #[rustc_allocator_nounwind]
-    fn __rust_oom(err: *const u8) -> !;
-    #[rustc_allocator_nounwind]
-    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
-    #[rustc_allocator_nounwind]
-    fn __rust_realloc(ptr: *mut u8,
-                      old_size: usize,
-                      old_align: usize,
-                      new_size: usize,
-                      new_align: usize,
-                      err: *mut u8) -> *mut u8;
-    #[rustc_allocator_nounwind]
-    fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
-}
-
-#[cfg(not(stage0))]
 extern "Rust" {
     #[allocator]
     #[rustc_allocator_nounwind]
@@ -74,10 +52,7 @@ pub const Heap: Global = Global;
 unsafe impl GlobalAlloc for Global {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
-        #[cfg(not(stage0))]
         let ptr = __rust_alloc(layout.size(), layout.align());
-        #[cfg(stage0)]
-        let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0);
         ptr as *mut Opaque
     }
 
@@ -88,20 +63,13 @@ unsafe impl GlobalAlloc for Global {
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
-        #[cfg(not(stage0))]
         let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size);
-        #[cfg(stage0)]
-        let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(),
-                                 new_size, layout.align(), &mut 0);
         ptr as *mut Opaque
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
-        #[cfg(not(stage0))]
         let ptr = __rust_alloc_zeroed(layout.size(), layout.align());
-        #[cfg(stage0)]
-        let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0);
         ptr as *mut Opaque
     }
 }
@@ -152,14 +120,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     }
 }
 
-#[cfg(stage0)]
-#[lang = "box_free"]
-#[inline]
-unsafe fn old_box_free<T: ?Sized>(ptr: *mut T) {
-    box_free(Unique::new_unchecked(ptr))
-}
-
-#[cfg_attr(not(any(test, stage0)), lang = "box_free")]
+#[cfg_attr(not(test), lang = "box_free")]
 #[inline]
 pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     let ptr = ptr.as_ptr();
@@ -172,12 +133,6 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     }
 }
 
-#[cfg(stage0)]
-pub fn oom() -> ! {
-    unsafe { ::core::intrinsics::abort() }
-}
-
-#[cfg(not(stage0))]
 pub fn oom() -> ! {
     extern {
         #[lang = "oom"]
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index f7dd9d4f010..91de3ad0c39 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -75,7 +75,6 @@
 #![deny(missing_debug_implementations)]
 
 #![cfg_attr(test, allow(deprecated))] // rand
-#![cfg_attr(all(not(test), stage0), feature(float_internals))]
 #![cfg_attr(not(test), feature(exact_size_is_empty))]
 #![cfg_attr(not(test), feature(generator_trait))]
 #![cfg_attr(test, feature(rand, test))]
@@ -90,13 +89,10 @@
 #![feature(collections_range)]
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
-#![cfg_attr(stage0, feature(core_slice_ext))]
-#![cfg_attr(stage0, feature(core_str_ext))]
 #![feature(custom_attribute)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
 #![feature(fmt_internals)]
-#![cfg_attr(stage0, feature(fn_must_use))]
 #![feature(from_ref)]
 #![feature(fundamental)]
 #![feature(lang_items)]
@@ -122,7 +118,6 @@
 #![feature(exact_chunks)]
 #![feature(pointer_methods)]
 #![feature(inclusive_range_methods)]
-#![cfg_attr(stage0, feature(generic_param_attrs))]
 #![feature(rustc_const_unstable)]
 #![feature(const_vec_new)]
 
@@ -157,15 +152,10 @@ pub mod alloc;
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
 /// Use the `alloc` module instead.
-#[cfg(not(stage0))]
 pub mod heap {
     pub use alloc::*;
 }
 
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
-#[cfg(stage0)]
-pub mod heap;
 
 // Primitive types using the heaps above
 
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index 6caf12aa7eb..4427ac004f9 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -101,7 +101,6 @@ use core::cmp::Ordering::{self, Less};
 use core::mem::size_of;
 use core::mem;
 use core::ptr;
-#[cfg(stage0)] use core::slice::SliceExt;
 use core::{u8, u16, u32};
 
 use borrow::{Borrow, BorrowMut, ToOwned};
@@ -171,13 +170,9 @@ mod hack {
     }
 }
 
-#[cfg_attr(stage0, lang = "slice")]
-#[cfg_attr(not(stage0), lang = "slice_alloc")]
+#[lang = "slice_alloc"]
 #[cfg(not(test))]
 impl<T> [T] {
-    #[cfg(stage0)]
-    slice_core_methods!();
-
     /// Sorts the slice.
     ///
     /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case.
@@ -467,8 +462,7 @@ impl<T> [T] {
     }
 }
 
-#[cfg_attr(stage0, lang = "slice_u8")]
-#[cfg_attr(not(stage0), lang = "slice_u8_alloc")]
+#[lang = "slice_u8_alloc"]
 #[cfg(not(test))]
 impl [u8] {
     /// Returns a vector containing a copy of this slice where each byte
@@ -504,9 +498,6 @@ impl [u8] {
         me.make_ascii_lowercase();
         me
     }
-
-    #[cfg(stage0)]
-    slice_u8_core_methods!();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index 42efdea74b1..c10c0a69433 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -40,7 +40,6 @@
 
 use core::fmt;
 use core::str as core_str;
-#[cfg(stage0)] use core::str::StrExt;
 use core::str::pattern::Pattern;
 use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
 use core::mem;
@@ -158,13 +157,9 @@ impl ToOwned for str {
 }
 
 /// Methods for string slices.
-#[cfg_attr(stage0, lang = "str")]
-#[cfg_attr(not(stage0), lang = "str_alloc")]
+#[lang = "str_alloc"]
 #[cfg(not(test))]
 impl str {
-    #[cfg(stage0)]
-    str_core_methods!();
-
     /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
     ///
     /// # Examples
diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs
index 1c8ff316e55..081c473768f 100644
--- a/src/liballoc/tests/lib.rs
+++ b/src/liballoc/tests/lib.rs
@@ -25,7 +25,6 @@
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
 #![feature(exact_chunks)]
-#![feature(inclusive_range_methods)]
 
 extern crate alloc_system;
 extern crate core;
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index d30f8cd0fca..bf89b377b7e 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -73,9 +73,6 @@ use core::intrinsics::{arith_offset, assume};
 use core::iter::{FromIterator, FusedIterator, TrustedLen};
 use core::marker::PhantomData;
 use core::mem;
-#[cfg(not(test))]
-#[cfg(stage0)]
-use core::num::Float;
 use core::ops::Bound::{Excluded, Included, Unbounded};
 use core::ops::{Index, IndexMut, RangeBounds};
 use core::ops;
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index 4b8755877de..ce856eccd83 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -97,13 +97,6 @@ mod contents {
         ptr
     }
 
-    #[cfg(stage0)]
-    #[no_mangle]
-    #[rustc_std_internal_symbol]
-    pub unsafe extern fn __rde_oom() -> ! {
-        ::core::intrinsics::abort();
-    }
-
     #[no_mangle]
     #[rustc_std_internal_symbol]
     pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 7376ac0f15d..9490b54e675 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -73,33 +73,6 @@ unsafe impl Alloc for System {
     }
 }
 
-#[cfg(stage0)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-unsafe impl<'a> Alloc for &'a System {
-    #[inline]
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr)
-    }
-
-    #[inline]
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr)
-    }
-
-    #[inline]
-    unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
-        GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout)
-    }
-
-    #[inline]
-    unsafe fn realloc(&mut self,
-                      ptr: NonNull<Opaque>,
-                      layout: Layout,
-                      new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
-    }
-}
-
 #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
 mod realloc_fallback {
     use core::alloc::{GlobalAlloc, Opaque, Layout};
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index c79e0e14e3d..f7143a4f981 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -26,7 +26,6 @@
 #![feature(alloc)]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
-#![cfg_attr(stage0, feature(generic_param_attrs))]
 #![cfg_attr(test, feature(test))]
 
 #![allow(deprecated)]
diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml
index 24529f7a9d8..321ed892ea9 100644
--- a/src/libcore/Cargo.toml
+++ b/src/libcore/Cargo.toml
@@ -2,6 +2,8 @@
 authors = ["The Rust Project Developers"]
 name = "core"
 version = "0.0.0"
+autotests = false
+autobenches = false
 
 [lib]
 name = "core"
diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs
index f79f7351698..3b15ba2b4ab 100644
--- a/src/libcore/clone.rs
+++ b/src/libcore/clone.rs
@@ -153,7 +153,6 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T
 ///
 /// Implementations that cannot be described in Rust
 /// are implemented in `SelectionContext::copy_clone_conditions()` in librustc.
-#[cfg(not(stage0))]
 mod impls {
 
     use super::Clone;
diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs
index 58eef649287..db75f9bf210 100644
--- a/src/libcore/internal_macros.rs
+++ b/src/libcore/internal_macros.rs
@@ -86,17 +86,3 @@ macro_rules! forward_ref_op_assign {
         }
     }
 }
-
-#[cfg(stage0)]
-macro_rules! public_in_stage0 {
-    ( { $(#[$attr:meta])* } $($Item: tt)*) => {
-        $(#[$attr])* pub $($Item)*
-    }
-}
-
-#[cfg(not(stage0))]
-macro_rules! public_in_stage0 {
-    ( { $(#[$attr:meta])* } $($Item: tt)*) => {
-        $(#[$attr])* pub(crate) $($Item)*
-    }
-}
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 5ec6cb6c710..2e3f5cb65c9 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -962,122 +962,59 @@ extern "rust-intrinsic" {
     /// value is not necessarily valid to be used to actually access memory.
     pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
 
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-    /// and destination must *not* overlap.
+    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
+    /// and destination may *not* overlap.
     ///
-    /// For regions of memory which might overlap, use [`copy`] instead.
-    ///
-    /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`].
-    ///
-    /// [`copy`]: ./fn.copy.html
-    /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy
+    /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
     ///
     /// # Safety
     ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * The region of memory which begins at `src` and has a length of
-    ///   `count * size_of::<T>()` bytes must be *both* valid and initialized.
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count * size_of::<T>()` bytes must be valid (but may or may not be
-    ///   initialized).
-    ///
-    /// * The two regions of memory must *not* overlap.
-    ///
-    /// * `src` must be properly aligned.
-    ///
-    /// * `dst` must be properly aligned.
-    ///
-    /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
-    /// region at `dst` can be used or dropped after calling
-    /// `copy_nonoverlapping`.  `copy_nonoverlapping` creates bitwise copies of
-    /// `T`, regardless of whether `T: Copy`, which can result in undefined
-    /// behavior if both copies are used.
-    ///
-    /// [`Copy`]: ../marker/trait.Copy.html
+    /// Beyond requiring that the program must be allowed to access both regions
+    /// of memory, it is Undefined Behavior for source and destination to
+    /// overlap. Care must also be taken with the ownership of `src` and
+    /// `dst`. This method semantically moves the values of `src` into `dst`.
+    /// However it does not drop the contents of `dst`, or prevent the contents
+    /// of `src` from being dropped or used.
     ///
     /// # Examples
     ///
-    /// Manually implement [`Vec::append`]:
+    /// A safe swap function:
     ///
     /// ```
+    /// use std::mem;
     /// use std::ptr;
     ///
-    /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
-    /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
-    ///     let src_len = src.len();
-    ///     let dst_len = dst.len();
-    ///
-    ///     // Ensure that `dst` has enough capacity to hold all of `src`.
-    ///     dst.reserve(src_len);
-    ///
+    /// # #[allow(dead_code)]
+    /// fn swap<T>(x: &mut T, y: &mut T) {
     ///     unsafe {
-    ///         // The call to offset is always safe because `Vec` will never
-    ///         // allocate more than `isize::MAX` bytes.
-    ///         let dst = dst.as_mut_ptr().offset(dst_len as isize);
-    ///         let src = src.as_ptr();
-    ///
-    ///         // The two regions cannot overlap becuase mutable references do
-    ///         // not alias, and two different vectors cannot own the same
-    ///         // memory.
-    ///         ptr::copy_nonoverlapping(src, dst, src_len);
-    ///     }
+    ///         // Give ourselves some scratch space to work with
+    ///         let mut t: T = mem::uninitialized();
     ///
-    ///     unsafe {
-    ///         // Truncate `src` without dropping its contents.
-    ///         src.set_len(0);
+    ///         // Perform the swap, `&mut` pointers never alias
+    ///         ptr::copy_nonoverlapping(x, &mut t, 1);
+    ///         ptr::copy_nonoverlapping(y, x, 1);
+    ///         ptr::copy_nonoverlapping(&t, y, 1);
     ///
-    ///         // Notify `dst` that it now holds the contents of `src`.
-    ///         dst.set_len(dst_len + src_len);
+    ///         // y and t now point to the same thing, but we need to completely forget `t`
+    ///         // because it's no longer relevant.
+    ///         mem::forget(t);
     ///     }
     /// }
-    ///
-    /// let mut a = vec!['r'];
-    /// let mut b = vec!['u', 's', 't'];
-    ///
-    /// append(&mut a, &mut b);
-    ///
-    /// assert_eq!(a, &['r', 'u', 's', 't']);
-    /// assert!(b.is_empty());
     /// ```
-    ///
-    /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
     /// and destination may overlap.
     ///
-    /// If the source and destination will *never* overlap,
-    /// [`copy_nonoverlapping`] can be used instead.
-    ///
-    /// `copy` is semantically equivalent to C's [`memmove`].
-    ///
-    /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html
-    /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove
+    /// `copy` is semantically equivalent to C's `memmove`.
     ///
     /// # Safety
     ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * The region of memory which begins at `src` and has a length of
-    ///   `count * size_of::<T>()` bytes must be *both* valid and initialized.
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count * size_of::<T>()` bytes must be valid (but may or may not be
-    ///   initialized).
-    ///
-    /// * `src` must be properly aligned.
-    ///
-    /// * `dst` must be properly aligned.
-    ///
-    /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
-    /// region at `dst` can be used or dropped after calling `copy`. `copy`
-    /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which
-    /// can result in undefined behavior if both copies are used.
-    ///
-    /// [`Copy`]: ../marker/trait.Copy.html
+    /// Care must be taken with the ownership of `src` and `dst`.
+    /// This method semantically moves the values of `src` into `dst`.
+    /// However it does not drop the contents of `dst`, or prevent the contents of `src`
+    /// from being dropped or used.
     ///
     /// # Examples
     ///
@@ -1094,34 +1031,15 @@ extern "rust-intrinsic" {
     ///     dst
     /// }
     /// ```
+    ///
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
-    /// `val`.
-    ///
-    /// `write_bytes` is semantically equivalent to C's [`memset`].
-    ///
-    /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset
-    ///
-    /// # Safety
-    ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count` bytes must be valid.
-    ///
-    /// * `dst` must be properly aligned.
-    ///
-    /// Additionally, the caller must ensure that writing `count` bytes to the
-    /// given region of memory results in a valid value of `T`. Creating an
-    /// invalid value of `T` can result in undefined behavior. An example is
-    /// provided below.
+    /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
+    /// bytes of memory starting at `dst` to `val`.
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::ptr;
     ///
@@ -1132,23 +1050,6 @@ extern "rust-intrinsic" {
     /// }
     /// assert_eq!(vec, [b'a', b'a', 0, 0]);
     /// ```
-    ///
-    /// Creating an invalid value:
-    ///
-    /// ```no_run
-    /// use std::{mem, ptr};
-    ///
-    /// let mut v = Box::new(0i32);
-    ///
-    /// unsafe {
-    ///     // Leaks the previously held value by overwriting the `Box<T>` with
-    ///     // a null pointer.
-    ///     ptr::write_bytes(&mut v, 0, mem::size_of::<Box<i32>>());
-    /// }
-    ///
-    /// // At this point, using or dropping `v` results in undefined behavior.
-    /// // v = Box::new(0i32); // ERROR
-    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
 
@@ -1463,38 +1364,8 @@ extern "rust-intrinsic" {
     /// source as well as std's catch implementation.
     pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32;
 
-    /// Computes the byte offset that needs to be applied to `ptr` in order to
-    /// make it aligned to `align`.
-    /// If it is not possible to align `ptr`, the implementation returns
-    /// `usize::max_value()`.
-    ///
-    /// There are no guarantees whatsover that offsetting the pointer will not
-    /// overflow or go beyond the allocation that `ptr` points into.
-    /// It is up to the caller to ensure that the returned offset is correct
-    /// in all terms other than alignment.
-    ///
-    /// # Examples
-    ///
-    /// Accessing adjacent `u8` as `u16`
-    ///
-    /// ```
-    /// # #![feature(core_intrinsics)]
-    /// # fn foo(n: usize) {
-    /// # use std::intrinsics::align_offset;
-    /// # use std::mem::align_of;
-    /// # unsafe {
-    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
-    /// let ptr = &x[n] as *const u8;
-    /// let offset = align_offset(ptr as *const (), align_of::<u16>());
-    /// if offset < x.len() - n - 1 {
-    ///     let u16_ptr = ptr.offset(offset as isize) as *const u16;
-    ///     assert_ne!(*u16_ptr, 500);
-    /// } else {
-    ///     // while the pointer can be aligned via `offset`, it would point
-    ///     // outside the allocation
-    /// }
-    /// # } }
-    /// ```
+    #[cfg(stage0)]
+    /// docs my friends, its friday!
     pub fn align_offset(ptr: *const (), align: usize) -> usize;
 
     /// Emits a `!nontemporal` store according to LLVM (see their docs).
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 06fbfcecba8..77b5488084d 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -112,18 +112,13 @@
 #![feature(unwind_attributes)]
 #![feature(doc_alias)]
 #![feature(inclusive_range_methods)]
-
-#![cfg_attr(not(stage0), feature(mmx_target_feature))]
-#![cfg_attr(not(stage0), feature(tbm_target_feature))]
-#![cfg_attr(not(stage0), feature(sse4a_target_feature))]
-#![cfg_attr(not(stage0), feature(arm_target_feature))]
-#![cfg_attr(not(stage0), feature(powerpc_target_feature))]
-#![cfg_attr(not(stage0), feature(mips_target_feature))]
-#![cfg_attr(not(stage0), feature(aarch64_target_feature))]
-
-#![cfg_attr(stage0, feature(target_feature))]
-#![cfg_attr(stage0, feature(cfg_target_feature))]
-#![cfg_attr(stage0, feature(fn_must_use))]
+#![feature(mmx_target_feature)]
+#![feature(tbm_target_feature)]
+#![feature(sse4a_target_feature)]
+#![feature(arm_target_feature)]
+#![feature(powerpc_target_feature)]
+#![feature(mips_target_feature)]
+#![feature(aarch64_target_feature)]
 
 #[prelude_import]
 #[allow(unused)]
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index db5f50a99ca..6c8ee0eda11 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -611,7 +611,6 @@ pub unsafe auto trait Unpin {}
 ///
 /// Implementations that cannot be described in Rust
 /// are implemented in `SelectionContext::copy_clone_conditions()` in librustc.
-#[cfg(not(stage0))]
 mod copy_impls {
 
     use super::Copy;
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 4a7dc13f0f2..718dd42a615 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -19,7 +19,7 @@
 
 use mem;
 use num::Float;
-#[cfg(not(stage0))] use num::FpCategory;
+use num::FpCategory;
 use num::FpCategory as Fp;
 
 /// The radix or base of the internal representation of `f32`.
@@ -277,7 +277,6 @@ impl Float for f32 {
 
 // FIXME: remove (inline) this macro and the Float trait
 // when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
 #[unstable(feature = "core_float", issue = "32110")]
 macro_rules! f32_core_methods { () => {
     /// Returns `true` if this value is `NaN` and false otherwise.
@@ -553,7 +552,6 @@ macro_rules! f32_core_methods { () => {
 
 #[lang = "f32"]
 #[cfg(not(test))]
-#[cfg(not(stage0))]
 impl f32 {
     f32_core_methods!();
 }
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 801de5e87bd..f128c55c78a 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -19,7 +19,7 @@
 
 use mem;
 use num::Float;
-#[cfg(not(stage0))] use num::FpCategory;
+use num::FpCategory;
 use num::FpCategory as Fp;
 
 /// The radix or base of the internal representation of `f64`.
@@ -276,7 +276,6 @@ impl Float for f64 {
 
 // FIXME: remove (inline) this macro and the Float trait
 // when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
 #[unstable(feature = "core_float", issue = "32110")]
 macro_rules! f64_core_methods { () => {
     /// Returns `true` if this value is `NaN` and false otherwise.
@@ -562,7 +561,6 @@ macro_rules! f64_core_methods { () => {
 
 #[lang = "f64"]
 #[cfg(not(test))]
-#[cfg(not(stage0))]
 impl f64 {
     f64_core_methods!();
 }
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 6df8ca98ba9..58d45b107f1 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -422,7 +422,6 @@ $EndFeature, "
         /// assert_eq!(m, -22016);
         /// ```
         #[unstable(feature = "reverse_bits", issue = "48763")]
-        #[cfg(not(stage0))]
         #[inline]
         pub fn reverse_bits(self) -> Self {
             (self as $UnsignedT).reverse_bits() as Self
@@ -2194,7 +2193,6 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
         /// assert_eq!(m, 43520);
         /// ```
         #[unstable(feature = "reverse_bits", issue = "48763")]
-        #[cfg(not(stage0))]
         #[inline]
         pub fn reverse_bits(self) -> Self {
             unsafe { intrinsics::bitreverse(self as $ActualT) as Self }
diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs
index 697e6a3efde..7c6e2447bdb 100644
--- a/src/libcore/ops/range.rs
+++ b/src/libcore/ops/range.rs
@@ -318,8 +318,6 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
 /// # Examples
 ///
 /// ```
-/// #![feature(inclusive_range_methods)]
-///
 /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5));
 /// assert_eq!(3 + 4 + 5, (3..=5).sum());
 ///
@@ -335,18 +333,8 @@ pub struct RangeInclusive<Idx> {
     // but it is known that LLVM is not able to optimize loops following that RFC.
     // Consider adding an extra `bool` field to indicate emptiness of the range.
     // See #45222 for performance test cases.
-    #[cfg(not(stage0))]
     pub(crate) start: Idx,
-    #[cfg(not(stage0))]
     pub(crate) end: Idx,
-    /// The lower bound of the range (inclusive).
-    #[cfg(stage0)]
-    #[unstable(feature = "inclusive_range_fields", issue = "49022")]
-    pub start: Idx,
-    /// The upper bound of the range (inclusive).
-    #[cfg(stage0)]
-    #[unstable(feature = "inclusive_range_fields", issue = "49022")]
-    pub end: Idx,
 }
 
 impl<Idx> RangeInclusive<Idx> {
@@ -355,12 +343,11 @@ impl<Idx> RangeInclusive<Idx> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
     /// use std::ops::RangeInclusive;
     ///
     /// assert_eq!(3..=5, RangeInclusive::new(3, 5));
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub const fn new(start: Idx, end: Idx) -> Self {
         Self { start, end }
@@ -373,17 +360,18 @@ impl<Idx> RangeInclusive<Idx> {
     /// whether the inclusive range is empty, use the [`is_empty()`] method
     /// instead of comparing `start() > end()`.
     ///
+    /// Note: the value returned by this method is unspecified after the range
+    /// has been iterated to exhaustion.
+    ///
     /// [`end()`]: #method.end
     /// [`is_empty()`]: #method.is_empty
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
-    ///
     /// assert_eq!((3..=5).start(), &3);
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub fn start(&self) -> &Idx {
         &self.start
@@ -396,32 +384,34 @@ impl<Idx> RangeInclusive<Idx> {
     /// whether the inclusive range is empty, use the [`is_empty()`] method
     /// instead of comparing `start() > end()`.
     ///
+    /// Note: the value returned by this method is unspecified after the range
+    /// has been iterated to exhaustion.
+    ///
     /// [`start()`]: #method.start
     /// [`is_empty()`]: #method.is_empty
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
-    ///
     /// assert_eq!((3..=5).end(), &5);
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub fn end(&self) -> &Idx {
         &self.end
     }
 
-    /// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound).
+    /// Destructures the `RangeInclusive` into (lower bound, upper (inclusive) bound).
+    ///
+    /// Note: the value returned by this method is unspecified after the range
+    /// has been iterated to exhaustion.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
-    ///
     /// assert_eq!((3..=5).into_inner(), (3, 5));
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub fn into_inner(self) -> (Idx, Idx) {
         (self.start, self.end)
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 0dfdabee031..28f37f72d6f 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -705,6 +705,42 @@ impl<T> Option<T> {
         }
     }
 
+    /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns `None`.
+    ///
+    /// [`Some`]: #variant.Some
+    /// [`None`]: #variant.None
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_xor)]
+    ///
+    /// let x = Some(2);
+    /// let y: Option<u32> = None;
+    /// assert_eq!(x.xor(y), Some(2));
+    ///
+    /// let x: Option<u32> = None;
+    /// let y = Some(2);
+    /// assert_eq!(x.xor(y), Some(2));
+    ///
+    /// let x = Some(2);
+    /// let y = Some(2);
+    /// assert_eq!(x.xor(y), None);
+    ///
+    /// let x: Option<u32> = None;
+    /// let y: Option<u32> = None;
+    /// assert_eq!(x.xor(y), None);
+    /// ```
+    #[inline]
+    #[unstable(feature = "option_xor", issue = "50512")]
+    pub fn xor(self, optb: Option<T>) -> Option<T> {
+        match (self, optb) {
+            (Some(a), None) => Some(a),
+            (None, Some(b)) => Some(b),
+            _ => None,
+        }
+    }
+
     /////////////////////////////////////////////////////////////////////////
     // Entry-like operations to insert if None and return a reference
     /////////////////////////////////////////////////////////////////////////
diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs
index 8212648f2d8..45f629a6442 100644
--- a/src/libcore/prelude/v1.rs
+++ b/src/libcore/prelude/v1.rs
@@ -54,13 +54,3 @@ pub use option::Option::{self, Some, None};
 #[stable(feature = "core_prelude", since = "1.4.0")]
 #[doc(no_inline)]
 pub use result::Result::{self, Ok, Err};
-
-// Re-exported extension traits for primitive types
-#[stable(feature = "core_prelude", since = "1.4.0")]
-#[doc(no_inline)]
-#[cfg(stage0)]
-pub use slice::SliceExt;
-#[stable(feature = "core_prelude", since = "1.4.0")]
-#[doc(no_inline)]
-#[cfg(stage0)]
-pub use str::StrExt;
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 63bcc024020..6c0709caa08 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -10,7 +10,7 @@
 
 // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory
 
-//! Manually manage memory through raw pointers.
+//! Raw, unsafe pointers, `*const T`, and `*mut T`.
 //!
 //! *[See also the pointer primitive types](../../std/primitive.pointer.html).*
 
@@ -38,62 +38,21 @@ pub use intrinsics::write_bytes;
 
 /// Executes the destructor (if any) of the pointed-to value.
 ///
-/// This is semantically equivalent to calling [`ptr::read`] and discarding
-/// the result, but has the following advantages:
+/// This has two use cases:
 ///
 /// * It is *required* to use `drop_in_place` to drop unsized types like
 ///   trait objects, because they can't be read out onto the stack and
 ///   dropped normally.
 ///
-/// * It is friendlier to the optimizer to do this over [`ptr::read`] when
+/// * It is friendlier to the optimizer to do this over `ptr::read` when
 ///   dropping manually allocated memory (e.g. when writing Box/Rc/Vec),
 ///   as the compiler doesn't need to prove that it's sound to elide the
 ///   copy.
 ///
-/// [`ptr::read`]: ../ptr/fn.read.html
-///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `to_drop` must point to valid memory.
-///
-/// * `to_drop` must be properly aligned.
-///
-/// Additionally, if `T` is not [`Copy`], using the pointed-to value after
-/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop =
-/// foo` counts as a use because it will cause the the value to be dropped
-/// again. [`write`] can be used to overwrite data without causing it to be
-/// dropped.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`write`]: ../ptr/fn.write.html
-///
-/// # Examples
-///
-/// Manually remove the last item from a vector:
-///
-/// ```
-/// use std::ptr;
-/// use std::rc::Rc;
-///
-/// let last = Rc::new(1);
-/// let weak = Rc::downgrade(&last);
-///
-/// let mut v = vec![Rc::new(0), last];
-///
-/// unsafe {
-///     // Without a call `drop_in_place`, the last item would never be dropped,
-///     // and the memory it manages would be leaked.
-///     ptr::drop_in_place(&mut v[1]);
-///     v.set_len(1);
-/// }
-///
-/// assert_eq!(v, &[0.into()]);
-///
-/// // Ensure that the last item was dropped.
-/// assert!(weak.upgrade().is_none());
-/// ```
+/// This has all the same safety problems as `ptr::read` with respect to
+/// invalid pointers, types, and double drops.
 #[stable(feature = "drop_in_place", since = "1.8.0")]
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
@@ -134,25 +93,17 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
 /// Swaps the values at two mutable locations of the same type, without
 /// deinitializing either.
 ///
-/// But for the following two exceptions, this function is semantically
-/// equivalent to [`mem::swap`]:
-///
-/// * It operates on raw pointers instead of references. When references are
-///   available, [`mem::swap`] should be preferred.
-///
-/// * The two pointed-to values may overlap. If the values do overlap, then the
-///   overlapping region of memory from `x` will be used. This is demonstrated
-///   in the examples below.
-///
-/// [`mem::swap`]: ../mem/fn.swap.html
+/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which
+/// is otherwise equivalent. If the values do overlap, then the overlapping
+/// region of memory from `x` will be used. This is demonstrated in the
+/// examples section below.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
+/// This function copies the memory through the raw pointers passed to it
+/// as arguments.
 ///
-/// * `x` and `y` must point to valid, initialized memory.
-///
-/// * `x` and `y` must be properly aligned.
+/// Ensure that these pointers are valid before calling `swap`.
 ///
 /// # Examples
 ///
@@ -288,39 +239,13 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
     }
 }
 
-/// Replaces the value at `dest` with `src`, returning the old value, without
-/// dropping either.
-///
-/// This function is semantically equivalent to [`mem::replace`] except that it
-/// operates on raw pointers instead of references. When references are
-/// available, [`mem::replace`] should be preferred.
-///
-/// [`mem::replace`]: ../mem/fn.replace.html
+/// Replaces the value at `dest` with `src`, returning the old
+/// value, without dropping either.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dest` must point to valid, initialized memory.
-///
-/// * `dest` must be properly aligned.
-///
-/// # Examples
-///
-/// ```
-/// use std::ptr;
-///
-/// let mut rust = vec!['b', 'u', 's', 't'];
-///
-/// // `mem::replace` would have the same effect without requiring the unsafe
-/// // block.
-/// let b = unsafe {
-///     ptr::replace(&mut rust[0], 'r')
-/// };
-///
-/// assert_eq!(b, 'b');
-/// assert_eq!(rust, &['r', 'u', 's', 't']);
-/// ```
+/// This is only unsafe because it accepts a raw pointer.
+/// Otherwise, this operation is identical to `mem::replace`.
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
@@ -333,23 +258,14 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must point to valid, initialized memory.
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
 ///
-/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the
-///   case.
-///
-/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
-/// pointed-to value can be used or dropped after calling `read`. `read` creates
-/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result
-/// in undefined behavior if both copies are used. Note that `*src = foo` counts
-/// as a use because it will attempt to drop the value previously at `*src`.
-/// [`write`] can be used to overwrite data without causing it to be dropped.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`read_unaligned`]: ./fn.read_unaligned.html
-/// [`write`]: ./fn.write.html
+/// The pointer must be aligned; use `read_unaligned` if that is not the case.
 ///
 /// # Examples
 ///
@@ -363,44 +279,6 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
-///
-/// Manually implement [`mem::swap`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// fn swap<T>(a: &mut T, b: &mut T) {
-///     unsafe {
-///         // Create a bitwise copy of the value at `a` in `tmp`.
-///         let tmp = ptr::read(a);
-///
-///         // Exiting at this point (either by explicitly returning or by
-///         // calling a function which panics) would cause the value in `tmp` to
-///         // be dropped while the same value is still referenced by `a`. This
-///         // could trigger undefined behavior if `T` is not `Copy`.
-///
-///         // Create a bitwise copy of the value at `b` in `a`.
-///         // This is safe because mutable references cannot alias.
-///         ptr::copy_nonoverlapping(b, a, 1);
-///
-///         // As above, exiting here could trigger undefined behavior because
-///         // the same value is referenced by `a` and `b`.
-///
-///         // Move `tmp` into `b`.
-///         ptr::write(b, tmp);
-///     }
-/// }
-///
-/// let mut foo = "foo".to_owned();
-/// let mut bar = "bar".to_owned();
-///
-/// swap(&mut foo, &mut bar);
-///
-/// assert_eq!(foo, "bar");
-/// assert_eq!(bar, "foo");
-/// ```
-///
-/// [`mem::swap`]: ../mem/fn.swap.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn read<T>(src: *const T) -> T {
@@ -412,62 +290,28 @@ pub unsafe fn read<T>(src: *const T) -> T {
 /// Reads the value from `src` without moving it. This leaves the
 /// memory in `src` unchanged.
 ///
-/// Unlike [`read`], `read_unaligned` works with unaligned pointers.
-///
-/// [`read`]: ./fn.read.html
+/// Unlike `read`, the pointer may be unaligned.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must point to valid, initialized memory.
-///
-/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
-/// pointed-to value can be used or dropped after calling `read_unaligned`.
-/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T:
-/// Copy`, and this can result in undefined behavior if both copies are used.
-/// Note that `*src = foo` counts as a use because it will attempt to drop the
-/// value previously at `*src`.  [`write_unaligned`] can be used to overwrite
-/// data without causing it to be dropped.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`write_unaligned`]: ./fn.write_unaligned.html
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
 ///
 /// # Examples
 ///
-/// Access members of a packed struct by reference:
+/// Basic usage:
 ///
 /// ```
-/// use std::ptr;
+/// let x = 12;
+/// let y = &x as *const i32;
 ///
-/// #[repr(packed, C)]
-/// #[derive(Default)]
-/// struct Packed {
-///     _padding: u8,
-///     unaligned: u32,
+/// unsafe {
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
 /// }
-///
-/// let x = Packed {
-///     _padding: 0x00,
-///     unaligned: 0x01020304,
-/// };
-///
-/// let v = unsafe {
-///     // Take a reference to a 32-bit integer which is not aligned.
-///     let unaligned = &x.unaligned;
-///
-///     // Dereferencing normally will emit an unaligned load instruction,
-///     // causing undefined behavior.
-///     // let v = *unaligned; // ERROR
-///
-///     // Instead, use `read_unaligned` to read improperly aligned values.
-///     let v = ptr::read_unaligned(unaligned);
-///
-///     v
-/// };
-///
-/// // Accessing unaligned values directly is safe.
-/// assert!(x.unaligned == v);
 /// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
@@ -482,7 +326,11 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
-/// `write` does not drop the contents of `dst`. This is safe, but it could leak
+/// # Safety
+///
+/// This operation is marked unsafe because it accepts a raw pointer.
+///
+/// It does not drop the contents of `dst`. This is safe, but it could leak
 /// allocations or resources, so care must be taken not to overwrite an object
 /// that should be dropped.
 ///
@@ -490,20 +338,9 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// location pointed to by `dst`.
 ///
 /// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been [`read`] from.
+/// memory that has previously been `read` from.
 ///
-/// [`read`]: ./fn.read.html
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dst` must point to valid memory.
-///
-/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
-///   case.
-///
-/// [`write_unaligned`]: ./fn.write_unaligned.html
+/// The pointer must be aligned; use `write_unaligned` if that is not the case.
 ///
 /// # Examples
 ///
@@ -519,30 +356,6 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
-///
-/// Manually implement [`mem::swap`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// fn swap<T>(a: &mut T, b: &mut T) {
-///     unsafe {
-///         let tmp = ptr::read(a);
-///         ptr::copy_nonoverlapping(b, a, 1);
-///         ptr::write(b, tmp);
-///     }
-/// }
-///
-/// let mut foo = "foo".to_owned();
-/// let mut bar = "bar".to_owned();
-///
-/// swap(&mut foo, &mut bar);
-///
-/// assert_eq!(foo, "bar");
-/// assert_eq!(bar, "foo");
-/// ```
-///
-/// [`mem::swap`]: ../mem/fn.swap.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn write<T>(dst: *mut T, src: T) {
@@ -552,58 +365,36 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
-/// Unlike [`write`], the pointer may be unaligned.
+/// Unlike `write`, the pointer may be unaligned.
+///
+/// # Safety
+///
+/// This operation is marked unsafe because it accepts a raw pointer.
 ///
-/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it
-/// could leak allocations or resources, so care must be taken not to overwrite
-/// an object that should be dropped.
+/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care must be taken not to overwrite an object
+/// that should be dropped.
 ///
 /// Additionally, it does not drop `src`. Semantically, `src` is moved into the
 /// location pointed to by `dst`.
 ///
 /// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been read with [`read_unaligned`].
-///
-/// [`write`]: ./fn.write.html
-/// [`read_unaligned`]: ./fn.read_unaligned.html
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dst` must point to valid memory.
+/// memory that has previously been `read` from.
 ///
 /// # Examples
 ///
-/// Access fields in a packed struct:
+/// Basic usage:
 ///
 /// ```
-/// use std::{mem, ptr};
-///
-/// #[repr(packed, C)]
-/// #[derive(Default)]
-/// struct Packed {
-///     _padding: u8,
-///     unaligned: u32,
-/// }
-///
-/// let v = 0x01020304;
-/// let mut x: Packed = unsafe { mem::zeroed() };
+/// let mut x = 0;
+/// let y = &mut x as *mut i32;
+/// let z = 12;
 ///
 /// unsafe {
-///     // Take a reference to a 32-bit integer which is not aligned.
-///     let unaligned = &mut x.unaligned;
-///
-///     // Dereferencing normally will emit an unaligned store instruction,
-///     // causing undefined behavior.
-///     // *unaligned = v; // ERROR
-///
-///     // Instead, use `write_unaligned` to write improperly aligned values.
-///     ptr::write_unaligned(unaligned, v);
+///     std::ptr::write_unaligned(y, z);
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
 /// }
-///
-/// // Accessing unaligned values directly is safe.
-/// assert!(x.unaligned == v);
+/// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
@@ -620,11 +411,6 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
-/// Memory read with `read_volatile` should almost always be written to using
-/// [`write_volatile`].
-///
-/// [`write_volatile`]: ./fn.write_volatile.html
-///
 /// # Notes
 ///
 /// Rust does not currently have a rigorously and formally defined memory model,
@@ -641,19 +427,12 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must point to valid, initialized memory.
-///
-/// * `src` must be properly aligned.
-///
-/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to
-/// object, regardless of whether `T` is [`Copy`]. Using both values can cause
-/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is
-/// almost certainly incorrect.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`read`]: ./fn.read.html
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
 ///
 /// # Examples
 ///
@@ -680,18 +459,6 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
-/// Memory written with `write_volatile` should almost always be read from using
-/// [`read_volatile`].
-///
-/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
-/// could leak allocations or resources, so care must be taken not to overwrite
-/// an object that should be dropped.
-///
-/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
-/// location pointed to by `dst`.
-///
-/// [`read_volatile`]: ./fn.read_volatile.html
-///
 /// # Notes
 ///
 /// Rust does not currently have a rigorously and formally defined memory model,
@@ -708,11 +475,14 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
+/// This operation is marked unsafe because it accepts a raw pointer.
 ///
-/// * `dst` must point to valid memory.
+/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care must be taken not to overwrite an object
+/// that should be dropped.
 ///
-/// * `dst` must be properly aligned.
+/// This is appropriate for initializing uninitialized memory, or overwriting
+/// memory that has previously been `read` from.
 ///
 /// # Examples
 ///
@@ -1433,15 +1203,22 @@ impl<T: ?Sized> *const T {
         copy_nonoverlapping(self, dest, count)
     }
 
-    /// Computes the byte offset that needs to be applied in order to
-    /// make the pointer aligned to `align`.
+    /// Computes the offset that needs to be applied to the pointer in order to make it aligned to
+    /// `align`.
+    ///
     /// If it is not possible to align the pointer, the implementation returns
     /// `usize::max_value()`.
     ///
-    /// There are no guarantees whatsover that offsetting the pointer will not
-    /// overflow or go beyond the allocation that the pointer points into.
-    /// It is up to the caller to ensure that the returned offset is correct
-    /// in all terms other than alignment.
+    /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
+    /// used with the `offset` or `offset_to` methods.
+    ///
+    /// There are no guarantees whatsover that offsetting the pointer will not overflow or go
+    /// beyond the allocation that the pointer points into. It is up to the caller to ensure that
+    /// the returned offset is correct in all terms other than alignment.
+    ///
+    /// # Panics
+    ///
+    /// The function panics if `align` is not a power-of-two.
     ///
     /// # Examples
     ///
@@ -1465,13 +1242,30 @@ impl<T: ?Sized> *const T {
     /// # } }
     /// ```
     #[unstable(feature = "align_offset", issue = "44488")]
-    pub fn align_offset(self, align: usize) -> usize {
+    #[cfg(not(stage0))]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
         unsafe {
-            intrinsics::align_offset(self as *const _, align)
+            align_offset(self, align)
+        }
+    }
+
+    /// definitely docs.
+    #[unstable(feature = "align_offset", issue = "44488")]
+    #[cfg(stage0)]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
+        unsafe {
+            intrinsics::align_offset(self as *const (), align)
         }
     }
 }
 
+
 #[lang = "mut_ptr"]
 impl<T: ?Sized> *mut T {
     /// Returns `true` if the pointer is null.
@@ -1804,44 +1598,6 @@ impl<T: ?Sized> *mut T {
         (self as *const T).wrapping_offset_from(origin)
     }
 
-    /// Computes the byte offset that needs to be applied in order to
-    /// make the pointer aligned to `align`.
-    /// If it is not possible to align the pointer, the implementation returns
-    /// `usize::max_value()`.
-    ///
-    /// There are no guarantees whatsover that offsetting the pointer will not
-    /// overflow or go beyond the allocation that the pointer points into.
-    /// It is up to the caller to ensure that the returned offset is correct
-    /// in all terms other than alignment.
-    ///
-    /// # Examples
-    ///
-    /// Accessing adjacent `u8` as `u16`
-    ///
-    /// ```
-    /// # #![feature(align_offset)]
-    /// # fn foo(n: usize) {
-    /// # use std::mem::align_of;
-    /// # unsafe {
-    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
-    /// let ptr = &x[n] as *const u8;
-    /// let offset = ptr.align_offset(align_of::<u16>());
-    /// if offset < x.len() - n - 1 {
-    ///     let u16_ptr = ptr.offset(offset as isize) as *const u16;
-    ///     assert_ne!(*u16_ptr, 500);
-    /// } else {
-    ///     // while the pointer can be aligned via `offset`, it would point
-    ///     // outside the allocation
-    /// }
-    /// # } }
-    /// ```
-    #[unstable(feature = "align_offset", issue = "44488")]
-    pub fn align_offset(self, align: usize) -> usize {
-        unsafe {
-            intrinsics::align_offset(self as *const _, align)
-        }
-    }
-
     /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
     ///
     /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
@@ -2511,8 +2267,200 @@ impl<T: ?Sized> *mut T {
     {
         swap(self, with)
     }
+
+    /// Computes the offset that needs to be applied to the pointer in order to make it aligned to
+    /// `align`.
+    ///
+    /// If it is not possible to align the pointer, the implementation returns
+    /// `usize::max_value()`.
+    ///
+    /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
+    /// used with the `offset` or `offset_to` methods.
+    ///
+    /// There are no guarantees whatsover that offsetting the pointer will not overflow or go
+    /// beyond the allocation that the pointer points into. It is up to the caller to ensure that
+    /// the returned offset is correct in all terms other than alignment.
+    ///
+    /// # Panics
+    ///
+    /// The function panics if `align` is not a power-of-two.
+    ///
+    /// # Examples
+    ///
+    /// Accessing adjacent `u8` as `u16`
+    ///
+    /// ```
+    /// # #![feature(align_offset)]
+    /// # fn foo(n: usize) {
+    /// # use std::mem::align_of;
+    /// # unsafe {
+    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
+    /// let ptr = &x[n] as *const u8;
+    /// let offset = ptr.align_offset(align_of::<u16>());
+    /// if offset < x.len() - n - 1 {
+    ///     let u16_ptr = ptr.offset(offset as isize) as *const u16;
+    ///     assert_ne!(*u16_ptr, 500);
+    /// } else {
+    ///     // while the pointer can be aligned via `offset`, it would point
+    ///     // outside the allocation
+    /// }
+    /// # } }
+    /// ```
+    #[unstable(feature = "align_offset", issue = "44488")]
+    #[cfg(not(stage0))]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
+        unsafe {
+            align_offset(self, align)
+        }
+    }
+
+    /// definitely docs.
+    #[unstable(feature = "align_offset", issue = "44488")]
+    #[cfg(stage0)]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
+        unsafe {
+            intrinsics::align_offset(self as *const (), align)
+        }
+    }
+}
+
+/// Align pointer `p`.
+///
+/// Calculate offset (in terms of elements of `stride` stride) that has to be applied
+/// to pointer `p` so that pointer `p` would get aligned to `a`.
+///
+/// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic.
+/// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated
+/// constants.
+///
+/// If we ever decide to make it possible to call the intrinsic with `a` that is not a
+/// power-of-two, it will probably be more prudent to just change to a naive implementation rather
+/// than trying to adapt this to accomodate that change.
+///
+/// Any questions go to @nagisa.
+#[lang="align_offset"]
+#[cfg(not(stage0))]
+pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
+    /// Calculate multiplicative modular inverse of `x` modulo `m`.
+    ///
+    /// This implementation is tailored for align_offset and has following preconditions:
+    ///
+    /// * `m` is a power-of-two;
+    /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead)
+    ///
+    /// Implementation of this function shall not panic. Ever.
+    #[inline]
+    fn mod_inv(x: usize, m: usize) -> usize {
+        /// Multiplicative modular inverse table modulo 2⁴ = 16.
+        ///
+        /// Note, that this table does not contain values where inverse does not exist (i.e. for
+        /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.)
+        const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
+        /// Modulo for which the `INV_TABLE_MOD_16` is intended.
+        const INV_TABLE_MOD: usize = 16;
+        /// INV_TABLE_MOD²
+        const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD;
+
+        let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1];
+        if m <= INV_TABLE_MOD {
+            return table_inverse & (m - 1);
+        } else {
+            // We iterate "up" using the following formula:
+            //
+            // $$ xy ≡ 1 (mod 2ⁿ) → xy (2 - xy) ≡ 1 (mod 2²ⁿ) $$
+            //
+            // until 2²ⁿ ≥ m. Then we can reduce to our desired `m` by taking the result `mod m`.
+            let mut inverse = table_inverse;
+            let mut going_mod = INV_TABLE_MOD_SQUARED;
+            loop {
+                // y = y * (2 - xy) mod n
+                //
+                // Note, that we use wrapping operations here intentionally – the original formula
+                // uses e.g. subtraction `mod n`. It is entirely fine to do them `mod
+                // usize::max_value()` instead, because we take the result `mod n` at the end
+                // anyway.
+                inverse = inverse.wrapping_mul(
+                    2usize.wrapping_sub(x.wrapping_mul(inverse))
+                ) & (going_mod - 1);
+                if going_mod > m {
+                    return inverse & (m - 1);
+                }
+                going_mod = going_mod.wrapping_mul(going_mod);
+            }
+        }
+    }
+
+    let stride = ::mem::size_of::<T>();
+    let a_minus_one = a.wrapping_sub(1);
+    let pmoda = p as usize & a_minus_one;
+
+    if pmoda == 0 {
+        // Already aligned. Yay!
+        return 0;
+    }
+
+    if stride <= 1 {
+        return if stride == 0 {
+            // If the pointer is not aligned, and the element is zero-sized, then no amount of
+            // elements will ever align the pointer.
+            !0
+        } else {
+            a.wrapping_sub(pmoda)
+        };
+    }
+
+    let smoda = stride & a_minus_one;
+    // a is power-of-two so cannot be 0. stride = 0 is handled above.
+    let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a));
+    let gcd = 1usize << gcdpow;
+
+    if gcd == 1 {
+        // This branch solves for the variable $o$ in following linear congruence equation:
+        //
+        // ⎰ p + o ≡ 0 (mod a)   # $p + o$ must be aligned to specified alignment $a$
+        // ⎱     o ≡ 0 (mod s)   # offset $o$ must be a multiple of stride $s$
+        //
+        // where
+        //
+        // * a, s are co-prime
+        //
+        // This gives us the formula below:
+        //
+        // o = (a - (p mod a)) * (s⁻¹ mod a) * s
+        //
+        // The first term is “the relative alignment of p to a”, the second term is “how does
+        // incrementing p by one s change the relative alignment of p”, the third term is
+        // translating change in units of s to a byte count.
+        //
+        // Furthermore, the result produced by this solution is not “minimal”, so it is necessary
+        // to take the result $o mod lcm(s, a)$. Since $s$ and $a$ are co-prime (i.e. $gcd(s, a) =
+        // 1$) and $lcm(s, a) = s * a / gcd(s, a)$, we can replace $lcm(s, a)$ with just a $s * a$.
+        //
+        // (Author note: we decided later on to express the offset in "elements" rather than bytes,
+        // which drops the multiplication by `s` on both sides of the modulo.)
+        return intrinsics::unchecked_rem(a.wrapping_sub(pmoda).wrapping_mul(mod_inv(smoda, a)), a);
+    }
+
+    if p as usize & (gcd - 1) == 0 {
+        // This can be aligned, but `a` and `stride` are not co-prime, so a somewhat adapted
+        // formula is used.
+        let j = a.wrapping_sub(pmoda) >> gcdpow;
+        let k = smoda >> gcdpow;
+        return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow);
+    }
+
+    // Cannot be aligned at all.
+    return usize::max_value();
 }
 
+
+
 // Equality for pointers
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *const T {
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 93ebc23ac0b..3b19a401859 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -68,181 +68,6 @@ struct Repr<T> {
 // Extension traits
 //
 
-public_in_stage0! {
-{
-/// Extension methods for slices.
-#[unstable(feature = "core_slice_ext",
-           reason = "stable interface provided by `impl [T]` in later crates",
-           issue = "32110")]
-#[allow(missing_docs)] // documented elsewhere
-}
-trait SliceExt {
-    type Item;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at(&self, mid: usize) -> (&[Self::Item], &[Self::Item]);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn iter(&self) -> Iter<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split<P>(&self, pred: P) -> Split<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "slice_rsplit", since = "1.27.0")]
-    fn rsplit<P>(&self, pred: P) -> RSplit<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn splitn<P>(&self, n: usize, pred: P) -> SplitN<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplitn<P>(&self,  n: usize, pred: P) -> RSplitN<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn windows(&self, size: usize) -> Windows<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn chunks(&self, size: usize) -> Chunks<Self::Item>;
-
-    #[unstable(feature = "exact_chunks", issue = "47115")]
-    fn exact_chunks(&self, size: usize) -> ExactChunks<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn get<I>(&self, index: I) -> Option<&I::Output>
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn first(&self) -> Option<&Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_first(&self) -> Option<(&Self::Item, &[Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_last(&self) -> Option<(&Self::Item, &[Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn last(&self) -> Option<&Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_ptr(&self) -> *const Self::Item;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn binary_search(&self, x: &Self::Item) -> Result<usize, usize>
-        where Self::Item: Ord;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
-        where F: FnMut(&'a Self::Item) -> Ordering;
-
-    #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
-    fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
-        where F: FnMut(&'a Self::Item) -> B,
-              B: Ord;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn len(&self) -> usize;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn is_empty(&self) -> bool { self.len() == 0 }
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn iter_mut(&mut self) -> IterMut<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn first_mut(&mut self) -> Option<&mut Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_first_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_last_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn last_mut(&mut self) -> Option<&mut Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_mut<P>(&mut self, pred: P) -> SplitMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "slice_rsplit", since = "1.27.0")]
-    fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplitn_mut<P>(&mut self,  n: usize, pred: P) -> RSplitNMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<Self::Item>;
-
-    #[unstable(feature = "exact_chunks", issue = "47115")]
-    fn exact_chunks_mut(&mut self, size: usize) -> ExactChunksMut<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn swap(&mut self, a: usize, b: usize);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at_mut(&mut self, mid: usize) -> (&mut [Self::Item], &mut [Self::Item]);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn reverse(&mut self);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_mut_ptr(&mut self) -> *mut Self::Item;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn contains(&self, x: &Self::Item) -> bool where Self::Item: PartialEq;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn starts_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
-
-    #[stable(feature = "slice_rotate", since = "1.26.0")]
-    fn rotate_left(&mut self, mid: usize);
-
-    #[stable(feature = "slice_rotate", since = "1.26.0")]
-    fn rotate_right(&mut self, k: usize);
-
-    #[stable(feature = "clone_from_slice", since = "1.7.0")]
-    fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone;
-
-    #[stable(feature = "copy_from_slice", since = "1.9.0")]
-    fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy;
-
-    #[stable(feature = "swap_with_slice", since = "1.27.0")]
-    fn swap_with_slice(&mut self, src: &mut [Self::Item]);
-
-    #[stable(feature = "sort_unstable", since = "1.20.0")]
-    fn sort_unstable(&mut self)
-        where Self::Item: Ord;
-
-    #[stable(feature = "sort_unstable", since = "1.20.0")]
-    fn sort_unstable_by<F>(&mut self, compare: F)
-        where F: FnMut(&Self::Item, &Self::Item) -> Ordering;
-
-    #[stable(feature = "sort_unstable", since = "1.20.0")]
-    fn sort_unstable_by_key<B, F>(&mut self, f: F)
-        where F: FnMut(&Self::Item) -> B,
-              B: Ord;
-}}
-
 // Use macros to be generic over const/mut
 macro_rules! slice_offset {
     ($ptr:expr, $by:expr) => {{
@@ -281,488 +106,9 @@ macro_rules! make_ref_mut {
     }};
 }
 
-#[unstable(feature = "core_slice_ext",
-           reason = "stable interface provided by `impl [T]` in later crates",
-           issue = "32110")]
-impl<T> SliceExt for [T] {
-    type Item = T;
-
-    #[inline]
-    fn split_at(&self, mid: usize) -> (&[T], &[T]) {
-        (&self[..mid], &self[mid..])
-    }
-
-    #[inline]
-    fn iter(&self) -> Iter<T> {
-        unsafe {
-            let p = if mem::size_of::<T>() == 0 {
-                1 as *const _
-            } else {
-                let p = self.as_ptr();
-                assume(!p.is_null());
-                p
-            };
-
-            Iter {
-                ptr: p,
-                end: slice_offset!(p, self.len() as isize),
-                _marker: marker::PhantomData
-            }
-        }
-    }
-
-    #[inline]
-    fn split<P>(&self, pred: P) -> Split<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        Split {
-            v: self,
-            pred,
-            finished: false
-        }
-    }
-
-    #[inline]
-    fn rsplit<P>(&self, pred: P) -> RSplit<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        RSplit { inner: self.split(pred) }
-    }
-
-    #[inline]
-    fn splitn<P>(&self, n: usize, pred: P) -> SplitN<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        SplitN {
-            inner: GenericSplitN {
-                iter: self.split(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn rsplitn<P>(&self, n: usize, pred: P) -> RSplitN<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        RSplitN {
-            inner: GenericSplitN {
-                iter: self.rsplit(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn windows(&self, size: usize) -> Windows<T> {
-        assert!(size != 0);
-        Windows { v: self, size: size }
-    }
-
-    #[inline]
-    fn chunks(&self, chunk_size: usize) -> Chunks<T> {
-        assert!(chunk_size != 0);
-        Chunks { v: self, chunk_size: chunk_size }
-    }
-
-    #[inline]
-    fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
-        assert!(chunk_size != 0);
-        let rem = self.len() % chunk_size;
-        let len = self.len() - rem;
-        ExactChunks { v: &self[..len], chunk_size: chunk_size}
-    }
-
-    #[inline]
-    fn get<I>(&self, index: I) -> Option<&I::Output>
-        where I: SliceIndex<[T]>
-    {
-        index.get(self)
-    }
-
-    #[inline]
-    fn first(&self) -> Option<&T> {
-        if self.is_empty() { None } else { Some(&self[0]) }
-    }
-
-    #[inline]
-    fn split_first(&self) -> Option<(&T, &[T])> {
-        if self.is_empty() { None } else { Some((&self[0], &self[1..])) }
-    }
-
-    #[inline]
-    fn split_last(&self) -> Option<(&T, &[T])> {
-        let len = self.len();
-        if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) }
-    }
-
-    #[inline]
-    fn last(&self) -> Option<&T> {
-        if self.is_empty() { None } else { Some(&self[self.len() - 1]) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
-        where I: SliceIndex<[T]>
-    {
-        index.get_unchecked(self)
-    }
-
-    #[inline]
-    fn as_ptr(&self) -> *const T {
-        self as *const [T] as *const T
-    }
-
-    fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
-        where F: FnMut(&'a T) -> Ordering
-    {
-        let s = self;
-        let mut size = s.len();
-        if size == 0 {
-            return Err(0);
-        }
-        let mut base = 0usize;
-        while size > 1 {
-            let half = size / 2;
-            let mid = base + half;
-            // mid is always in [0, size), that means mid is >= 0 and < size.
-            // mid >= 0: by definition
-            // mid < size: mid = size / 2 + size / 4 + size / 8 ...
-            let cmp = f(unsafe { s.get_unchecked(mid) });
-            base = if cmp == Greater { base } else { mid };
-            size -= half;
-        }
-        // base is always in [0, size) because base <= mid.
-        let cmp = f(unsafe { s.get_unchecked(base) });
-        if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) }
-    }
-
-    #[inline]
-    fn len(&self) -> usize {
-        unsafe {
-            mem::transmute::<&[T], Repr<T>>(self).len
-        }
-    }
-
-    #[inline]
-    fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
-        where I: SliceIndex<[T]>
-    {
-        index.get_mut(self)
-    }
-
-    #[inline]
-    fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
-        let len = self.len();
-        let ptr = self.as_mut_ptr();
-
-        unsafe {
-            assert!(mid <= len);
-
-            (from_raw_parts_mut(ptr, mid),
-             from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
-        }
-    }
-
-    #[inline]
-    fn iter_mut(&mut self) -> IterMut<T> {
-        unsafe {
-            let p = if mem::size_of::<T>() == 0 {
-                1 as *mut _
-            } else {
-                let p = self.as_mut_ptr();
-                assume(!p.is_null());
-                p
-            };
-
-            IterMut {
-                ptr: p,
-                end: slice_offset!(p, self.len() as isize),
-                _marker: marker::PhantomData
-            }
-        }
-    }
-
-    #[inline]
-    fn last_mut(&mut self) -> Option<&mut T> {
-        let len = self.len();
-        if len == 0 { return None; }
-        Some(&mut self[len - 1])
-    }
-
-    #[inline]
-    fn first_mut(&mut self) -> Option<&mut T> {
-        if self.is_empty() { None } else { Some(&mut self[0]) }
-    }
-
-    #[inline]
-    fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        if self.is_empty() { None } else {
-            let split = self.split_at_mut(1);
-            Some((&mut split.0[0], split.1))
-        }
-    }
-
-    #[inline]
-    fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        let len = self.len();
-        if len == 0 { None } else {
-            let split = self.split_at_mut(len - 1);
-            Some((&mut split.1[0], split.0))
-        }
-    }
-
-    #[inline]
-    fn split_mut<P>(&mut self, pred: P) -> SplitMut<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        SplitMut { v: self, pred: pred, finished: false }
-    }
-
-    #[inline]
-    fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        RSplitMut { inner: self.split_mut(pred) }
-    }
-
-    #[inline]
-    fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        SplitNMut {
-            inner: GenericSplitN {
-                iter: self.split_mut(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn rsplitn_mut<P>(&mut self, n: usize, pred: P) -> RSplitNMut<T, P> where
-        P: FnMut(&T) -> bool,
-    {
-        RSplitNMut {
-            inner: GenericSplitN {
-                iter: self.rsplit_mut(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
-        assert!(chunk_size != 0);
-        ChunksMut { v: self, chunk_size: chunk_size }
-    }
-
-    #[inline]
-    fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
-        assert!(chunk_size != 0);
-        let rem = self.len() % chunk_size;
-        let len = self.len() - rem;
-        ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size}
-    }
-
-    #[inline]
-    fn swap(&mut self, a: usize, b: usize) {
-        unsafe {
-            // Can't take two mutable loans from one vector, so instead just cast
-            // them to their raw pointers to do the swap
-            let pa: *mut T = &mut self[a];
-            let pb: *mut T = &mut self[b];
-            ptr::swap(pa, pb);
-        }
-    }
-
-    fn reverse(&mut self) {
-        let mut i: usize = 0;
-        let ln = self.len();
-
-        // For very small types, all the individual reads in the normal
-        // path perform poorly.  We can do better, given efficient unaligned
-        // load/store, by loading a larger chunk and reversing a register.
-
-        // Ideally LLVM would do this for us, as it knows better than we do
-        // whether unaligned reads are efficient (since that changes between
-        // different ARM versions, for example) and what the best chunk size
-        // would be.  Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls
-        // the loop, so we need to do this ourselves.  (Hypothesis: reverse
-        // is troublesome because the sides can be aligned differently --
-        // will be, when the length is odd -- so there's no way of emitting
-        // pre- and postludes to use fully-aligned SIMD in the middle.)
-
-        let fast_unaligned =
-            cfg!(any(target_arch = "x86", target_arch = "x86_64"));
-
-        if fast_unaligned && mem::size_of::<T>() == 1 {
-            // Use the llvm.bswap intrinsic to reverse u8s in a usize
-            let chunk = mem::size_of::<usize>();
-            while i + chunk - 1 < ln / 2 {
-                unsafe {
-                    let pa: *mut T = self.get_unchecked_mut(i);
-                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
-                    let va = ptr::read_unaligned(pa as *mut usize);
-                    let vb = ptr::read_unaligned(pb as *mut usize);
-                    ptr::write_unaligned(pa as *mut usize, vb.swap_bytes());
-                    ptr::write_unaligned(pb as *mut usize, va.swap_bytes());
-                }
-                i += chunk;
-            }
-        }
-
-        if fast_unaligned && mem::size_of::<T>() == 2 {
-            // Use rotate-by-16 to reverse u16s in a u32
-            let chunk = mem::size_of::<u32>() / 2;
-            while i + chunk - 1 < ln / 2 {
-                unsafe {
-                    let pa: *mut T = self.get_unchecked_mut(i);
-                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
-                    let va = ptr::read_unaligned(pa as *mut u32);
-                    let vb = ptr::read_unaligned(pb as *mut u32);
-                    ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16));
-                    ptr::write_unaligned(pb as *mut u32, va.rotate_left(16));
-                }
-                i += chunk;
-            }
-        }
-
-        while i < ln / 2 {
-            // Unsafe swap to avoid the bounds check in safe swap.
-            unsafe {
-                let pa: *mut T = self.get_unchecked_mut(i);
-                let pb: *mut T = self.get_unchecked_mut(ln - i - 1);
-                ptr::swap(pa, pb);
-            }
-            i += 1;
-        }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
-        where I: SliceIndex<[T]>
-    {
-        index.get_unchecked_mut(self)
-    }
-
-    #[inline]
-    fn as_mut_ptr(&mut self) -> *mut T {
-        self as *mut [T] as *mut T
-    }
-
-    #[inline]
-    fn contains(&self, x: &T) -> bool where T: PartialEq {
-        x.slice_contains(self)
-    }
-
-    #[inline]
-    fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq {
-        let n = needle.len();
-        self.len() >= n && needle == &self[..n]
-    }
-
-    #[inline]
-    fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq {
-        let (m, n) = (self.len(), needle.len());
-        m >= n && needle == &self[m-n..]
-    }
-
-    fn binary_search(&self, x: &T) -> Result<usize, usize>
-        where T: Ord
-    {
-        self.binary_search_by(|p| p.cmp(x))
-    }
-
-    fn rotate_left(&mut self, mid: usize) {
-        assert!(mid <= self.len());
-        let k = self.len() - mid;
-
-        unsafe {
-            let p = self.as_mut_ptr();
-            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
-        }
-    }
-
-    fn rotate_right(&mut self, k: usize) {
-        assert!(k <= self.len());
-        let mid = self.len() - k;
-
-        unsafe {
-            let p = self.as_mut_ptr();
-            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
-        }
-    }
-
-    #[inline]
-    fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
-        assert!(self.len() == src.len(),
-                "destination and source slices have different lengths");
-        // NOTE: We need to explicitly slice them to the same length
-        // for bounds checking to be elided, and the optimizer will
-        // generate memcpy for simple cases (for example T = u8).
-        let len = self.len();
-        let src = &src[..len];
-        for i in 0..len {
-            self[i].clone_from(&src[i]);
-        }
-    }
-
-    #[inline]
-    fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
-        assert!(self.len() == src.len(),
-                "destination and source slices have different lengths");
-        unsafe {
-            ptr::copy_nonoverlapping(
-                src.as_ptr(), self.as_mut_ptr(), self.len());
-        }
-    }
-
-    #[inline]
-    fn swap_with_slice(&mut self, src: &mut [T]) {
-        assert!(self.len() == src.len(),
-                "destination and source slices have different lengths");
-        unsafe {
-            ptr::swap_nonoverlapping(
-                self.as_mut_ptr(), src.as_mut_ptr(), self.len());
-        }
-    }
-
-    #[inline]
-    fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
-        where F: FnMut(&'a Self::Item) -> B,
-              B: Ord
-    {
-        self.binary_search_by(|k| f(k).cmp(b))
-    }
-
-    #[inline]
-    fn sort_unstable(&mut self)
-        where Self::Item: Ord
-    {
-        sort::quicksort(self, |a, b| a.lt(b));
-    }
-
-    #[inline]
-    fn sort_unstable_by<F>(&mut self, mut compare: F)
-        where F: FnMut(&Self::Item, &Self::Item) -> Ordering
-    {
-        sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less);
-    }
-
-    #[inline]
-    fn sort_unstable_by_key<B, F>(&mut self, mut f: F)
-        where F: FnMut(&Self::Item) -> B,
-              B: Ord
-    {
-        sort::quicksort(self, |a, b| f(a).lt(&f(b)));
-    }
-}
-
-// FIXME: remove (inline) this macro and the SliceExt trait
-// when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
-#[unstable(feature = "core_slice_ext", issue = "32110")]
-macro_rules! slice_core_methods { () => {
+#[lang = "slice"]
+#[cfg(not(test))]
+impl<T> [T] {
     /// Returns the number of elements in the slice.
     ///
     /// # Examples
@@ -774,7 +120,9 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn len(&self) -> usize {
-        SliceExt::len(self)
+        unsafe {
+            mem::transmute::<&[T], Repr<T>>(self).len
+        }
     }
 
     /// Returns `true` if the slice has a length of 0.
@@ -788,7 +136,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn is_empty(&self) -> bool {
-        SliceExt::is_empty(self)
+        self.len() == 0
     }
 
     /// Returns the first element of the slice, or `None` if it is empty.
@@ -805,7 +153,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn first(&self) -> Option<&T> {
-        SliceExt::first(self)
+        if self.is_empty() { None } else { Some(&self[0]) }
     }
 
     /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty.
@@ -823,7 +171,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn first_mut(&mut self) -> Option<&mut T> {
-        SliceExt::first_mut(self)
+        if self.is_empty() { None } else { Some(&mut self[0]) }
     }
 
     /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
@@ -841,7 +189,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_first(&self) -> Option<(&T, &[T])> {
-        SliceExt::split_first(self)
+        if self.is_empty() { None } else { Some((&self[0], &self[1..])) }
     }
 
     /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
@@ -861,7 +209,10 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        SliceExt::split_first_mut(self)
+        if self.is_empty() { None } else {
+            let split = self.split_at_mut(1);
+            Some((&mut split.0[0], split.1))
+        }
     }
 
     /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
@@ -879,7 +230,8 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_last(&self) -> Option<(&T, &[T])> {
-        SliceExt::split_last(self)
+        let len = self.len();
+        if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) }
     }
 
     /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
@@ -899,7 +251,12 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        SliceExt::split_last_mut(self)
+        let len = self.len();
+        if len == 0 { None } else {
+            let split = self.split_at_mut(len - 1);
+            Some((&mut split.1[0], split.0))
+        }
+
     }
 
     /// Returns the last element of the slice, or `None` if it is empty.
@@ -916,7 +273,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn last(&self) -> Option<&T> {
-        SliceExt::last(self)
+        if self.is_empty() { None } else { Some(&self[self.len() - 1]) }
     }
 
     /// Returns a mutable pointer to the last item in the slice.
@@ -934,7 +291,9 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn last_mut(&mut self) -> Option<&mut T> {
-        SliceExt::last_mut(self)
+        let len = self.len();
+        if len == 0 { return None; }
+        Some(&mut self[len - 1])
     }
 
     /// Returns a reference to an element or subslice depending on the type of
@@ -959,7 +318,7 @@ macro_rules! slice_core_methods { () => {
     pub fn get<I>(&self, index: I) -> Option<&I::Output>
         where I: SliceIndex<Self>
     {
-        SliceExt::get(self, index)
+        index.get(self)
     }
 
     /// Returns a mutable reference to an element or subslice depending on the
@@ -982,7 +341,7 @@ macro_rules! slice_core_methods { () => {
     pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
         where I: SliceIndex<Self>
     {
-        SliceExt::get_mut(self, index)
+        index.get_mut(self)
     }
 
     /// Returns a reference to an element or subslice, without doing bounds
@@ -1007,7 +366,7 @@ macro_rules! slice_core_methods { () => {
     pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
         where I: SliceIndex<Self>
     {
-        SliceExt::get_unchecked(self, index)
+        index.get_unchecked(self)
     }
 
     /// Returns a mutable reference to an element or subslice, without doing
@@ -1034,7 +393,7 @@ macro_rules! slice_core_methods { () => {
     pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
         where I: SliceIndex<Self>
     {
-        SliceExt::get_unchecked_mut(self, index)
+        index.get_unchecked_mut(self)
     }
 
     /// Returns a raw pointer to the slice's buffer.
@@ -1060,7 +419,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn as_ptr(&self) -> *const T {
-        SliceExt::as_ptr(self)
+        self as *const [T] as *const T
     }
 
     /// Returns an unsafe mutable pointer to the slice's buffer.
@@ -1087,7 +446,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn as_mut_ptr(&mut self) -> *mut T {
-        SliceExt::as_mut_ptr(self)
+        self as *mut [T] as *mut T
     }
 
     /// Swaps two elements in the slice.
@@ -1111,7 +470,13 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn swap(&mut self, a: usize, b: usize) {
-        SliceExt::swap(self, a, b)
+        unsafe {
+            // Can't take two mutable loans from one vector, so instead just cast
+            // them to their raw pointers to do the swap
+            let pa: *mut T = &mut self[a];
+            let pb: *mut T = &mut self[b];
+            ptr::swap(pa, pb);
+        }
     }
 
     /// Reverses the order of elements in the slice, in place.
@@ -1126,7 +491,66 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn reverse(&mut self) {
-        SliceExt::reverse(self)
+        let mut i: usize = 0;
+        let ln = self.len();
+
+        // For very small types, all the individual reads in the normal
+        // path perform poorly.  We can do better, given efficient unaligned
+        // load/store, by loading a larger chunk and reversing a register.
+
+        // Ideally LLVM would do this for us, as it knows better than we do
+        // whether unaligned reads are efficient (since that changes between
+        // different ARM versions, for example) and what the best chunk size
+        // would be.  Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls
+        // the loop, so we need to do this ourselves.  (Hypothesis: reverse
+        // is troublesome because the sides can be aligned differently --
+        // will be, when the length is odd -- so there's no way of emitting
+        // pre- and postludes to use fully-aligned SIMD in the middle.)
+
+        let fast_unaligned =
+            cfg!(any(target_arch = "x86", target_arch = "x86_64"));
+
+        if fast_unaligned && mem::size_of::<T>() == 1 {
+            // Use the llvm.bswap intrinsic to reverse u8s in a usize
+            let chunk = mem::size_of::<usize>();
+            while i + chunk - 1 < ln / 2 {
+                unsafe {
+                    let pa: *mut T = self.get_unchecked_mut(i);
+                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
+                    let va = ptr::read_unaligned(pa as *mut usize);
+                    let vb = ptr::read_unaligned(pb as *mut usize);
+                    ptr::write_unaligned(pa as *mut usize, vb.swap_bytes());
+                    ptr::write_unaligned(pb as *mut usize, va.swap_bytes());
+                }
+                i += chunk;
+            }
+        }
+
+        if fast_unaligned && mem::size_of::<T>() == 2 {
+            // Use rotate-by-16 to reverse u16s in a u32
+            let chunk = mem::size_of::<u32>() / 2;
+            while i + chunk - 1 < ln / 2 {
+                unsafe {
+                    let pa: *mut T = self.get_unchecked_mut(i);
+                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
+                    let va = ptr::read_unaligned(pa as *mut u32);
+                    let vb = ptr::read_unaligned(pb as *mut u32);
+                    ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16));
+                    ptr::write_unaligned(pb as *mut u32, va.rotate_left(16));
+                }
+                i += chunk;
+            }
+        }
+
+        while i < ln / 2 {
+            // Unsafe swap to avoid the bounds check in safe swap.
+            unsafe {
+                let pa: *mut T = self.get_unchecked_mut(i);
+                let pb: *mut T = self.get_unchecked_mut(ln - i - 1);
+                ptr::swap(pa, pb);
+            }
+            i += 1;
+        }
     }
 
     /// Returns an iterator over the slice.
@@ -1145,7 +569,21 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn iter(&self) -> Iter<T> {
-        SliceExt::iter(self)
+        unsafe {
+            let p = if mem::size_of::<T>() == 0 {
+                1 as *const _
+            } else {
+                let p = self.as_ptr();
+                assume(!p.is_null());
+                p
+            };
+
+            Iter {
+                ptr: p,
+                end: slice_offset!(p, self.len() as isize),
+                _marker: marker::PhantomData
+            }
+        }
     }
 
     /// Returns an iterator that allows modifying each value.
@@ -1162,7 +600,21 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn iter_mut(&mut self) -> IterMut<T> {
-        SliceExt::iter_mut(self)
+        unsafe {
+            let p = if mem::size_of::<T>() == 0 {
+                1 as *mut _
+            } else {
+                let p = self.as_mut_ptr();
+                assume(!p.is_null());
+                p
+            };
+
+            IterMut {
+                ptr: p,
+                end: slice_offset!(p, self.len() as isize),
+                _marker: marker::PhantomData
+            }
+        }
     }
 
     /// Returns an iterator over all contiguous windows of length
@@ -1194,7 +646,8 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn windows(&self, size: usize) -> Windows<T> {
-        SliceExt::windows(self, size)
+        assert!(size != 0);
+        Windows { v: self, size: size }
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a
@@ -1224,7 +677,8 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
-        SliceExt::chunks(self, chunk_size)
+        assert!(chunk_size != 0);
+        Chunks { v: self, chunk_size: chunk_size }
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a
@@ -1256,7 +710,10 @@ macro_rules! slice_core_methods { () => {
     #[unstable(feature = "exact_chunks", issue = "47115")]
     #[inline]
     pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
-        SliceExt::exact_chunks(self, chunk_size)
+        assert!(chunk_size != 0);
+        let rem = self.len() % chunk_size;
+        let len = self.len() - rem;
+        ExactChunks { v: &self[..len], chunk_size: chunk_size}
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a time.
@@ -1290,7 +747,8 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
-        SliceExt::chunks_mut(self, chunk_size)
+        assert!(chunk_size != 0);
+        ChunksMut { v: self, chunk_size: chunk_size }
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a time.
@@ -1328,7 +786,10 @@ macro_rules! slice_core_methods { () => {
     #[unstable(feature = "exact_chunks", issue = "47115")]
     #[inline]
     pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
-        SliceExt::exact_chunks_mut(self, chunk_size)
+        assert!(chunk_size != 0);
+        let rem = self.len() % chunk_size;
+        let len = self.len() - rem;
+        ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size}
     }
 
     /// Divides one slice into two at an index.
@@ -1367,7 +828,7 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
-        SliceExt::split_at(self, mid)
+        (&self[..mid], &self[mid..])
     }
 
     /// Divides one mutable slice into two at an index.
@@ -1397,7 +858,15 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
-        SliceExt::split_at_mut(self, mid)
+        let len = self.len();
+        let ptr = self.as_mut_ptr();
+
+        unsafe {
+            assert!(mid <= len);
+
+            (from_raw_parts_mut(ptr, mid),
+             from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1445,7 +914,11 @@ macro_rules! slice_core_methods { () => {
     pub fn split<F>(&self, pred: F) -> Split<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::split(self, pred)
+        Split {
+            v: self,
+            pred,
+            finished: false
+        }
     }
 
     /// Returns an iterator over mutable subslices separated by elements that
@@ -1466,7 +939,7 @@ macro_rules! slice_core_methods { () => {
     pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::split_mut(self, pred)
+        SplitMut { v: self, pred: pred, finished: false }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1501,7 +974,7 @@ macro_rules! slice_core_methods { () => {
     pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplit(self, pred)
+        RSplit { inner: self.split(pred) }
     }
 
     /// Returns an iterator over mutable subslices separated by elements that
@@ -1526,7 +999,7 @@ macro_rules! slice_core_methods { () => {
     pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplit_mut(self, pred)
+        RSplitMut { inner: self.split_mut(pred) }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1553,7 +1026,12 @@ macro_rules! slice_core_methods { () => {
     pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::splitn(self, n, pred)
+        SplitN {
+            inner: GenericSplitN {
+                iter: self.split(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1578,7 +1056,12 @@ macro_rules! slice_core_methods { () => {
     pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::splitn_mut(self, n, pred)
+        SplitNMut {
+            inner: GenericSplitN {
+                iter: self.split_mut(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1606,7 +1089,12 @@ macro_rules! slice_core_methods { () => {
     pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplitn(self, n, pred)
+        RSplitN {
+            inner: GenericSplitN {
+                iter: self.rsplit(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1632,7 +1120,12 @@ macro_rules! slice_core_methods { () => {
     pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplitn_mut(self, n, pred)
+        RSplitNMut {
+            inner: GenericSplitN {
+                iter: self.rsplit_mut(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns `true` if the slice contains an element with the given value.
@@ -1648,7 +1141,7 @@ macro_rules! slice_core_methods { () => {
     pub fn contains(&self, x: &T) -> bool
         where T: PartialEq
     {
-        SliceExt::contains(self, x)
+        x.slice_contains(self)
     }
 
     /// Returns `true` if `needle` is a prefix of the slice.
@@ -1675,7 +1168,8 @@ macro_rules! slice_core_methods { () => {
     pub fn starts_with(&self, needle: &[T]) -> bool
         where T: PartialEq
     {
-        SliceExt::starts_with(self, needle)
+        let n = needle.len();
+        self.len() >= n && needle == &self[..n]
     }
 
     /// Returns `true` if `needle` is a suffix of the slice.
@@ -1702,7 +1196,8 @@ macro_rules! slice_core_methods { () => {
     pub fn ends_with(&self, needle: &[T]) -> bool
         where T: PartialEq
     {
-        SliceExt::ends_with(self, needle)
+        let (m, n) = (self.len(), needle.len());
+        m >= n && needle == &self[m-n..]
     }
 
     /// Binary searches this sorted slice for a given element.
@@ -1731,7 +1226,7 @@ macro_rules! slice_core_methods { () => {
     pub fn binary_search(&self, x: &T) -> Result<usize, usize>
         where T: Ord
     {
-        SliceExt::binary_search(self, x)
+        self.binary_search_by(|p| p.cmp(x))
     }
 
     /// Binary searches this sorted slice with a comparator function.
@@ -1767,10 +1262,29 @@ macro_rules! slice_core_methods { () => {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
+    pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
         where F: FnMut(&'a T) -> Ordering
     {
-        SliceExt::binary_search_by(self, f)
+        let s = self;
+        let mut size = s.len();
+        if size == 0 {
+            return Err(0);
+        }
+        let mut base = 0usize;
+        while size > 1 {
+            let half = size / 2;
+            let mid = base + half;
+            // mid is always in [0, size), that means mid is >= 0 and < size.
+            // mid >= 0: by definition
+            // mid < size: mid = size / 2 + size / 4 + size / 8 ...
+            let cmp = f(unsafe { s.get_unchecked(mid) });
+            base = if cmp == Greater { base } else { mid };
+            size -= half;
+        }
+        // base is always in [0, size) because base <= mid.
+        let cmp = f(unsafe { s.get_unchecked(base) });
+        if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) }
+
     }
 
     /// Binary searches this sorted slice with a key extraction function.
@@ -1805,11 +1319,11 @@ macro_rules! slice_core_methods { () => {
     /// ```
     #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
     #[inline]
-    pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
+    pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
         where F: FnMut(&'a T) -> B,
               B: Ord
     {
-        SliceExt::binary_search_by_key(self, b, f)
+        self.binary_search_by(|k| f(k).cmp(b))
     }
 
     /// Sorts the slice, but may not preserve the order of equal elements.
@@ -1843,7 +1357,7 @@ macro_rules! slice_core_methods { () => {
     pub fn sort_unstable(&mut self)
         where T: Ord
     {
-        SliceExt::sort_unstable(self);
+        sort::quicksort(self, |a, b| a.lt(b));
     }
 
     /// Sorts the slice with a comparator function, but may not preserve the order of equal
@@ -1878,10 +1392,10 @@ macro_rules! slice_core_methods { () => {
     /// [pdqsort]: https://github.com/orlp/pdqsort
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
-    pub fn sort_unstable_by<F>(&mut self, compare: F)
+    pub fn sort_unstable_by<F>(&mut self, mut compare: F)
         where F: FnMut(&T, &T) -> Ordering
     {
-        SliceExt::sort_unstable_by(self, compare);
+        sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less);
     }
 
     /// Sorts the slice with a key extraction function, but may not preserve the order of equal
@@ -1910,10 +1424,10 @@ macro_rules! slice_core_methods { () => {
     /// [pdqsort]: https://github.com/orlp/pdqsort
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
-    pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
+    pub fn sort_unstable_by_key<K, F>(&mut self, mut f: F)
         where F: FnMut(&T) -> K, K: Ord
     {
-        SliceExt::sort_unstable_by_key(self, f);
+        sort::quicksort(self, |a, b| f(a).lt(&f(b)));
     }
 
     /// Rotates the slice in-place such that the first `mid` elements of the
@@ -1948,7 +1462,13 @@ macro_rules! slice_core_methods { () => {
    /// ```
     #[stable(feature = "slice_rotate", since = "1.26.0")]
     pub fn rotate_left(&mut self, mid: usize) {
-        SliceExt::rotate_left(self, mid);
+        assert!(mid <= self.len());
+        let k = self.len() - mid;
+
+        unsafe {
+            let p = self.as_mut_ptr();
+            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
+        }
     }
 
     /// Rotates the slice in-place such that the first `self.len() - k`
@@ -1983,7 +1503,13 @@ macro_rules! slice_core_methods { () => {
     /// ```
     #[stable(feature = "slice_rotate", since = "1.26.0")]
     pub fn rotate_right(&mut self, k: usize) {
-        SliceExt::rotate_right(self, k);
+        assert!(k <= self.len());
+        let mid = self.len() - k;
+
+        unsafe {
+            let p = self.as_mut_ptr();
+            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
+        }
     }
 
     /// Copies the elements from `src` into `self`.
@@ -2040,7 +1566,17 @@ macro_rules! slice_core_methods { () => {
     /// [`split_at_mut`]: #method.split_at_mut
     #[stable(feature = "clone_from_slice", since = "1.7.0")]
     pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
-        SliceExt::clone_from_slice(self, src)
+        assert!(self.len() == src.len(),
+                "destination and source slices have different lengths");
+        // NOTE: We need to explicitly slice them to the same length
+        // for bounds checking to be elided, and the optimizer will
+        // generate memcpy for simple cases (for example T = u8).
+        let len = self.len();
+        let src = &src[..len];
+        for i in 0..len {
+            self[i].clone_from(&src[i]);
+        }
+
     }
 
     /// Copies all elements from `src` into `self`, using a memcpy.
@@ -2096,7 +1632,12 @@ macro_rules! slice_core_methods { () => {
     /// [`split_at_mut`]: #method.split_at_mut
     #[stable(feature = "copy_from_slice", since = "1.9.0")]
     pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
-        SliceExt::copy_from_slice(self, src)
+        assert!(self.len() == src.len(),
+                "destination and source slices have different lengths");
+        unsafe {
+            ptr::copy_nonoverlapping(
+                src.as_ptr(), self.as_mut_ptr(), self.len());
+        }
     }
 
     /// Swaps all elements in `self` with those in `other`.
@@ -2148,22 +1689,186 @@ macro_rules! slice_core_methods { () => {
     /// [`split_at_mut`]: #method.split_at_mut
     #[stable(feature = "swap_with_slice", since = "1.27.0")]
     pub fn swap_with_slice(&mut self, other: &mut [T]) {
-        SliceExt::swap_with_slice(self, other)
+        assert!(self.len() == other.len(),
+                "destination and source slices have different lengths");
+        unsafe {
+            ptr::swap_nonoverlapping(
+                self.as_mut_ptr(), other.as_mut_ptr(), self.len());
+        }
     }
-}}
 
-#[lang = "slice"]
-#[cfg(not(test))]
-#[cfg(not(stage0))]
-impl<T> [T] {
-    slice_core_methods!();
+    /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`.
+    #[cfg(not(stage0))]
+    fn align_to_offsets<U>(&self) -> (usize, usize) {
+        // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a
+        // lowest number of `T`s. And how many `T`s we need for each such "multiple".
+        //
+        // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider
+        // for example a case where size_of::<T> = 16, size_of::<U> = 24. We can put 2 Us in
+        // place of every 3 Ts in the `rest` slice. A bit more complicated.
+        //
+        // Formula to calculate this is:
+        //
+        // Us = lcm(size_of::<T>, size_of::<U>) / size_of::<U>
+        // Ts = lcm(size_of::<T>, size_of::<U>) / size_of::<T>
+        //
+        // Expanded and simplified:
+        //
+        // Us = size_of::<T> / gcd(size_of::<T>, size_of::<U>)
+        // Ts = size_of::<U> / gcd(size_of::<T>, size_of::<U>)
+        //
+        // Luckily since all this is constant-evaluated... performance here matters not!
+        #[inline]
+        fn gcd(a: usize, b: usize) -> usize {
+            // iterative stein’s algorithm
+            // We should still make this `const fn` (and revert to recursive algorithm if we do)
+            // because relying on llvm to consteval all this is… well, it makes me
+            let (ctz_a, mut ctz_b) = unsafe {
+                if a == 0 { return b; }
+                if b == 0 { return a; }
+                (::intrinsics::cttz_nonzero(a), ::intrinsics::cttz_nonzero(b))
+            };
+            let k = ctz_a.min(ctz_b);
+            let mut a = a >> ctz_a;
+            let mut b = b;
+            loop {
+                // remove all factors of 2 from b
+                b >>= ctz_b;
+                if a > b {
+                    ::mem::swap(&mut a, &mut b);
+                }
+                b = b - a;
+                unsafe {
+                    if b == 0 {
+                        break;
+                    }
+                    ctz_b = ::intrinsics::cttz_nonzero(b);
+                }
+            }
+            return a << k;
+        }
+        let gcd: usize = gcd(::mem::size_of::<T>(), ::mem::size_of::<U>());
+        let ts: usize = ::mem::size_of::<U>() / gcd;
+        let us: usize = ::mem::size_of::<T>() / gcd;
+
+        // Armed with this knowledge, we can find how many `U`s we can fit!
+        let us_len = self.len() / ts * us;
+        // And how many `T`s will be in the trailing slice!
+        let ts_len = self.len() % ts;
+        return (us_len, ts_len);
+    }
+
+    /// Transmute the slice to a slice of another type, ensuring aligment of the types is
+    /// maintained.
+    ///
+    /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
+    /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
+    /// possible for a given type and input slice.
+    ///
+    /// This method has no purpose when either input element `T` or output element `U` are
+    /// zero-sized and will return the original slice without splitting anything.
+    ///
+    /// # Unsafety
+    ///
+    /// This method is essentially a `transmute` with respect to the elements in the returned
+    /// middle slice, so all the usual caveats pertaining to `transmute::<T, U>` also apply here.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(slice_align_to)]
+    /// unsafe {
+    ///     let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    ///     let (prefix, shorts, suffix) = bytes.align_to::<u16>();
+    ///     // less_efficient_algorithm_for_bytes(prefix);
+    ///     // more_efficient_algorithm_for_aligned_shorts(shorts);
+    ///     // less_efficient_algorithm_for_bytes(suffix);
+    /// }
+    /// ```
+    #[unstable(feature = "slice_align_to", issue = "44488")]
+    #[cfg(not(stage0))]
+    pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
+        // Note that most of this function will be constant-evaluated,
+        if ::mem::size_of::<U>() == 0 || ::mem::size_of::<T>() == 0 {
+            // handle ZSTs specially, which is – don't handle them at all.
+            return (self, &[], &[]);
+        }
+
+        // First, find at what point do we split between the first and 2nd slice. Easy with
+        // ptr.align_offset.
+        let ptr = self.as_ptr();
+        let offset = ::ptr::align_offset(ptr, ::mem::align_of::<U>());
+        if offset > self.len() {
+            return (self, &[], &[]);
+        } else {
+            let (left, rest) = self.split_at(offset);
+            let (us_len, ts_len) = rest.align_to_offsets::<U>();
+            return (left,
+                    from_raw_parts(rest.as_ptr() as *const U, us_len),
+                    from_raw_parts(rest.as_ptr().offset((rest.len() - ts_len) as isize), ts_len))
+        }
+    }
+
+    /// Transmute the slice to a slice of another type, ensuring aligment of the types is
+    /// maintained.
+    ///
+    /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
+    /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
+    /// possible for a given type and input slice.
+    ///
+    /// This method has no purpose when either input element `T` or output element `U` are
+    /// zero-sized and will return the original slice without splitting anything.
+    ///
+    /// # Unsafety
+    ///
+    /// This method is essentially a `transmute` with respect to the elements in the returned
+    /// middle slice, so all the usual caveats pertaining to `transmute::<T, U>` also apply here.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(slice_align_to)]
+    /// unsafe {
+    ///     let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    ///     let (prefix, shorts, suffix) = bytes.align_to_mut::<u16>();
+    ///     // less_efficient_algorithm_for_bytes(prefix);
+    ///     // more_efficient_algorithm_for_aligned_shorts(shorts);
+    ///     // less_efficient_algorithm_for_bytes(suffix);
+    /// }
+    /// ```
+    #[unstable(feature = "slice_align_to", issue = "44488")]
+    #[cfg(not(stage0))]
+    pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
+        // Note that most of this function will be constant-evaluated,
+        if ::mem::size_of::<U>() == 0 || ::mem::size_of::<T>() == 0 {
+            // handle ZSTs specially, which is – don't handle them at all.
+            return (self, &mut [], &mut []);
+        }
+
+        // First, find at what point do we split between the first and 2nd slice. Easy with
+        // ptr.align_offset.
+        let ptr = self.as_ptr();
+        let offset = ::ptr::align_offset(ptr, ::mem::align_of::<U>());
+        if offset > self.len() {
+            return (self, &mut [], &mut []);
+        } else {
+            let (left, rest) = self.split_at_mut(offset);
+            let (us_len, ts_len) = rest.align_to_offsets::<U>();
+            let mut_ptr = rest.as_mut_ptr();
+            return (left,
+                    from_raw_parts_mut(mut_ptr as *mut U, us_len),
+                    from_raw_parts_mut(mut_ptr.offset((rest.len() - ts_len) as isize), ts_len))
+        }
+    }
 }
 
-// FIXME: remove (inline) this macro
-// when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
-#[unstable(feature = "core_slice_ext", issue = "32110")]
-macro_rules! slice_u8_core_methods { () => {
+#[lang = "slice_u8"]
+#[cfg(not(test))]
+impl [u8] {
     /// Checks if all bytes in this slice are within the ASCII range.
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
@@ -2217,13 +1922,7 @@ macro_rules! slice_u8_core_methods { () => {
             byte.make_ascii_lowercase();
         }
     }
-}}
 
-#[lang = "slice_u8"]
-#[cfg(not(test))]
-#[cfg(not(stage0))]
-impl [u8] {
-    slice_u8_core_methods!();
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index df7b2f25a86..82bead0ab46 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -2097,119 +2097,7 @@ mod traits {
             (..self.end+1).index_mut(slice)
         }
     }
-
-}
-
-public_in_stage0! {
-{
-/// Methods for string slices
-#[allow(missing_docs)]
-#[doc(hidden)]
-#[unstable(feature = "core_str_ext",
-           reason = "stable interface provided by `impl str` in later crates",
-           issue = "32110")]
 }
-trait StrExt {
-    // NB there are no docs here are they're all located on the StrExt trait in
-    // liballoc, not here.
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn chars(&self) -> Chars;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn bytes(&self) -> Bytes;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn char_indices(&self) -> CharIndices;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn lines(&self) -> Lines;
-    #[stable(feature = "core", since = "1.6.0")]
-    #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")]
-    #[allow(deprecated)]
-    fn lines_any(&self) -> LinesAny;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output>;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output>;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output;
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str;
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: DoubleEndedSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "is_char_boundary", since = "1.9.0")]
-    fn is_char_boundary(&self, index: usize) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_bytes(&self) -> &[u8];
-    #[stable(feature = "str_mut_extras", since = "1.20.0")]
-    unsafe fn as_bytes_mut(&mut self) -> &mut [u8];
-    #[stable(feature = "core", since = "1.6.0")]
-    fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
-        where P::Searcher: ReverseSearcher<'a>;
-    fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at(&self, mid: usize) -> (&str, &str);
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str);
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_ptr(&self) -> *const u8;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn len(&self) -> usize;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn is_empty(&self) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
-    #[stable(feature = "split_whitespace", since = "1.1.0")]
-    fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>;
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn trim(&self) -> &str;
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn trim_left(&self) -> &str;
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn trim_right(&self) -> &str;
-}}
 
 // truncate `&str` to length at most equal to `max`
 // return `true` if it were truncated, and the new str.
@@ -2255,307 +2143,9 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
            index, ch, char_range, s_trunc, ellipsis);
 }
 
-#[stable(feature = "core", since = "1.6.0")]
-impl StrExt for str {
-    #[inline]
-    fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        pat.is_contained_in(self)
-    }
-
-    #[inline]
-    fn chars(&self) -> Chars {
-        Chars{iter: self.as_bytes().iter()}
-    }
-
-    #[inline]
-    fn bytes(&self) -> Bytes {
-        Bytes(self.as_bytes().iter().cloned())
-    }
-
-    #[inline]
-    fn char_indices(&self) -> CharIndices {
-        CharIndices { front_offset: 0, iter: self.chars() }
-    }
-
-    #[inline]
-    fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
-        Split(SplitInternal {
-            start: 0,
-            end: self.len(),
-            matcher: pat.into_searcher(self),
-            allow_trailing_empty: true,
-            finished: false,
-        })
-    }
-
-    #[inline]
-    fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RSplit(self.split(pat).0)
-    }
-
-    #[inline]
-    fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
-        SplitN(SplitNInternal {
-            iter: self.split(pat).0,
-            count,
-        })
-    }
-
-    #[inline]
-    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RSplitN(self.splitn(count, pat).0)
-    }
-
-    #[inline]
-    fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
-        SplitTerminator(SplitInternal {
-            allow_trailing_empty: false,
-            ..self.split(pat).0
-        })
-    }
-
-    #[inline]
-    fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RSplitTerminator(self.split_terminator(pat).0)
-    }
-
-    #[inline]
-    fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
-        Matches(MatchesInternal(pat.into_searcher(self)))
-    }
-
-    #[inline]
-    fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RMatches(self.matches(pat).0)
-    }
-
-    #[inline]
-    fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
-        MatchIndices(MatchIndicesInternal(pat.into_searcher(self)))
-    }
-
-    #[inline]
-    fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RMatchIndices(self.match_indices(pat).0)
-    }
-    #[inline]
-    fn lines(&self) -> Lines {
-        Lines(self.split_terminator('\n').map(LinesAnyMap))
-    }
-
-    #[inline]
-    #[allow(deprecated)]
-    fn lines_any(&self) -> LinesAny {
-        LinesAny(self.lines())
-    }
-
-    #[inline]
-    fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
-        i.get(self)
-    }
-
-    #[inline]
-    fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
-        i.get_mut(self)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-        i.get_unchecked(self)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-        i.get_unchecked_mut(self)
-    }
-
-    #[inline]
-    unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
-        (begin..end).get_unchecked(self)
-    }
-
-    #[inline]
-    unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
-        (begin..end).get_unchecked_mut(self)
-    }
-
-    #[inline]
-    fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        pat.is_prefix_of(self)
-    }
-
-    #[inline]
-    fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        pat.is_suffix_of(self)
-    }
-
-    #[inline]
-    fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: DoubleEndedSearcher<'a>
-    {
-        let mut i = 0;
-        let mut j = 0;
-        let mut matcher = pat.into_searcher(self);
-        if let Some((a, b)) = matcher.next_reject() {
-            i = a;
-            j = b; // Remember earliest known match, correct it below if
-                   // last match is different
-        }
-        if let Some((_, b)) = matcher.next_reject_back() {
-            j = b;
-        }
-        unsafe {
-            // Searcher is known to return valid indices
-            self.slice_unchecked(i, j)
-        }
-    }
-
-    #[inline]
-    fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
-        let mut i = self.len();
-        let mut matcher = pat.into_searcher(self);
-        if let Some((a, _)) = matcher.next_reject() {
-            i = a;
-        }
-        unsafe {
-            // Searcher is known to return valid indices
-            self.slice_unchecked(i, self.len())
-        }
-    }
-
-    #[inline]
-    fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        let mut j = 0;
-        let mut matcher = pat.into_searcher(self);
-        if let Some((_, b)) = matcher.next_reject_back() {
-            j = b;
-        }
-        unsafe {
-            // Searcher is known to return valid indices
-            self.slice_unchecked(0, j)
-        }
-    }
-
-    #[inline]
-    fn is_char_boundary(&self, index: usize) -> bool {
-        // 0 and len are always ok.
-        // Test for 0 explicitly so that it can optimize out the check
-        // easily and skip reading string data for that case.
-        if index == 0 || index == self.len() { return true; }
-        match self.as_bytes().get(index) {
-            None => false,
-            // This is bit magic equivalent to: b < 128 || b >= 192
-            Some(&b) => (b as i8) >= -0x40,
-        }
-    }
-
-    #[inline]
-    fn as_bytes(&self) -> &[u8] {
-        unsafe { &*(self as *const str as *const [u8]) }
-    }
-
-    #[inline]
-    unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
-        &mut *(self as *mut str as *mut [u8])
-    }
-
-    fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
-        pat.into_searcher(self).next_match().map(|(i, _)| i)
-    }
-
-    fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        pat.into_searcher(self).next_match_back().map(|(i, _)| i)
-    }
-
-    fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
-        self.find(pat)
-    }
-
-    #[inline]
-    fn split_at(&self, mid: usize) -> (&str, &str) {
-        // is_char_boundary checks that the index is in [0, .len()]
-        if self.is_char_boundary(mid) {
-            unsafe {
-                (self.slice_unchecked(0, mid),
-                 self.slice_unchecked(mid, self.len()))
-            }
-        } else {
-            slice_error_fail(self, 0, mid)
-        }
-    }
-
-    fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
-        // is_char_boundary checks that the index is in [0, .len()]
-        if self.is_char_boundary(mid) {
-            let len = self.len();
-            let ptr = self.as_ptr() as *mut u8;
-            unsafe {
-                (from_raw_parts_mut(ptr, mid),
-                 from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
-            }
-        } else {
-            slice_error_fail(self, 0, mid)
-        }
-    }
-
-    #[inline]
-    fn as_ptr(&self) -> *const u8 {
-        self as *const str as *const u8
-    }
-
-    #[inline]
-    fn len(&self) -> usize {
-        self.as_bytes().len()
-    }
-
-    #[inline]
-    fn is_empty(&self) -> bool { self.len() == 0 }
-
-    #[inline]
-    fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) }
-
-    #[inline]
-    fn split_whitespace(&self) -> SplitWhitespace {
-        SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
-    }
-
-    #[inline]
-    fn trim(&self) -> &str {
-        self.trim_matches(|c: char| c.is_whitespace())
-    }
-
-    #[inline]
-    fn trim_left(&self) -> &str {
-        self.trim_left_matches(|c: char| c.is_whitespace())
-    }
-
-    #[inline]
-    fn trim_right(&self) -> &str {
-        self.trim_right_matches(|c: char| c.is_whitespace())
-    }
-}
-
-// FIXME: remove (inline) this macro and the SliceExt trait
-// when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
-#[unstable(feature = "core_str_ext", issue = "32110")]
-macro_rules! str_core_methods { () => {
+#[lang = "str"]
+#[cfg(not(test))]
+impl str {
     /// Returns the length of `self`.
     ///
     /// This length is in bytes, not [`char`]s or graphemes. In other words,
@@ -2577,7 +2167,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn len(&self) -> usize {
-        StrExt::len(self)
+        self.as_bytes().len()
     }
 
     /// Returns `true` if `self` has a length of zero bytes.
@@ -2596,7 +2186,7 @@ macro_rules! str_core_methods { () => {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
-        StrExt::is_empty(self)
+        self.len() == 0
     }
 
     /// Checks that `index`-th byte lies at the start and/or end of a
@@ -2626,7 +2216,15 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "is_char_boundary", since = "1.9.0")]
     #[inline]
     pub fn is_char_boundary(&self, index: usize) -> bool {
-        StrExt::is_char_boundary(self, index)
+        // 0 and len are always ok.
+        // Test for 0 explicitly so that it can optimize out the check
+        // easily and skip reading string data for that case.
+        if index == 0 || index == self.len() { return true; }
+        match self.as_bytes().get(index) {
+            None => false,
+            // This is bit magic equivalent to: b < 128 || b >= 192
+            Some(&b) => (b as i8) >= -0x40,
+        }
     }
 
     /// Converts a string slice to a byte slice. To convert the byte slice back
@@ -2645,7 +2243,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline(always)]
     pub fn as_bytes(&self) -> &[u8] {
-        StrExt::as_bytes(self)
+        unsafe { &*(self as *const str as *const [u8]) }
     }
 
     /// Converts a mutable string slice to a mutable byte slice. To convert the
@@ -2684,7 +2282,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_mut_extras", since = "1.20.0")]
     #[inline(always)]
     pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
-        StrExt::as_bytes_mut(self)
+        &mut *(self as *mut str as *mut [u8])
     }
 
     /// Converts a string slice to a raw pointer.
@@ -2706,7 +2304,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn as_ptr(&self) -> *const u8 {
-        StrExt::as_ptr(self)
+        self as *const str as *const u8
     }
 
     /// Returns a subslice of `str`.
@@ -2733,7 +2331,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
-        StrExt::get(self, i)
+        i.get(self)
     }
 
     /// Returns a mutable subslice of `str`.
@@ -2767,7 +2365,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
-        StrExt::get_mut(self, i)
+        i.get_mut(self)
     }
 
     /// Returns a unchecked subslice of `str`.
@@ -2799,7 +2397,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-        StrExt::get_unchecked(self, i)
+        i.get_unchecked(self)
     }
 
     /// Returns a mutable, unchecked subslice of `str`.
@@ -2831,7 +2429,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-        StrExt::get_unchecked_mut(self, i)
+        i.get_unchecked_mut(self)
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2880,7 +2478,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
-        StrExt::slice_unchecked(self, begin, end)
+        (begin..end).get_unchecked(self)
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2910,7 +2508,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_slice_mut", since = "1.5.0")]
     #[inline]
     pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
-        StrExt::slice_mut_unchecked(self, begin, end)
+        (begin..end).get_unchecked_mut(self)
     }
 
     /// Divide one string slice into two at an index.
@@ -2946,7 +2544,15 @@ macro_rules! str_core_methods { () => {
     #[inline]
     #[stable(feature = "str_split_at", since = "1.4.0")]
     pub fn split_at(&self, mid: usize) -> (&str, &str) {
-        StrExt::split_at(self, mid)
+        // is_char_boundary checks that the index is in [0, .len()]
+        if self.is_char_boundary(mid) {
+            unsafe {
+                (self.slice_unchecked(0, mid),
+                 self.slice_unchecked(mid, self.len()))
+            }
+        } else {
+            slice_error_fail(self, 0, mid)
+        }
     }
 
     /// Divide one mutable string slice into two at an index.
@@ -2983,7 +2589,17 @@ macro_rules! str_core_methods { () => {
     #[inline]
     #[stable(feature = "str_split_at", since = "1.4.0")]
     pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
-        StrExt::split_at_mut(self, mid)
+        // is_char_boundary checks that the index is in [0, .len()]
+        if self.is_char_boundary(mid) {
+            let len = self.len();
+            let ptr = self.as_ptr() as *mut u8;
+            unsafe {
+                (from_raw_parts_mut(ptr, mid),
+                 from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
+            }
+        } else {
+            slice_error_fail(self, 0, mid)
+        }
     }
 
     /// Returns an iterator over the [`char`]s of a string slice.
@@ -3035,8 +2651,9 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn chars(&self) -> Chars {
-        StrExt::chars(self)
+        Chars{iter: self.as_bytes().iter()}
     }
+
     /// Returns an iterator over the [`char`]s of a string slice, and their
     /// positions.
     ///
@@ -3091,7 +2708,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn char_indices(&self) -> CharIndices {
-        StrExt::char_indices(self)
+        CharIndices { front_offset: 0, iter: self.chars() }
     }
 
     /// An iterator over the bytes of a string slice.
@@ -3116,7 +2733,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn bytes(&self) -> Bytes {
-        StrExt::bytes(self)
+        Bytes(self.as_bytes().iter().cloned())
     }
 
     /// Split a string slice by whitespace.
@@ -3156,7 +2773,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "split_whitespace", since = "1.1.0")]
     #[inline]
     pub fn split_whitespace(&self) -> SplitWhitespace {
-        StrExt::split_whitespace(self)
+        SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
     }
 
     /// An iterator over the lines of a string, as string slices.
@@ -3198,7 +2815,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn lines(&self) -> Lines {
-        StrExt::lines(self)
+        Lines(self.split_terminator('\n').map(LinesAnyMap))
     }
 
     /// An iterator over the lines of a string.
@@ -3207,7 +2824,7 @@ macro_rules! str_core_methods { () => {
     #[inline]
     #[allow(deprecated)]
     pub fn lines_any(&self) -> LinesAny {
-        StrExt::lines_any(self)
+        LinesAny(self.lines())
     }
 
     /// Returns an iterator of `u16` over the string encoded as UTF-16.
@@ -3226,7 +2843,7 @@ macro_rules! str_core_methods { () => {
     /// ```
     #[stable(feature = "encode_utf16", since = "1.8.0")]
     pub fn encode_utf16(&self) -> EncodeUtf16 {
-        EncodeUtf16::new(self)
+        EncodeUtf16 { chars: self.chars(), extra: 0 }
     }
 
     /// Returns `true` if the given pattern matches a sub-slice of
@@ -3247,7 +2864,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        StrExt::contains(self, pat)
+        pat.is_contained_in(self)
     }
 
     /// Returns `true` if the given pattern matches a prefix of this
@@ -3267,7 +2884,7 @@ macro_rules! str_core_methods { () => {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        StrExt::starts_with(self, pat)
+        pat.is_prefix_of(self)
     }
 
     /// Returns `true` if the given pattern matches a suffix of this
@@ -3289,7 +2906,7 @@ macro_rules! str_core_methods { () => {
     pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::ends_with(self, pat)
+        pat.is_suffix_of(self)
     }
 
     /// Returns the byte index of the first character of this string slice that
@@ -3337,7 +2954,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
-        StrExt::find(self, pat)
+        pat.into_searcher(self).next_match().map(|(i, _)| i)
     }
 
     /// Returns the byte index of the last character of this string slice that
@@ -3384,7 +3001,7 @@ macro_rules! str_core_methods { () => {
     pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rfind(self, pat)
+        pat.into_searcher(self).next_match_back().map(|(i, _)| i)
     }
 
     /// An iterator over substrings of this string slice, separated by
@@ -3496,7 +3113,13 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
-        StrExt::split(self, pat)
+        Split(SplitInternal {
+            start: 0,
+            end: self.len(),
+            matcher: pat.into_searcher(self),
+            allow_trailing_empty: true,
+            finished: false,
+        })
     }
 
     /// An iterator over substrings of the given string slice, separated by
@@ -3548,7 +3171,7 @@ macro_rules! str_core_methods { () => {
     pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rsplit(self, pat)
+        RSplit(self.split(pat).0)
     }
 
     /// An iterator over substrings of the given string slice, separated by
@@ -3593,7 +3216,10 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
-        StrExt::split_terminator(self, pat)
+        SplitTerminator(SplitInternal {
+            allow_trailing_empty: false,
+            ..self.split(pat).0
+        })
     }
 
     /// An iterator over substrings of `self`, separated by characters
@@ -3639,7 +3265,7 @@ macro_rules! str_core_methods { () => {
     pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rsplit_terminator(self, pat)
+        RSplitTerminator(self.split_terminator(pat).0)
     }
 
     /// An iterator over substrings of the given string slice, separated by a
@@ -3690,7 +3316,10 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
-        StrExt::splitn(self, n, pat)
+        SplitN(SplitNInternal {
+            iter: self.split(pat).0,
+            count: n,
+        })
     }
 
     /// An iterator over substrings of this string slice, separated by a
@@ -3740,7 +3369,7 @@ macro_rules! str_core_methods { () => {
     pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rsplitn(self, n, pat)
+        RSplitN(self.splitn(n, pat).0)
     }
 
     /// An iterator over the disjoint matches of a pattern within the given string
@@ -3779,7 +3408,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_matches", since = "1.2.0")]
     #[inline]
     pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
-        StrExt::matches(self, pat)
+        Matches(MatchesInternal(pat.into_searcher(self)))
     }
 
     /// An iterator over the disjoint matches of a pattern within this string slice,
@@ -3818,7 +3447,7 @@ macro_rules! str_core_methods { () => {
     pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rmatches(self, pat)
+        RMatches(self.matches(pat).0)
     }
 
     /// An iterator over the disjoint matches of a pattern within this string
@@ -3862,7 +3491,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "str_match_indices", since = "1.5.0")]
     #[inline]
     pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
-        StrExt::match_indices(self, pat)
+        MatchIndices(MatchIndicesInternal(pat.into_searcher(self)))
     }
 
     /// An iterator over the disjoint matches of a pattern within `self`,
@@ -3907,7 +3536,7 @@ macro_rules! str_core_methods { () => {
     pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rmatch_indices(self, pat)
+        RMatchIndices(self.match_indices(pat).0)
     }
 
     /// Returns a string slice with leading and trailing whitespace removed.
@@ -3926,7 +3555,7 @@ macro_rules! str_core_methods { () => {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim(&self) -> &str {
-        StrExt::trim(self)
+        self.trim_matches(|c: char| c.is_whitespace())
     }
 
     /// Returns a string slice with leading whitespace removed.
@@ -3962,7 +3591,7 @@ macro_rules! str_core_methods { () => {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim_left(&self) -> &str {
-        StrExt::trim_left(self)
+        self.trim_left_matches(|c: char| c.is_whitespace())
     }
 
     /// Returns a string slice with trailing whitespace removed.
@@ -3998,7 +3627,7 @@ macro_rules! str_core_methods { () => {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim_right(&self) -> &str {
-        StrExt::trim_right(self)
+        self.trim_right_matches(|c: char| c.is_whitespace())
     }
 
     /// Returns a string slice with all prefixes and suffixes that match a
@@ -4030,7 +3659,21 @@ macro_rules! str_core_methods { () => {
     pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         where P::Searcher: DoubleEndedSearcher<'a>
     {
-        StrExt::trim_matches(self, pat)
+        let mut i = 0;
+        let mut j = 0;
+        let mut matcher = pat.into_searcher(self);
+        if let Some((a, b)) = matcher.next_reject() {
+            i = a;
+            j = b; // Remember earliest known match, correct it below if
+                   // last match is different
+        }
+        if let Some((_, b)) = matcher.next_reject_back() {
+            j = b;
+        }
+        unsafe {
+            // Searcher is known to return valid indices
+            self.slice_unchecked(i, j)
+        }
     }
 
     /// Returns a string slice with all prefixes that match a pattern
@@ -4061,7 +3704,15 @@ macro_rules! str_core_methods { () => {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
-        StrExt::trim_left_matches(self, pat)
+        let mut i = self.len();
+        let mut matcher = pat.into_searcher(self);
+        if let Some((a, _)) = matcher.next_reject() {
+            i = a;
+        }
+        unsafe {
+            // Searcher is known to return valid indices
+            self.slice_unchecked(i, self.len())
+        }
     }
 
     /// Returns a string slice with all suffixes that match a pattern
@@ -4100,7 +3751,15 @@ macro_rules! str_core_methods { () => {
     pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::trim_right_matches(self, pat)
+        let mut j = 0;
+        let mut matcher = pat.into_searcher(self);
+        if let Some((_, b)) = matcher.next_reject_back() {
+            j = b;
+        }
+        unsafe {
+            // Searcher is known to return valid indices
+            self.slice_unchecked(0, j)
+        }
     }
 
     /// Parses this string slice into another type.
@@ -4150,7 +3809,7 @@ macro_rules! str_core_methods { () => {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
-        StrExt::parse(self)
+        FromStr::from_str(self)
     }
 
     /// Checks if all characters in this string are within the ASCII range.
@@ -4220,16 +3879,8 @@ macro_rules! str_core_methods { () => {
         let me = unsafe { self.as_bytes_mut() };
         me.make_ascii_lowercase()
     }
-}}
-
-#[lang = "str"]
-#[cfg(not(test))]
-#[cfg(not(stage0))]
-impl str {
-    str_core_methods!();
 }
 
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<[u8]> for str {
     #[inline]
@@ -4332,17 +3983,6 @@ pub struct EncodeUtf16<'a> {
     extra: u16,
 }
 
-// FIXME: remove (inline) this method
-// when updating to a bootstrap compiler that has the new lang items.
-// For grepping purpose: #[cfg(stage0)]
-impl<'a> EncodeUtf16<'a> {
-    #[unstable(feature = "core_str_ext", issue = "32110")]
-    #[doc(hidden)]
-    pub fn new(s: &'a str) -> Self {
-        EncodeUtf16 { chars: s.chars(), extra: 0 }
-    }
-}
-
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<'a> fmt::Debug for EncodeUtf16<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 7fb4b503c01..13189d532ab 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -41,9 +41,9 @@
 #![feature(try_from)]
 #![feature(try_trait)]
 #![feature(exact_chunks)]
-#![cfg_attr(stage0, feature(atomic_nand))]
+#![feature(slice_align_to)]
+#![feature(align_offset)]
 #![feature(reverse_bits)]
-#![feature(inclusive_range_methods)]
 #![feature(iterator_find_map)]
 #![feature(slice_internals)]
 
diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs
index 257f6ea20d4..ca6906f7310 100644
--- a/src/libcore/tests/num/uint_macros.rs
+++ b/src/libcore/tests/num/uint_macros.rs
@@ -98,7 +98,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg(not(stage0))]
     fn test_reverse_bits() {
         assert_eq!(A.reverse_bits().reverse_bits(), A);
         assert_eq!(B.reverse_bits().reverse_bits(), B);
diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs
index 00f87336f3c..31bc1d67768 100644
--- a/src/libcore/tests/ptr.rs
+++ b/src/libcore/tests/ptr.rs
@@ -296,3 +296,92 @@ fn write_unaligned_drop() {
     }
     DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
 }
+
+#[test]
+fn align_offset_zst() {
+    // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
+    // all, because no amount of elements will align the pointer.
+    let mut p = 1;
+    while p < 1024 {
+        assert_eq!((p as *const ()).align_offset(p), 0);
+        if p != 1 {
+            assert_eq!(((p + 1) as *const ()).align_offset(p), !0);
+        }
+        p = (p + 1).next_power_of_two();
+    }
+}
+
+#[test]
+fn align_offset_stride1() {
+    // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
+    // number of bytes.
+    let mut align = 1;
+    while align < 1024 {
+        for ptr in 1..2*align {
+            let expected = ptr % align;
+            let offset = if expected == 0 { 0 } else { align - expected };
+            assert_eq!((ptr as *const u8).align_offset(align), offset,
+            "ptr = {}, align = {}, size = 1", ptr, align);
+        }
+        align = (align + 1).next_power_of_two();
+    }
+}
+
+#[test]
+fn align_offset_weird_strides() {
+    #[repr(packed)]
+    struct A3(u16, u8);
+    struct A4(u32);
+    #[repr(packed)]
+    struct A5(u32, u8);
+    #[repr(packed)]
+    struct A6(u32, u16);
+    #[repr(packed)]
+    struct A7(u32, u16, u8);
+    #[repr(packed)]
+    struct A8(u32, u32);
+    #[repr(packed)]
+    struct A9(u32, u32, u8);
+    #[repr(packed)]
+    struct A10(u32, u32, u16);
+
+    unsafe fn test_weird_stride<T>(ptr: *const T, align: usize) -> bool {
+        let numptr = ptr as usize;
+        let mut expected = usize::max_value();
+        // Naive but definitely correct way to find the *first* aligned element of stride::<T>.
+        for el in 0..align {
+            if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
+                expected = el;
+                break;
+            }
+        }
+        let got = ptr.align_offset(align);
+        if got != expected {
+            eprintln!("aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr,
+                      ::std::mem::size_of::<T>(), align, expected, got);
+            return true;
+        }
+        return false;
+    }
+
+    // For pointers of stride != 1, we verify the algorithm against the naivest possible
+    // implementation
+    let mut align = 1;
+    let mut x = false;
+    while align < 1024 {
+        for ptr in 1usize..4*align {
+            unsafe {
+                x |= test_weird_stride::<A3>(ptr as *const A3, align);
+                x |= test_weird_stride::<A4>(ptr as *const A4, align);
+                x |= test_weird_stride::<A5>(ptr as *const A5, align);
+                x |= test_weird_stride::<A6>(ptr as *const A6, align);
+                x |= test_weird_stride::<A7>(ptr as *const A7, align);
+                x |= test_weird_stride::<A8>(ptr as *const A8, align);
+                x |= test_weird_stride::<A9>(ptr as *const A9, align);
+                x |= test_weird_stride::<A10>(ptr as *const A10, align);
+            }
+        }
+        align = (align + 1).next_power_of_two();
+    }
+    assert!(!x);
+}
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 19b5c86c474..fcd79222e16 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -812,3 +812,37 @@ pub mod memchr {
         }
     }
 }
+
+#[test]
+fn test_align_to_simple() {
+    let bytes = [1u8, 2, 3, 4, 5, 6, 7];
+    let (prefix, aligned, suffix) = unsafe { bytes.align_to::<u16>() };
+    assert_eq!(aligned.len(), 3);
+    assert!(prefix == [1] || suffix == [7]);
+    let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6];
+    let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8];
+    let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7];
+    let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8];
+    assert!(aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4,
+            "aligned={:?} expected={:?} || {:?} || {:?} || {:?}",
+            aligned, expect1, expect2, expect3, expect4);
+}
+
+#[test]
+fn test_align_to_zst() {
+    let bytes = [1, 2, 3, 4, 5, 6, 7];
+    let (prefix, aligned, suffix) = unsafe { bytes.align_to::<()>() };
+    assert_eq!(aligned.len(), 0);
+    assert!(prefix == [1, 2, 3, 4, 5, 6, 7] || suffix == [1, 2, 3, 4, 5, 6, 7]);
+}
+
+#[test]
+fn test_align_to_non_trivial() {
+    #[repr(align(8))] struct U64(u64, u64);
+    #[repr(align(8))] struct U64U64U32(u64, u64, u32);
+    let data = [U64(1, 2), U64(3, 4), U64(5, 6), U64(7, 8), U64(9, 10), U64(11, 12), U64(13, 14),
+                U64(15, 16)];
+    let (prefix, aligned, suffix) = unsafe { data.align_to::<U64U64U32>() };
+    assert_eq!(aligned.len(), 4);
+    assert_eq!(prefix.len() + suffix.len(), 2);
+}
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index a551b1b770a..a77751d65d0 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -127,6 +127,14 @@ pub enum Count<'a> {
     CountImplied,
 }
 
+pub struct ParseError {
+    pub description: string::String,
+    pub note: Option<string::String>,
+    pub label: string::String,
+    pub start: usize,
+    pub end: usize,
+}
+
 /// The parser structure for interpreting the input format string. This is
 /// modeled as an iterator over `Piece` structures to form a stream of tokens
 /// being output.
@@ -137,7 +145,7 @@ pub struct Parser<'a> {
     input: &'a str,
     cur: iter::Peekable<str::CharIndices<'a>>,
     /// Error messages accumulated during parsing
-    pub errors: Vec<(string::String, Option<string::String>)>,
+    pub errors: Vec<ParseError>,
     /// Current position of implicit positional argument pointer
     curarg: usize,
 }
@@ -160,12 +168,17 @@ impl<'a> Iterator for Parser<'a> {
                 }
                 '}' => {
                     self.cur.next();
+                    let pos = pos + 1;
                     if self.consume('}') {
-                        Some(String(self.string(pos + 1)))
+                        Some(String(self.string(pos)))
                     } else {
-                        self.err_with_note("unmatched `}` found",
-                                           "if you intended to print `}`, \
-                                           you can escape it using `}}`");
+                        self.err_with_note(
+                            "unmatched `}` found",
+                            "unmatched `}`",
+                            "if you intended to print `}`, you can escape it using `}}`",
+                            pos,
+                            pos,
+                        );
                         None
                     }
                 }
@@ -191,15 +204,40 @@ impl<'a> Parser<'a> {
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err(&mut self, msg: &str) {
-        self.errors.push((msg.to_owned(), None));
+    fn err<S1: Into<string::String>, S2: Into<string::String>>(
+        &mut self,
+        description: S1,
+        label: S2,
+        start: usize,
+        end: usize,
+    ) {
+        self.errors.push(ParseError {
+            description: description.into(),
+            note: None,
+            label: label.into(),
+            start,
+            end,
+        });
     }
 
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err_with_note(&mut self, msg: &str, note: &str) {
-        self.errors.push((msg.to_owned(), Some(note.to_owned())));
+    fn err_with_note<S1: Into<string::String>, S2: Into<string::String>, S3: Into<string::String>>(
+        &mut self,
+        description: S1,
+        label: S2,
+        note: S3,
+        start: usize,
+        end: usize,
+    ) {
+        self.errors.push(ParseError {
+            description: description.into(),
+            note: Some(note.into()),
+            label: label.into(),
+            start,
+            end,
+        });
     }
 
     /// Optionally consumes the specified character. If the character is not at
@@ -222,19 +260,26 @@ impl<'a> Parser<'a> {
     /// found, an error is emitted.
     fn must_consume(&mut self, c: char) {
         self.ws();
-        if let Some(&(_, maybe)) = self.cur.peek() {
+        if let Some(&(pos, maybe)) = self.cur.peek() {
             if c == maybe {
                 self.cur.next();
             } else {
-                self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe));
+                self.err(format!("expected `{:?}`, found `{:?}`", c, maybe),
+                         format!("expected `{}`", c),
+                         pos + 1,
+                         pos + 1);
             }
         } else {
-            let msg = &format!("expected `{:?}` but string was terminated", c);
+            let msg = format!("expected `{:?}` but string was terminated", c);
+            let pos = self.input.len() + 1; // point at closing `"`
             if c == '}' {
                 self.err_with_note(msg,
-                                   "if you intended to print `{`, you can escape it using `{{`");
+                                   format!("expected `{:?}`", c),
+                                   "if you intended to print `{`, you can escape it using `{{`",
+                                   pos,
+                                   pos);
             } else {
-                self.err(msg);
+                self.err(msg, format!("expected `{:?}`", c), pos, pos);
             }
         }
     }
@@ -300,6 +345,15 @@ impl<'a> Parser<'a> {
         } else {
             match self.cur.peek() {
                 Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())),
+                Some(&(pos, c)) if c == '_' => {
+                    let invalid_name = self.string(pos);
+                    self.err_with_note(format!("invalid argument name `{}`", invalid_name),
+                                       "invalid argument name",
+                                       "argument names cannot start with an underscore",
+                                       pos + 1, // add 1 to account for leading `{`
+                                       pos + 1 + invalid_name.len());
+                    Some(ArgumentNamed(invalid_name))
+                },
 
                 // This is an `ArgumentNext`.
                 // Record the fact and do the resolution after parsing the
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 610a9a2a394..bcab6168096 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -818,7 +818,7 @@ impl Ident {
     pub fn new_raw(string: &str, span: Span) -> Ident {
         let mut ident = Ident::new(string, span);
         if ident.sym == keywords::Underscore.name() ||
-           token::is_path_segment_keyword(ast::Ident::with_empty_ctxt(ident.sym)) {
+           ast::Ident::with_empty_ctxt(ident.sym).is_path_segment_keyword() {
             panic!("`{:?}` is not a valid raw identifier", string)
         }
         ident.is_raw = true;
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 0f4871954d6..45d429612a1 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -593,6 +593,7 @@ impl<'a> LoweringContext<'a> {
                 span: Some(span),
                 allow_internal_unstable: true,
                 allow_internal_unsafe: false,
+                edition: codemap::hygiene::default_edition(),
             },
         });
         span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 9cd9e0dce54..940a68e8ce5 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -13,7 +13,7 @@ pub use self::AnnNode::*;
 use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::codemap::{CodeMap, Spanned};
-use syntax::parse::{token, ParseSess};
+use syntax::parse::ParseSess;
 use syntax::parse::lexer::comments;
 use syntax::print::pp::{self, Breaks};
 use syntax::print::pp::Breaks::{Consistent, Inconsistent};
@@ -1559,7 +1559,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
-        if token::is_raw_guess(ast::Ident::with_empty_ctxt(name)) {
+        if name.to_ident().is_raw_guess() {
             self.s.word(&format!("r#{}", name))?;
         } else {
             self.s.word(&name.as_str())?;
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index f56d701b028..3a37c1c18c8 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -132,6 +132,15 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
 });
 
 impl<'a> HashStable<StableHashingContext<'a>>
+for ::syntax::edition::Edition {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>>
 for ::syntax::attr::StabilityLevel {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a>,
@@ -389,6 +398,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan {
     format,
     allow_internal_unstable,
     allow_internal_unsafe,
+    edition,
     span
 });
 
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 31dce2a14c2..1b16d93ef27 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -132,7 +132,7 @@ for ty::RegionKind {
             ty::ReLateBound(..) |
             ty::ReVar(..) |
             ty::ReSkolemized(..) => {
-                bug!("TypeIdHasher: unexpected region {:?}", *self)
+                bug!("StableHasher: unexpected region {:?}", *self)
             }
         }
     }
@@ -401,8 +401,9 @@ for ::mir::interpret::ConstValue<'gcx> {
                 a.hash_stable(hcx, hasher);
                 b.hash_stable(hcx, hasher);
             }
-            ByRef(alloc) => {
+            ByRef(alloc, offset) => {
                 alloc.hash_stable(hcx, hasher);
+                offset.hash_stable(hcx, hasher);
             }
         }
     }
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index c388fa21371..99d7b4eaf7d 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -318,7 +318,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         // should think carefully about whether it needs to be cleared
         // or updated in some way.
         let RegionConstraintCollector {
-            var_infos,
+            var_infos: _,
             data,
             lubs,
             glbs,
@@ -338,10 +338,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         // un-unified" state. Note that when we unify `a` and `b`, we
         // also insert `a <= b` and a `b <= a` edges, so the
         // `RegionConstraintData` contains the relationship here.
-        *unification_table = ut::UnificationTable::new();
-        for vid in var_infos.indices() {
-            unification_table.new_key(unify_key::RegionVidKey { min_vid: vid });
-        }
+        unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
 
         mem::replace(data, RegionConstraintData::default())
     }
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index ac6ff6831ad..1d53a305193 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -46,7 +46,6 @@
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![feature(entry_or_default)]
-#![cfg_attr(stage0, feature(dyn_trait))]
 #![feature(from_ref)]
 #![feature(fs_read_write)]
 #![feature(iterator_find_map)]
@@ -69,7 +68,6 @@
 #![feature(trusted_len)]
 #![feature(catch_expr)]
 #![feature(test)]
-#![feature(inclusive_range_methods)]
 
 #![recursion_limit="512"]
 
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 5ebea52f3c5..ac2fa8515bc 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -27,7 +27,7 @@ declare_lint! {
 
 declare_lint! {
     pub CONST_ERR,
-    Warn,
+    Deny,
     "constant evaluation detected erroneous expression"
 }
 
@@ -177,12 +177,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    pub LEGACY_IMPORTS,
-    Deny,
-    "detects names that resolve to ambiguous glob imports with RFC 1560"
-}
-
-declare_lint! {
     pub LEGACY_CONSTRUCTOR_VISIBILITY,
     Deny,
     "detects use of struct constructors that would be invisible with new visibility rules"
@@ -279,6 +273,12 @@ declare_lint! {
     "detects name collision with an existing but unstable method"
 }
 
+declare_lint! {
+    pub UNUSED_LABELS,
+    Allow,
+    "detects labels that are never used"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -314,7 +314,6 @@ impl LintPass for HardwiredLints {
             SAFE_PACKED_BORROWS,
             PATTERNS_IN_FNS_WITHOUT_BODY,
             LEGACY_DIRECTORY_OWNERSHIP,
-            LEGACY_IMPORTS,
             LEGACY_CONSTRUCTOR_VISIBILITY,
             MISSING_FRAGMENT_SPECIFIER,
             PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
@@ -325,6 +324,7 @@ impl LintPass for HardwiredLints {
             UNUSED_MUT,
             SINGLE_USE_LIFETIME,
             UNUSED_LIFETIME,
+            UNUSED_LABELS,
             TYVAR_BEHIND_RAW_POINTER,
             ELIDED_LIFETIME_IN_PATH,
             BARE_TRAIT_OBJECT,
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 61c8470b616..518021f4125 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -34,6 +34,7 @@ use session::search_paths::PathKind;
 use std::any::Any;
 use std::path::{Path, PathBuf};
 use syntax::ast;
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -235,6 +236,7 @@ pub trait CrateStore {
     fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
     fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
+    fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition;
     fn struct_field_names_untracked(&self, def: DefId) -> Vec<ast::Name>;
     fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec<def::Export>;
     fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro;
@@ -309,6 +311,7 @@ impl CrateStore for DummyCrateStore {
         bug!("crate_disambiguator")
     }
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") }
+    fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { bug!("crate_edition_untracked") }
 
     // resolve
     fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") }
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 95e92e21b09..d70f994e87b 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -348,6 +348,9 @@ language_item_table! {
     I128ShroFnLangItem,              "i128_shro",               i128_shro_fn;
     U128ShroFnLangItem,              "u128_shro",               u128_shro_fn;
 
+    // Align offset for stride != 1, must not panic.
+    AlignOffsetLangItem,             "align_offset",            align_offset_fn;
+
     TerminationTraitLangItem,        "termination",             termination;
 }
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index b39311a7471..3db8c746713 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -117,6 +117,7 @@ use std::io::prelude::*;
 use std::io;
 use std::rc::Rc;
 use syntax::ast::{self, NodeId};
+use syntax::ptr::P;
 use syntax::symbol::keywords;
 use syntax_pos::Span;
 
@@ -398,72 +399,65 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
     lsets.warn_about_unused_args(body, entry_ln);
 }
 
-fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
-    local.pat.each_binding(|_, p_id, sp, path1| {
-        debug!("adding local variable {}", p_id);
+fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P<hir::Pat>) {
+    // For struct patterns, take note of which fields used shorthand
+    // (`x` rather than `x: x`).
+    //
+    // FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be
+    // phased out in favor of `HirId`s; however, we need to match the signature of
+    // `each_binding`, which uses `NodeIds`.
+    let mut shorthand_field_ids = NodeSet();
+    let mut pats = VecDeque::new();
+    pats.push_back(pat);
+    while let Some(pat) = pats.pop_front() {
+        use hir::PatKind::*;
+        match pat.node {
+            Binding(_, _, _, ref inner_pat) => {
+                pats.extend(inner_pat.iter());
+            }
+            Struct(_, ref fields, _) => {
+                for field in fields {
+                    if field.node.is_shorthand {
+                        shorthand_field_ids.insert(field.node.pat.id);
+                    }
+                }
+            }
+            Ref(ref inner_pat, _) |
+            Box(ref inner_pat) => {
+                pats.push_back(inner_pat);
+            }
+            TupleStruct(_, ref inner_pats, _) |
+            Tuple(ref inner_pats, _) => {
+                pats.extend(inner_pats.iter());
+            }
+            Slice(ref pre_pats, ref inner_pat, ref post_pats) => {
+                pats.extend(pre_pats.iter());
+                pats.extend(inner_pat.iter());
+                pats.extend(post_pats.iter());
+            }
+            _ => {}
+        }
+    }
+
+    pat.each_binding(|_bm, p_id, _sp, path1| {
         let name = path1.node;
-        ir.add_live_node_for_node(p_id, VarDefNode(sp));
+        ir.add_live_node_for_node(p_id, VarDefNode(path1.span));
         ir.add_variable(Local(LocalInfo {
             id: p_id,
             name,
-            is_shorthand: false,
+            is_shorthand: shorthand_field_ids.contains(&p_id)
         }));
     });
+}
+
+fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
+    add_from_pat(ir, &local.pat);
     intravisit::walk_local(ir, local);
 }
 
 fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) {
-    for mut pat in &arm.pats {
-        // For struct patterns, take note of which fields used shorthand
-        // (`x` rather than `x: x`).
-        //
-        // FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be
-        // phased out in favor of `HirId`s; however, we need to match the signature of
-        // `each_binding`, which uses `NodeIds`.
-        let mut shorthand_field_ids = NodeSet();
-        let mut pats = VecDeque::new();
-        pats.push_back(pat);
-        while let Some(pat) = pats.pop_front() {
-            use hir::PatKind::*;
-            match pat.node {
-                Binding(_, _, _, ref inner_pat) => {
-                    pats.extend(inner_pat.iter());
-                }
-                Struct(_, ref fields, _) => {
-                    for field in fields {
-                        if field.node.is_shorthand {
-                            shorthand_field_ids.insert(field.node.pat.id);
-                        }
-                    }
-                }
-                Ref(ref inner_pat, _) |
-                Box(ref inner_pat) => {
-                    pats.push_back(inner_pat);
-                }
-                TupleStruct(_, ref inner_pats, _) |
-                Tuple(ref inner_pats, _) => {
-                    pats.extend(inner_pats.iter());
-                }
-                Slice(ref pre_pats, ref inner_pat, ref post_pats) => {
-                    pats.extend(pre_pats.iter());
-                    pats.extend(inner_pat.iter());
-                    pats.extend(post_pats.iter());
-                }
-                _ => {}
-            }
-        }
-
-        pat.each_binding(|bm, p_id, _sp, path1| {
-            debug!("adding local variable {} from match with bm {:?}",
-                   p_id, bm);
-            let name = path1.node;
-            ir.add_live_node_for_node(p_id, VarDefNode(path1.span));
-            ir.add_variable(Local(LocalInfo {
-                id: p_id,
-                name: name,
-                is_shorthand: shorthand_field_ids.contains(&p_id)
-            }));
-        })
+    for pat in &arm.pats {
+        add_from_pat(ir, pat);
     }
     intravisit::walk_arm(ir, arm);
 }
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 71d7abed6c9..42a08afe305 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -542,18 +542,6 @@ impl<'tcx> ScopeTree {
         assert!(previous.is_none());
     }
 
-    fn closure_is_enclosed_by(&self,
-                              mut sub_closure: hir::ItemLocalId,
-                              sup_closure: hir::ItemLocalId) -> bool {
-        loop {
-            if sub_closure == sup_closure { return true; }
-            match self.closure_tree.get(&sub_closure) {
-                Some(&s) => { sub_closure = s; }
-                None => { return false; }
-            }
-        }
-    }
-
     fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) {
         debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
         assert!(var != lifetime.item_local_id());
@@ -688,65 +676,37 @@ impl<'tcx> ScopeTree {
         // requires a hash table lookup, and we often have very long scope
         // chains (10s or 100s of scopes) that only differ by a few elements at
         // the start. So this algorithm is faster.
-        let mut ma = Some(scope_a);
-        let mut mb = Some(scope_b);
-        let mut seen_a: SmallVec<[Scope; 32]> = SmallVec::new();
-        let mut seen_b: SmallVec<[Scope; 32]> = SmallVec::new();
+
+        let mut ma = Some(&scope_a);
+        let mut mb = Some(&scope_b);
+
+        // A HashSet<Scope> is a more obvious choice for these, but SmallVec is
+        // faster because the set size is normally small so linear search is
+        // as good or better than a hash table lookup, plus the size is usually
+        // small enough to avoid a heap allocation.
+        let mut seen_a: SmallVec<[&Scope; 32]> = SmallVec::new();
+        let mut seen_b: SmallVec<[&Scope; 32]> = SmallVec::new();
+
         loop {
             if let Some(a) = ma {
-                if seen_b.iter().position(|s| *s == a).is_some() {
-                    return a;
+                if seen_b.iter().any(|s| *s == a) {
+                    return *a;
                 }
                 seen_a.push(a);
-                ma = self.parent_map.get(&a).map(|s| *s);
+                ma = self.parent_map.get(&a);
             }
 
             if let Some(b) = mb {
-                if seen_a.iter().position(|s| *s == b).is_some() {
-                    return b;
+                if seen_a.iter().any(|s| *s == b) {
+                    return *b;
                 }
                 seen_b.push(b);
-                mb = self.parent_map.get(&b).map(|s| *s);
+                mb = self.parent_map.get(&b);
             }
 
             if ma.is_none() && mb.is_none() {
-                break;
-            }
-        };
-
-        fn outermost_scope(parent_map: &FxHashMap<Scope, Scope>, scope: Scope) -> Scope {
-            let mut scope = scope;
-            loop {
-               match parent_map.get(&scope) {
-                   Some(&superscope) => scope = superscope,
-                   None => break scope,
-               }
-            }
-        }
-
-        // In this (rare) case, the two regions belong to completely different
-        // functions. Compare those fn for lexical nesting. The reasoning
-        // behind this is subtle. See the "Modeling closures" section of the
-        // README in infer::region_constraints for more details.
-        let a_root_scope = outermost_scope(&self.parent_map, scope_a);
-        let b_root_scope = outermost_scope(&self.parent_map, scope_b);
-        match (a_root_scope.data(), b_root_scope.data()) {
-            (ScopeData::Destruction(a_root_id),
-             ScopeData::Destruction(b_root_id)) => {
-                if self.closure_is_enclosed_by(a_root_id, b_root_id) {
-                    // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
-                    scope_b
-                } else if self.closure_is_enclosed_by(b_root_id, a_root_id) {
-                    // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
-                    scope_a
-                } else {
-                    // neither fn encloses the other
-                    bug!()
-                }
-            }
-            _ => {
-                // root ids are always Node right now
-                bug!()
+                // No nearest common ancestor found.
+                bug!();
             }
         }
     }
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 1e1d50c3fc0..6885bf89cc8 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -2,6 +2,7 @@ use std::{fmt, env};
 
 use mir;
 use ty::{FnSig, Ty, layout};
+use ty::layout::{Size, Align};
 
 use super::{
     MemoryPointer, Lock, AccessKind
@@ -47,7 +48,7 @@ pub enum EvalErrorKind<'tcx, O> {
     PointerOutOfBounds {
         ptr: MemoryPointer,
         access: bool,
-        allocation_size: u64,
+        allocation_size: Size,
     },
     InvalidNullPointerUsage,
     ReadPointerAsBytes,
@@ -71,8 +72,8 @@ pub enum EvalErrorKind<'tcx, O> {
     TlsOutOfBounds,
     AbiViolation(String),
     AlignmentCheckFailed {
-        required: u64,
-        has: u64,
+        required: Align,
+        has: Align,
     },
     MemoryLockViolation {
         ptr: MemoryPointer,
@@ -108,7 +109,7 @@ pub enum EvalErrorKind<'tcx, O> {
     DeallocatedWrongMemoryKind(String, String),
     ReallocateNonBasePtr,
     DeallocateNonBasePtr,
-    IncorrectAllocationInformation(u64, usize, u64, u64),
+    IncorrectAllocationInformation(Size, Size, Align, Align),
     Layout(layout::LayoutError<'tcx>),
     HeapAllocZeroBytes,
     HeapAllocNonPowerOfTwoAlignment(u64),
@@ -269,7 +270,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
             PointerOutOfBounds { ptr, access, allocation_size } => {
                 write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}",
                        if access { "memory access" } else { "pointer computed" },
-                       ptr.offset, ptr.alloc_id, allocation_size)
+                       ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
             },
             MemoryLockViolation { ptr, len, frame, access, ref lock } => {
                 write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}",
@@ -305,7 +306,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
                 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
             AlignmentCheckFailed { required, has } =>
                write!(f, "tried to access memory with alignment {}, but alignment {} is required",
-                      has, required),
+                      has.abi(), required.abi()),
             TypeNotPrimitive(ty) =>
                 write!(f, "expected primitive type, got {}", ty),
             Layout(ref err) =>
@@ -315,7 +316,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
             MachineError(ref inner) =>
                 write!(f, "{}", inner),
             IncorrectAllocationInformation(size, size2, align, align2) =>
-                write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2),
+                write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
             _ => write!(f, "{}", self.description()),
         }
     }
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 31885c1e020..d4f18acf8ad 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -17,7 +17,7 @@ use std::fmt;
 use mir;
 use hir::def_id::DefId;
 use ty::{self, TyCtxt};
-use ty::layout::{self, Align, HasDataLayout};
+use ty::layout::{self, Align, HasDataLayout, Size};
 use middle::region;
 use std::iter;
 use std::io;
@@ -109,42 +109,42 @@ impl<T: layout::HasDataLayout> PointerArithmetic for T {}
 #[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
 pub struct MemoryPointer {
     pub alloc_id: AllocId,
-    pub offset: u64,
+    pub offset: Size,
 }
 
 impl<'tcx> MemoryPointer {
-    pub fn new(alloc_id: AllocId, offset: u64) -> Self {
+    pub fn new(alloc_id: AllocId, offset: Size) -> Self {
         MemoryPointer { alloc_id, offset }
     }
 
     pub(crate) fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
         MemoryPointer::new(
             self.alloc_id,
-            cx.data_layout().wrapping_signed_offset(self.offset, i),
+            Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
         )
     }
 
     pub fn overflowing_signed_offset<C: HasDataLayout>(self, i: i128, cx: C) -> (Self, bool) {
-        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset, i);
-        (MemoryPointer::new(self.alloc_id, res), over)
+        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
+        (MemoryPointer::new(self.alloc_id, Size::from_bytes(res)), over)
     }
 
     pub(crate) fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
         Ok(MemoryPointer::new(
             self.alloc_id,
-            cx.data_layout().signed_offset(self.offset, i)?,
+            Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
         ))
     }
 
-    pub fn overflowing_offset<C: HasDataLayout>(self, i: u64, cx: C) -> (Self, bool) {
-        let (res, over) = cx.data_layout().overflowing_offset(self.offset, i);
-        (MemoryPointer::new(self.alloc_id, res), over)
+    pub fn overflowing_offset<C: HasDataLayout>(self, i: Size, cx: C) -> (Self, bool) {
+        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
+        (MemoryPointer::new(self.alloc_id, Size::from_bytes(res)), over)
     }
 
-    pub fn offset<C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> {
+    pub fn offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
         Ok(MemoryPointer::new(
             self.alloc_id,
-            cx.data_layout().offset(self.offset, i)?,
+            Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
         ))
     }
 }
@@ -244,7 +244,7 @@ pub struct Allocation {
     pub bytes: Vec<u8>,
     /// Maps from byte addresses to allocations.
     /// Only the first byte of a pointer is inserted into the map.
-    pub relocations: BTreeMap<u64, AllocId>,
+    pub relocations: BTreeMap<Size, AllocId>,
     /// Denotes undefined memory. Reading from undefined memory is forbidden in miri
     pub undef_mask: UndefMask,
     /// The alignment of the allocation to detect unaligned reads.
@@ -257,8 +257,8 @@ pub struct Allocation {
 
 impl Allocation {
     pub fn from_bytes(slice: &[u8], align: Align) -> Self {
-        let mut undef_mask = UndefMask::new(0);
-        undef_mask.grow(slice.len() as u64, true);
+        let mut undef_mask = UndefMask::new(Size::from_bytes(0));
+        undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
         Self {
             bytes: slice.to_owned(),
             relocations: BTreeMap::new(),
@@ -272,10 +272,10 @@ impl Allocation {
         Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
     }
 
-    pub fn undef(size: u64, align: Align) -> Self {
-        assert_eq!(size as usize as u64, size);
+    pub fn undef(size: Size, align: Align) -> Self {
+        assert_eq!(size.bytes() as usize as u64, size.bytes());
         Allocation {
-            bytes: vec![0; size as usize],
+            bytes: vec![0; size.bytes() as usize],
             relocations: BTreeMap::new(),
             undef_mask: UndefMask::new(size),
             align,
@@ -331,35 +331,35 @@ const BLOCK_SIZE: u64 = 64;
 #[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub struct UndefMask {
     blocks: Vec<Block>,
-    len: u64,
+    len: Size,
 }
 
 impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
 
 impl UndefMask {
-    pub fn new(size: u64) -> Self {
+    pub fn new(size: Size) -> Self {
         let mut m = UndefMask {
             blocks: vec![],
-            len: 0,
+            len: Size::from_bytes(0),
         };
         m.grow(size, false);
         m
     }
 
     /// Check whether the range `start..end` (end-exclusive) is entirely defined.
-    pub fn is_range_defined(&self, start: u64, end: u64) -> bool {
+    pub fn is_range_defined(&self, start: Size, end: Size) -> bool {
         if end > self.len {
             return false;
         }
-        for i in start..end {
-            if !self.get(i) {
+        for i in start.bytes()..end.bytes() {
+            if !self.get(Size::from_bytes(i)) {
                 return false;
             }
         }
         true
     }
 
-    pub fn set_range(&mut self, start: u64, end: u64, new_state: bool) {
+    pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) {
         let len = self.len;
         if end > len {
             self.grow(end - len, new_state);
@@ -367,18 +367,18 @@ impl UndefMask {
         self.set_range_inbounds(start, end, new_state);
     }
 
-    pub fn set_range_inbounds(&mut self, start: u64, end: u64, new_state: bool) {
-        for i in start..end {
-            self.set(i, new_state);
+    pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
+        for i in start.bytes()..end.bytes() {
+            self.set(Size::from_bytes(i), new_state);
         }
     }
 
-    pub fn get(&self, i: u64) -> bool {
+    pub fn get(&self, i: Size) -> bool {
         let (block, bit) = bit_index(i);
         (self.blocks[block] & 1 << bit) != 0
     }
 
-    pub fn set(&mut self, i: u64, new_state: bool) {
+    pub fn set(&mut self, i: Size, new_state: bool) {
         let (block, bit) = bit_index(i);
         if new_state {
             self.blocks[block] |= 1 << bit;
@@ -387,10 +387,10 @@ impl UndefMask {
         }
     }
 
-    pub fn grow(&mut self, amount: u64, new_state: bool) {
-        let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len;
-        if amount > unused_trailing_bits {
-            let additional_blocks = amount / BLOCK_SIZE + 1;
+    pub fn grow(&mut self, amount: Size, new_state: bool) {
+        let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes();
+        if amount.bytes() > unused_trailing_bits {
+            let additional_blocks = amount.bytes() / BLOCK_SIZE + 1;
             assert_eq!(additional_blocks as usize as u64, additional_blocks);
             self.blocks.extend(
                 iter::repeat(0).take(additional_blocks as usize),
@@ -402,7 +402,8 @@ impl UndefMask {
     }
 }
 
-fn bit_index(bits: u64) -> (usize, usize) {
+fn bit_index(bits: Size) -> (usize, usize) {
+    let bits = bits.bytes();
     let a = bits / BLOCK_SIZE;
     let b = bits % BLOCK_SIZE;
     assert_eq!(a as usize as u64, a);
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 7bd84a607e7..5ac2f7f356e 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -1,6 +1,6 @@
 #![allow(unknown_lints)]
 
-use ty::layout::{Align, HasDataLayout};
+use ty::layout::{Align, HasDataLayout, Size};
 use ty;
 
 use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
@@ -9,12 +9,12 @@ use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
 /// matches Value's optimizations for easy conversions between these two types
 #[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
 pub enum ConstValue<'tcx> {
-    // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
+    /// Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
     ByVal(PrimVal),
-    // Used only for types with layout::abi::ScalarPair
+    /// Used only for types with layout::abi::ScalarPair
     ByValPair(PrimVal, PrimVal),
-    // Used only for the remaining cases
-    ByRef(&'tcx Allocation),
+    /// Used only for the remaining cases. An allocation + offset into the allocation
+    ByRef(&'tcx Allocation, Size),
 }
 
 impl<'tcx> ConstValue<'tcx> {
@@ -129,13 +129,13 @@ impl<'tcx> Pointer {
         }
     }
 
-    pub fn offset<C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> {
+    pub fn offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
         let layout = cx.data_layout();
         match self.primval {
             PrimVal::Bytes(b) => {
                 assert_eq!(b as u64 as u128, b);
                 Ok(Pointer::from(
-                    PrimVal::Bytes(layout.offset(b as u64, i)? as u128),
+                    PrimVal::Bytes(layout.offset(b as u64, i.bytes())? as u128),
                 ))
             }
             PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from),
@@ -336,25 +336,25 @@ impl PrimValKind {
         }
     }
 
-    pub fn from_uint_size(size: u64) -> Self {
-        match size {
+    pub fn from_uint_size(size: Size) -> Self {
+        match size.bytes() {
             1 => PrimValKind::U8,
             2 => PrimValKind::U16,
             4 => PrimValKind::U32,
             8 => PrimValKind::U64,
             16 => PrimValKind::U128,
-            _ => bug!("can't make uint with size {}", size),
+            _ => bug!("can't make uint with size {}", size.bytes()),
         }
     }
 
-    pub fn from_int_size(size: u64) -> Self {
-        match size {
+    pub fn from_int_size(size: Size) -> Self {
+        match size.bytes() {
             1 => PrimValKind::I8,
             2 => PrimValKind::I16,
             4 => PrimValKind::I32,
             8 => PrimValKind::I64,
             16 => PrimValKind::I128,
-            _ => bug!("can't make int with size {}", size),
+            _ => bug!("can't make int with size {}", size.bytes()),
         }
     }
 
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 40e9b687f0c..f42f876510d 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1913,7 +1913,7 @@ pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Resul
                     .get_alloc(ptr.alloc_id);
                 if let Some(alloc) = alloc {
                     assert_eq!(len as usize as u128, len);
-                    let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)];
+                    let slice = &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
                     let s = ::std::str::from_utf8(slice)
                         .expect("non utf8 str from miri");
                     write!(f, "{:?}", s)
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 2344cd11f66..bcad3fbc841 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1239,8 +1239,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "print the result of the monomorphization collection pass"),
     mir_opt_level: usize = (1, parse_uint, [TRACKED],
           "set the MIR optimization level (0-3, default: 1)"),
-    mutable_noalias: bool = (false, parse_bool, [TRACKED],
-          "emit noalias metadata for mutable references"),
+    mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
+          "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
     arg_align_attributes: bool = (false, parse_bool, [TRACKED],
           "emit align metadata for reference arguments"),
     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index e4520bce681..97ce730c59e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -203,17 +203,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     obligation.cause.span,
                     infer::LateBoundRegionConversionTime::HigherRankedType,
                     data);
-                let normalized = super::normalize_projection_type(
+                let mut obligations = vec![];
+                let normalized_ty = super::normalize_projection_type(
                     &mut selcx,
                     obligation.param_env,
                     data.projection_ty,
                     obligation.cause.clone(),
-                    0
+                    0,
+                    &mut obligations
                 );
                 if let Err(error) = self.at(&obligation.cause, obligation.param_env)
-                                        .eq(normalized.value, data.ty) {
+                                        .eq(normalized_ty, data.ty) {
                     values = Some(infer::ValuePairs::Types(ExpectedFound {
-                        expected: normalized.value,
+                        expected: normalized_ty,
                         found: data.ty,
                     }));
                     err_buf = error;
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 94ee3947077..4447a2b6ed1 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -161,19 +161,18 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         // FIXME(#20304) -- cache
 
         let mut selcx = SelectionContext::new(infcx);
-        let normalized = project::normalize_projection_type(&mut selcx,
-                                                            param_env,
-                                                            projection_ty,
-                                                            cause,
-                                                            0);
-
-        for obligation in normalized.obligations {
-            self.register_predicate_obligation(infcx, obligation);
-        }
-
-        debug!("normalize_projection_type: result={:?}", normalized.value);
-
-        normalized.value
+        let mut obligations = vec![];
+        let normalized_ty = project::normalize_projection_type(&mut selcx,
+                                                               param_env,
+                                                               projection_ty,
+                                                               cause,
+                                                               0,
+                                                               &mut obligations);
+        self.register_predicate_obligations(infcx, obligations);
+
+        debug!("normalize_projection_type: result={:?}", normalized_ty);
+
+        normalized_ty
     }
 
     /// Requires that `ty` must implement the trait with `def_id` in
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 270e06a872b..174c35d1d69 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -225,12 +225,14 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
     debug!("project_and_unify_type(obligation={:?})",
            obligation);
 
-    let Normalized { value: normalized_ty, mut obligations } =
+    let mut obligations = vec![];
+    let normalized_ty =
         match opt_normalize_projection_type(selcx,
                                             obligation.param_env,
                                             obligation.predicate.projection_ty,
                                             obligation.cause.clone(),
-                                            obligation.recursion_depth) {
+                                            obligation.recursion_depth,
+                                            &mut obligations) {
             Some(n) => n,
             None => return Ok(None),
         };
@@ -386,16 +388,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
                 // binder). It would be better to normalize in a
                 // binding-aware fashion.
 
-                let Normalized { value: normalized_ty, obligations } =
-                    normalize_projection_type(self.selcx,
-                                              self.param_env,
-                                              data.clone(),
-                                              self.cause.clone(),
-                                              self.depth);
-                debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?} \
-                        with {} add'l obligations",
-                       self.depth, ty, normalized_ty, obligations.len());
-                self.obligations.extend(obligations);
+                let normalized_ty = normalize_projection_type(self.selcx,
+                                                              self.param_env,
+                                                              data.clone(),
+                                                              self.cause.clone(),
+                                                              self.depth,
+                                                              &mut self.obligations);
+                debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?}, \
+                        now with {} obligations",
+                       self.depth, ty, normalized_ty, self.obligations.len());
                 normalized_ty
             }
 
@@ -471,10 +472,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::ProjectionTy<'tcx>,
     cause: ObligationCause<'tcx>,
-    depth: usize)
-    -> NormalizedTy<'tcx>
+    depth: usize,
+    obligations: &mut Vec<PredicateObligation<'tcx>>)
+    -> Ty<'tcx>
 {
-    opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth)
+    opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth,
+                                  obligations)
         .unwrap_or_else(move || {
             // if we bottom out in ambiguity, create a type variable
             // and a deferred predicate to resolve this when more type
@@ -490,10 +493,8 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             });
             let obligation = Obligation::with_depth(
                 cause, depth + 1, param_env, projection.to_predicate());
-            Normalized {
-                value: ty_var,
-                obligations: vec![obligation]
-            }
+            obligations.push(obligation);
+            ty_var
         })
 }
 
@@ -501,13 +502,20 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
 /// as Trait>::Item`. The result is always a type (and possibly
 /// additional obligations). Returns `None` in the case of ambiguity,
 /// which indicates that there are unbound type variables.
+///
+/// This function used to return `Option<NormalizedTy<'tcx>>`, which contains a
+/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very
+/// often immediately appended to another obligations vector. So now this
+/// function takes an obligations vector and appends to it directly, which is
+/// slightly uglier but avoids the need for an extra short-lived allocation.
 fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::ProjectionTy<'tcx>,
     cause: ObligationCause<'tcx>,
-    depth: usize)
-    -> Option<NormalizedTy<'tcx>>
+    depth: usize,
+    obligations: &mut Vec<PredicateObligation<'tcx>>)
+    -> Option<Ty<'tcx>>
 {
     let infcx = selcx.infcx();
 
@@ -579,7 +587,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                                                     projection_ty);
             selcx.infcx().report_overflow_error(&obligation, false);
         }
-        Err(ProjectionCacheEntry::NormalizedTy(mut ty)) => {
+        Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
+            // This is the hottest path in this function.
+            //
             // If we find the value in the cache, then return it along
             // with the obligations that went along with it. Note
             // that, when using a fulfillment context, these
@@ -596,29 +606,32 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             // Once we have inferred everything we need to know, we
             // can ignore the `obligations` from that point on.
             if !infcx.any_unresolved_type_vars(&ty.value) {
-                infcx.projection_cache.borrow_mut().complete(cache_key);
-                ty.obligations = vec![];
+                infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty);
+                // No need to extend `obligations`.
+            } else {
+                obligations.extend(ty.obligations);
             }
 
-            push_paranoid_cache_value_obligation(infcx,
-                                                 param_env,
-                                                 projection_ty,
-                                                 cause,
-                                                 depth,
-                                                 &mut ty);
-
-            return Some(ty);
+            obligations.push(get_paranoid_cache_value_obligation(infcx,
+                                                                 param_env,
+                                                                 projection_ty,
+                                                                 cause,
+                                                                 depth));
+            return Some(ty.value);
         }
         Err(ProjectionCacheEntry::Error) => {
             debug!("opt_normalize_projection_type: \
                     found error");
-            return Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth));
+            let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+            obligations.extend(result.obligations);
+            return Some(result.value)
         }
     }
 
     let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
     match project_type(selcx, &obligation) {
-        Ok(ProjectedTy::Progress(Progress { ty: projected_ty, mut obligations })) => {
+        Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
+                                            obligations: mut projected_obligations })) => {
             // if projection succeeded, then what we get out of this
             // is also non-normalized (consider: it was derived from
             // an impl, where-clause etc) and hence we must
@@ -627,10 +640,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             debug!("opt_normalize_projection_type: \
                     projected_ty={:?} \
                     depth={} \
-                    obligations={:?}",
+                    projected_obligations={:?}",
                    projected_ty,
                    depth,
-                   obligations);
+                   projected_obligations);
 
             let result = if projected_ty.has_projections() {
                 let mut normalizer = AssociatedTypeNormalizer::new(selcx,
@@ -644,22 +657,22 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                        normalized_ty,
                        depth);
 
-                obligations.extend(normalizer.obligations);
+                projected_obligations.extend(normalizer.obligations);
                 Normalized {
                     value: normalized_ty,
-                    obligations,
+                    obligations: projected_obligations,
                 }
             } else {
                 Normalized {
                     value: projected_ty,
-                    obligations,
+                    obligations: projected_obligations,
                 }
             };
 
             let cache_value = prune_cache_value_obligations(infcx, &result);
             infcx.projection_cache.borrow_mut().insert_ty(cache_key, cache_value);
-
-            Some(result)
+            obligations.extend(result.obligations);
+            Some(result.value)
         }
         Ok(ProjectedTy::NoProgress(projected_ty)) => {
             debug!("opt_normalize_projection_type: \
@@ -670,7 +683,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                 obligations: vec![]
             };
             infcx.projection_cache.borrow_mut().insert_ty(cache_key, result.clone());
-            Some(result)
+            // No need to extend `obligations`.
+            Some(result.value)
         }
         Err(ProjectionTyError::TooManyCandidates) => {
             debug!("opt_normalize_projection_type: \
@@ -688,7 +702,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
 
             infcx.projection_cache.borrow_mut()
                                   .error(cache_key);
-            Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth))
+            let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+            obligations.extend(result.obligations);
+            Some(result.value)
         }
     }
 }
@@ -737,7 +753,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
 /// may or may not be necessary -- in principle, all the obligations
 /// that must be proven to show that `T: Trait` were also returned
 /// when the cache was first populated. But there are some vague concerns,
-/// and so we take the precatuionary measure of including `T: Trait` in
+/// and so we take the precautionary measure of including `T: Trait` in
 /// the result:
 ///
 /// Concern #1. The current setup is fragile. Perhaps someone could
@@ -754,19 +770,21 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
 /// that may yet turn out to be wrong.  This *may* lead to some sort
 /// of trouble, though we don't have a concrete example of how that
 /// can occur yet.  But it seems risky at best.
-fn push_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                                                        param_env: ty::ParamEnv<'tcx>,
-                                                        projection_ty: ty::ProjectionTy<'tcx>,
-                                                        cause: ObligationCause<'tcx>,
-                                                        depth: usize,
-                                                        result: &mut NormalizedTy<'tcx>)
+fn get_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>(
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    projection_ty: ty::ProjectionTy<'tcx>,
+    cause: ObligationCause<'tcx>,
+    depth: usize)
+    -> PredicateObligation<'tcx>
 {
     let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
-    let trait_obligation = Obligation { cause,
-                                        recursion_depth: depth,
-                                        param_env,
-                                        predicate: trait_ref.to_predicate() };
-    result.obligations.push(trait_obligation);
+    Obligation {
+        cause,
+        recursion_depth: depth,
+        param_env,
+        predicate: trait_ref.to_predicate(),
+    }
 }
 
 /// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
@@ -1682,6 +1700,23 @@ impl<'tcx> ProjectionCache<'tcx> {
         }));
     }
 
+    /// A specialized version of `complete` for when the key's value is known
+    /// to be a NormalizedTy.
+    pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) {
+        // We want to insert `ty` with no obligations. If the existing value
+        // already has no obligations (as is common) we can use `insert_noop`
+        // to do a minimal amount of work -- the HashMap insertion is skipped,
+        // and minimal changes are made to the undo log.
+        if ty.obligations.is_empty() {
+            self.map.insert_noop();
+        } else {
+            self.map.insert(key, ProjectionCacheEntry::NormalizedTy(Normalized {
+                value: ty.value,
+                obligations: vec![]
+            }));
+        }
+    }
+
     /// Indicates that trying to normalize `key` resulted in
     /// ambiguity. No point in trying it again then until we gain more
     /// type information (in which case, the "fully resolved" key will
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 4493c668593..0b8f10d311d 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -19,7 +19,7 @@ use ty::subst::{Substs, Subst, Kind, UnpackedKind};
 use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
 use ty::{Slice, TyS};
 use util::captures::Captures;
-use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};
+use mir::interpret::{PrimVal, MemoryPointer, Value, ConstValue};
 
 use std::iter;
 use std::cmp::Ordering;
@@ -1768,15 +1768,6 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn from_alloc(
-        tcx: TyCtxt<'_, '_, 'tcx>,
-        alloc: &'tcx Allocation,
-        ty: Ty<'tcx>,
-    ) -> &'tcx Self {
-        Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty)
-    }
-
-    #[inline]
     pub fn from_byval_value(
         tcx: TyCtxt<'_, '_, 'tcx>,
         val: Value,
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index d5532f8f835..7cfcbcb86af 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -15,10 +15,8 @@ use hir::def_id::DefId;
 use hir::map::{DefPathData, Node};
 use hir;
 use ich::NodeIdHashingMode;
-use middle::const_val::ConstVal;
 use traits::{self, ObligationCause};
 use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
-use ty::fold::TypeVisitor;
 use ty::subst::{Substs, UnpackedKind};
 use ty::maps::TyCtxtAt;
 use ty::TypeVariants::*;
@@ -26,12 +24,9 @@ use ty::layout::{Integer, IntegerExt};
 use util::common::ErrorReported;
 use middle::lang_items;
 
-use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
-                                           HashStable};
+use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use rustc_data_structures::fx::FxHashMap;
 use std::{cmp, fmt};
-use std::hash::Hash;
-use std::intrinsics;
 use syntax::ast;
 use syntax::attr::{self, SignedInt, UnsignedInt};
 use syntax_pos::{Span, DUMMY_SP};
@@ -615,150 +610,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> {
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    state: StableHasher<W>,
-}
-
-impl<'a, 'gcx, 'tcx, W> TypeIdHasher<'a, 'gcx, 'tcx, W>
-    where W: StableHasherResult
-{
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
-        TypeIdHasher { tcx: tcx, state: StableHasher::new() }
-    }
-
-    pub fn finish(self) -> W {
-        self.state.finish()
-    }
-
-    pub fn hash<T: Hash>(&mut self, x: T) {
-        x.hash(&mut self.state);
-    }
-
-    fn hash_discriminant_u8<T>(&mut self, x: &T) {
-        let v = unsafe {
-            intrinsics::discriminant_value(x)
-        };
-        let b = v as u8;
-        assert_eq!(v, b as u64);
-        self.hash(b)
-    }
-
-    fn def_id(&mut self, did: DefId) {
-        // Hash the DefPath corresponding to the DefId, which is independent
-        // of compiler internal state. We already have a stable hash value of
-        // all DefPaths available via tcx.def_path_hash(), so we just feed that
-        // into the hasher.
-        let hash = self.tcx.def_path_hash(did);
-        self.hash(hash);
-    }
-}
-
-impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
-    where W: StableHasherResult
-{
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
-        // Distinguish between the Ty variants uniformly.
-        self.hash_discriminant_u8(&ty.sty);
-
-        match ty.sty {
-            TyInt(i) => self.hash(i),
-            TyUint(u) => self.hash(u),
-            TyFloat(f) => self.hash(f),
-            TyArray(_, n) => {
-                self.hash_discriminant_u8(&n.val);
-                match n.val {
-                    ConstVal::Value(alloc) => self.hash(alloc),
-                    ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
-                }
-            }
-            TyRawPtr(m) => self.hash(m.mutbl),
-            TyRef(_, _, mutbl) => self.hash(mutbl),
-            TyClosure(def_id, _) |
-            TyGenerator(def_id, _, _) |
-            TyAnon(def_id, _) |
-            TyFnDef(def_id, _) => self.def_id(def_id),
-            TyAdt(d, _) => self.def_id(d.did),
-            TyForeign(def_id) => self.def_id(def_id),
-            TyFnPtr(f) => {
-                self.hash(f.unsafety());
-                self.hash(f.abi());
-                self.hash(f.variadic());
-                self.hash(f.inputs().skip_binder().len());
-            }
-            TyDynamic(ref data, ..) => {
-                if let Some(p) = data.principal() {
-                    self.def_id(p.def_id());
-                }
-                for d in data.auto_traits() {
-                    self.def_id(d);
-                }
-            }
-            TyGeneratorWitness(tys) => {
-                self.hash(tys.skip_binder().len());
-            }
-            TyTuple(tys) => {
-                self.hash(tys.len());
-            }
-            TyParam(p) => {
-                self.hash(p.idx);
-                self.hash(p.name);
-            }
-            TyProjection(ref data) => {
-                self.def_id(data.item_def_id);
-            }
-            TyNever |
-            TyBool |
-            TyChar |
-            TyStr |
-            TySlice(_) => {}
-
-            TyError |
-            TyInfer(_) => bug!("TypeIdHasher: unexpected type {}", ty)
-        }
-
-        ty.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-        self.hash_discriminant_u8(r);
-        match *r {
-            ty::ReErased |
-            ty::ReStatic |
-            ty::ReEmpty => {
-                // No variant fields to hash for these ...
-            }
-            ty::ReCanonical(c) => {
-                self.hash(c);
-            }
-            ty::ReLateBound(db, ty::BrAnon(i)) => {
-                self.hash(db.depth);
-                self.hash(i);
-            }
-            ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
-                self.def_id(def_id);
-            }
-
-            ty::ReClosureBound(..) |
-            ty::ReLateBound(..) |
-            ty::ReFree(..) |
-            ty::ReScope(..) |
-            ty::ReVar(..) |
-            ty::ReSkolemized(..) => {
-                bug!("TypeIdHasher: unexpected region {:?}", r)
-            }
-        }
-        false
-    }
-
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, x: &ty::Binder<T>) -> bool {
-        // Anonymize late-bound regions so that, for example:
-        // `for<'a, b> fn(&'a &'b T)` and `for<'a, b> fn(&'b &'a T)`
-        // result in the same TypeId (the two types are equivalent).
-        self.tcx.anonymize_late_bound_regions(x).super_visit_with(self)
-    }
-}
-
 impl<'a, 'tcx> ty::TyS<'tcx> {
     pub fn moves_by_default(&'tcx self,
                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index de8814d3d6a..497d5fdcac7 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -21,7 +21,7 @@ use syntax::ext::base::ExtCtxt;
 use syntax::ext::base::Resolver;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
-use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::ext::hygiene::{self, Mark, SyntaxContext};
 use syntax::fold::{self, Folder};
 use syntax::parse::ParseSess;
 use syntax::ptr::P;
@@ -86,6 +86,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
                 span: None,
                 allow_internal_unstable: true,
                 allow_internal_unsafe: false,
+                edition: hygiene::default_edition(),
             },
         });
         let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 25c598c532c..221012903d9 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -127,8 +127,12 @@ impl LlvmType for Reg {
 impl LlvmType for CastTarget {
     fn llvm_type(&self, cx: &CodegenCx) -> Type {
         let rest_ll_unit = self.rest.unit.llvm_type(cx);
-        let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes();
-        let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes();
+        let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
+            (0, 0)
+        } else {
+            (self.rest.total.bytes() / self.rest.unit.size.bytes(),
+            self.rest.total.bytes() % self.rest.unit.size.bytes())
+        };
 
         if self.prefix.iter().all(|x| x.is_none()) {
             // Simplify to a single unit when there is no prefix and size <= unit size
diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs
index dbfd430a3e2..735c4d2f76f 100644
--- a/src/librustc_codegen_llvm/back/link.rs
+++ b/src/librustc_codegen_llvm/back/link.rs
@@ -625,11 +625,6 @@ fn link_natively(sess: &Session,
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
         cmd.args(args);
     }
-    if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
-        if sess.crt_static() {
-            cmd.args(args);
-        }
-    }
     if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
         cmd.args(args);
     }
@@ -644,18 +639,6 @@ fn link_natively(sess: &Session,
         cmd.arg(root.join(obj));
     }
 
-    if crate_type == config::CrateTypeExecutable && sess.crt_static() {
-        for obj in &sess.target.target.options.pre_link_objects_exe_crt {
-            cmd.arg(root.join(obj));
-        }
-
-        for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys {
-            if flavor == LinkerFlavor::Gcc {
-                cmd.arg(format!("-l:{}", obj));
-            }
-        }
-    }
-
     if sess.target.target.options.is_like_emscripten {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
@@ -677,16 +660,6 @@ fn link_natively(sess: &Session,
     for obj in &sess.target.target.options.post_link_objects {
         cmd.arg(root.join(obj));
     }
-    if sess.crt_static() {
-        for obj in &sess.target.target.options.post_link_objects_crt_sys {
-            if flavor == LinkerFlavor::Gcc {
-                cmd.arg(format!("-l:{}", obj));
-            }
-        }
-        for obj in &sess.target.target.options.post_link_objects_crt {
-            cmd.arg(root.join(obj));
-        }
-    }
     if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
         cmd.args(args);
     }
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index ee60711c11d..ae0f6067f47 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -23,12 +23,11 @@ use llvm::{self, ValueRef};
 use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
                       DICompositeType, DILexicalBlock, DIFlags};
 
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::def::CtorKind;
 use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
-use rustc::ty::fold::TypeVisitor;
-use rustc::ty::util::TypeIdHasher;
-use rustc::ich::Fingerprint;
+use rustc::ich::{Fingerprint, NodeIdHashingMode};
 use rustc::ty::Instance;
 use common::CodegenCx;
 use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
@@ -144,9 +143,15 @@ impl<'tcx> TypeMap<'tcx> {
 
         // The hasher we are using to generate the UniqueTypeId. We want
         // something that provides more than the 64 bits of the DefaultHasher.
-        let mut type_id_hasher = TypeIdHasher::<Fingerprint>::new(cx.tcx);
-        type_id_hasher.visit_ty(type_);
-        let unique_type_id = type_id_hasher.finish().to_hex();
+        let mut hasher = StableHasher::<Fingerprint>::new();
+        let mut hcx = cx.tcx.create_stable_hashing_context();
+        let type_ = cx.tcx.erase_regions(&type_);
+        hcx.while_hashing_spans(false, |hcx| {
+            hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+                type_.hash_stable(hcx, &mut hasher);
+            });
+        });
+        let unique_type_id = hasher.finish().to_hex();
 
         let key = self.unique_id_interner.intern(&unique_type_id);
         self.type_to_unique_id.insert(type_, UniqueTypeId(key));
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index ba04cc7fad5..cffe7f79e97 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -389,18 +389,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
             args[0].deref(bx.cx).codegen_get_discr(bx, ret_ty)
         }
 
-        "align_offset" => {
-            // `ptr as usize`
-            let ptr_val = bx.ptrtoint(args[0].immediate(), bx.cx.isize_ty);
-            // `ptr_val % align`
-            let align = args[1].immediate();
-            let offset = bx.urem(ptr_val, align);
-            let zero = C_null(bx.cx.isize_ty);
-            // `offset == 0`
-            let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero);
-            // `if offset == 0 { 0 } else { align - offset }`
-            bx.select(is_zero, zero, bx.sub(align, offset))
-        }
         name if name.starts_with("simd_") => {
             match generic_simd_intrinsic(bx, name,
                                          callee_ty,
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index bd053da4bd3..0b0bab96dfd 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -29,7 +29,6 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(optin_builtin_traits)]
-#![feature(inclusive_range_methods)]
 
 use rustc::dep_graph::WorkProduct;
 use syntax_pos::symbol::Symbol;
diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs
index c2638d2d410..36c1d335ec4 100644
--- a/src/librustc_codegen_llvm/mir/constant.rs
+++ b/src/librustc_codegen_llvm/mir/constant.rs
@@ -16,7 +16,7 @@ use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue};
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
+use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar, Size};
 use builder::Builder;
 use common::{CodegenCx};
 use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
@@ -68,7 +68,7 @@ pub fn primval_to_llvm(cx: &CodegenCx,
 
                 let llval = unsafe { llvm::LLVMConstInBoundsGEP(
                     consts::bitcast(base_addr, Type::i8p(cx)),
-                    &C_usize(cx, ptr.offset),
+                    &C_usize(cx, ptr.offset.bytes()),
                     1,
                 ) };
                 if scalar.value != layout::Pointer {
@@ -81,49 +81,6 @@ pub fn primval_to_llvm(cx: &CodegenCx,
     }
 }
 
-fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef {
-    let layout = cx.layout_of(ty);
-
-    if layout.is_zst() {
-        return C_undef(layout.immediate_llvm_type(cx));
-    }
-
-    match val {
-        ConstValue::ByVal(x) => {
-            let scalar = match layout.abi {
-                layout::Abi::Scalar(ref x) => x,
-                _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout)
-            };
-            primval_to_llvm(
-                cx,
-                x,
-                scalar,
-                layout.immediate_llvm_type(cx),
-            )
-        },
-        ConstValue::ByValPair(a, b) => {
-            let (a_scalar, b_scalar) = match layout.abi {
-                layout::Abi::ScalarPair(ref a, ref b) => (a, b),
-                _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout)
-            };
-            let a_llval = primval_to_llvm(
-                cx,
-                a,
-                a_scalar,
-                layout.scalar_pair_element_llvm_type(cx, 0),
-            );
-            let b_llval = primval_to_llvm(
-                cx,
-                b,
-                b_scalar,
-                layout.scalar_pair_element_llvm_type(cx, 1),
-            );
-            C_struct(cx, &[a_llval, b_llval], false)
-        },
-        ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc),
-    }
-}
-
 pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
     let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
     let layout = cx.data_layout();
@@ -131,6 +88,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
 
     let mut next_offset = 0;
     for (&offset, &alloc_id) in &alloc.relocations {
+        let offset = offset.bytes();
         assert_eq!(offset as usize as u64, offset);
         let offset = offset as usize;
         if offset > next_offset {
@@ -142,7 +100,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
         ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
         llvals.push(primval_to_llvm(
             cx,
-            PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
+            PrimVal::Ptr(MemoryPointer { alloc_id, offset: Size::from_bytes(ptr_offset) }),
             &Scalar {
                 value: layout::Primitive::Pointer,
                 valid_range: 0..=!0
@@ -171,11 +129,11 @@ pub fn codegen_static_initializer<'a, 'tcx>(
     let param_env = ty::ParamEnv::reveal_all();
     let static_ = cx.tcx.const_eval(param_env.and(cid))?;
 
-    let val = match static_.val {
-        ConstVal::Value(val) => val,
+    let alloc = match static_.val {
+        ConstVal::Value(ConstValue::ByRef(alloc, n)) if n.bytes() == 0 => alloc,
         _ => bug!("static const eval returned {:#?}", static_),
     };
-    Ok(const_value_to_llvm(cx, val, static_.ty))
+    Ok(const_alloc_to_llvm(cx, alloc))
 }
 
 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs
index 62ef58f8255..91e39373334 100644
--- a/src/librustc_codegen_llvm/mir/operand.rs
+++ b/src/librustc_codegen_llvm/mir/operand.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::ValueRef;
+use llvm::{ValueRef, LLVMConstInBoundsGEP};
 use rustc::middle::const_val::ConstEvalErr;
 use rustc::mir;
 use rustc::mir::interpret::ConstValue;
@@ -137,9 +137,15 @@ impl<'a, 'tcx> OperandRef<'tcx> {
                 );
                 OperandValue::Pair(a_llval, b_llval)
             },
-            ConstValue::ByRef(alloc) => {
+            ConstValue::ByRef(alloc, offset) => {
                 let init = const_alloc_to_llvm(bx.cx, alloc);
-                let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str");
+                let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
+
+                let llval = unsafe { LLVMConstInBoundsGEP(
+                    consts::bitcast(base_addr, Type::i8p(bx.cx)),
+                    &C_usize(bx.cx, offset.bytes()),
+                    1,
+                )};
                 let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
                 return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
             },
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 5f186e7514e..21436b74731 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -10,6 +10,7 @@
 
 use abi::{FnType, FnTypeExt};
 use common::*;
+use llvm;
 use rustc::hir;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout};
@@ -428,8 +429,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
                         PointerKind::Shared
                     },
                     hir::MutMutable => {
-                        if cx.tcx.sess.opts.debugging_opts.mutable_noalias ||
-                           cx.tcx.sess.panic_strategy() == PanicStrategy::Abort {
+                        // Only emit noalias annotations for LLVM >= 6 or in panic=abort
+                        // mode, as prior versions had many bugs in conjunction with
+                        // unwinding. See also issue #31681.
+                        let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias
+                            .unwrap_or(unsafe { llvm::LLVMRustVersionMajor() >= 6 }
+                                || cx.tcx.sess.panic_strategy() == PanicStrategy::Abort);
+                        if mutable_noalias {
                             PointerKind::UniqueBorrowed
                         } else {
                             PointerKind::Shared
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index 1a62f39ae3d..2063db6dc53 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -97,18 +97,19 @@
 //! virtually impossible. Thus, symbol hash generation exclusively relies on
 //! DefPaths which are much more robust in the face of changes to the code base.
 
-use rustc::middle::weak_lang_items;
-use rustc_mir::monomorphize::Instance;
-use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode};
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::fold::TypeVisitor;
+use rustc::hir::map::definitions::DefPathData;
+use rustc::ich::NodeIdHashingMode;
+use rustc::middle::weak_lang_items;
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::ty::maps::Providers;
 use rustc::ty::subst::Substs;
-use rustc::hir::map::definitions::DefPathData;
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::util::common::record_time;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
+use rustc_mir::monomorphize::Instance;
 
 use syntax::attr;
 use syntax_pos::symbol::Symbol;
@@ -124,51 +125,60 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn get_symbol_hash<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
-                             // the DefId of the item this name is for
-                             def_id: DefId,
+    // the DefId of the item this name is for
+    def_id: DefId,
 
-                             // instance this name will be for
-                             instance: Instance<'tcx>,
+    // instance this name will be for
+    instance: Instance<'tcx>,
 
-                             // type of the item, without any generic
-                             // parameters substituted; this is
-                             // included in the hash as a kind of
-                             // safeguard.
-                             item_type: Ty<'tcx>,
+    // type of the item, without any generic
+    // parameters substituted; this is
+    // included in the hash as a kind of
+    // safeguard.
+    item_type: Ty<'tcx>,
 
-                             // values for generic type parameters,
-                             // if any.
-                             substs: &'tcx Substs<'tcx>)
-                             -> u64 {
-    debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
+    // values for generic type parameters,
+    // if any.
+    substs: &'tcx Substs<'tcx>,
+) -> u64 {
+    debug!(
+        "get_symbol_hash(def_id={:?}, parameters={:?})",
+        def_id, substs
+    );
 
-    let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
+    let mut hasher = StableHasher::<u64>::new();
+    let mut hcx = tcx.create_stable_hashing_context();
 
     record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
         // the main symbol name is not necessarily unique; hash in the
         // compiler's internal def-path, guaranteeing each symbol has a
         // truly unique path
-        hasher.hash(tcx.def_path_hash(def_id));
+        tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
 
         // Include the main item-type. Note that, in this case, the
         // assertions about `needs_subst` may not hold, but this item-type
         // ought to be the same for every reference anyway.
         assert!(!item_type.has_erasable_regions());
-        hasher.visit_ty(item_type);
+        hcx.while_hashing_spans(false, |hcx| {
+            hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+                item_type.hash_stable(hcx, &mut hasher);
+            });
+        });
 
         // If this is a function, we hash the signature as well.
         // This is not *strictly* needed, but it may help in some
         // situations, see the `run-make/a-b-a-linker-guard` test.
         if let ty::TyFnDef(..) = item_type.sty {
-            item_type.fn_sig(tcx).visit_with(&mut hasher);
+            item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher);
         }
 
         // also include any type parameters (for generic items)
         assert!(!substs.has_erasable_regions());
         assert!(!substs.needs_subst());
-        substs.visit_with(&mut hasher);
+        substs.hash_stable(&mut hcx, &mut hasher);
 
         let is_generic = substs.types().next().is_some();
         let avoid_cross_crate_conflicts =
@@ -194,12 +204,11 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 if !def_id.is_local() && tcx.share_generics() {
                     // If we are re-using a monomorphization from another crate,
                     // we have to compute the symbol hash accordingly.
-                    let upstream_monomorphizations =
-                        tcx.upstream_monomorphizations_for(def_id);
+                    let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
 
-                    upstream_monomorphizations.and_then(|monos| monos.get(&substs)
-                                                                     .cloned())
-                                              .unwrap_or(LOCAL_CRATE)
+                    upstream_monomorphizations
+                        .and_then(|monos| monos.get(&substs).cloned())
+                        .unwrap_or(LOCAL_CRATE)
                 } else {
                     LOCAL_CRATE
                 }
@@ -207,8 +216,9 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 LOCAL_CRATE
             };
 
-            hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]);
-            hasher.hash(&tcx.crate_disambiguator(instantiating_crate));
+            (&tcx.original_crate_name(instantiating_crate).as_str()[..])
+                .hash_stable(&mut hcx, &mut hasher);
+            (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher);
         }
     });
 
@@ -216,9 +226,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     hasher.finish()
 }
 
-fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                             -> ty::SymbolName
-{
+fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName {
     let mut buffer = SymbolPathBuffer::new();
     item_path::with_forced_absolute_paths(|| {
         tcx.push_item_path(&mut buffer, def_id);
@@ -226,20 +234,17 @@ fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     buffer.into_interned()
 }
 
-fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
-                         -> ty::SymbolName
-{
-    ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str() }
+fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
+    ty::SymbolName {
+        name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str(),
+    }
 }
 
-fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
-    -> String
-{
+fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> String {
     let def_id = instance.def_id();
     let substs = instance.substs;
 
-    debug!("symbol_name(def_id={:?}, substs={:?})",
-           def_id, substs);
+    debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs);
 
     let node_id = tcx.hir.as_local_node_id(def_id);
 
@@ -259,7 +264,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
     let is_foreign = if let Some(id) = node_id {
         match tcx.hir.get(id) {
             hir_map::NodeForeignItem(_) => true,
-            _ => false
+            _ => false,
         }
     } else {
         tcx.is_foreign_item(def_id)
@@ -296,8 +301,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
     loop {
         let key = tcx.def_key(ty_def_id);
         match key.disambiguated_data.data {
-            DefPathData::TypeNs(_) |
-            DefPathData::ValueNs(_) => {
+            DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => {
                 instance_ty = tcx.type_of(ty_def_id);
                 break;
             }
@@ -306,8 +310,12 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
                 // to be a value or type-def or something in there
                 // *somewhere*
                 ty_def_id.index = key.parent.unwrap_or_else(|| {
-                    bug!("finding type for {:?}, encountered def-id {:?} with no \
-                          parent", def_id, ty_def_id);
+                    bug!(
+                        "finding type for {:?}, encountered def-id {:?} with no \
+                         parent",
+                        def_id,
+                        ty_def_id
+                    );
                 });
             }
         }
@@ -337,14 +345,14 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
 // use C++ name-mangling.
 struct SymbolPathBuffer {
     result: String,
-    temp_buf: String
+    temp_buf: String,
 }
 
 impl SymbolPathBuffer {
     fn new() -> Self {
         let mut result = SymbolPathBuffer {
             result: String::with_capacity(64),
-            temp_buf: String::with_capacity(16)
+            temp_buf: String::with_capacity(16),
         };
         result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
         result
@@ -353,14 +361,16 @@ impl SymbolPathBuffer {
     fn from_interned(symbol: ty::SymbolName) -> Self {
         let mut result = SymbolPathBuffer {
             result: String::with_capacity(64),
-            temp_buf: String::with_capacity(16)
+            temp_buf: String::with_capacity(16),
         };
         result.result.push_str(&symbol.name.as_str());
         result
     }
 
     fn into_interned(self) -> ty::SymbolName {
-        ty::SymbolName { name: Symbol::intern(&self.result).as_interned_str() }
+        ty::SymbolName {
+            name: Symbol::intern(&self.result).as_interned_str(),
+        }
     }
 
     fn finish(mut self, hash: u64) -> String {
@@ -379,7 +389,11 @@ impl ItemPathBuffer for SymbolPathBuffer {
     fn push(&mut self, text: &str) {
         self.temp_buf.clear();
         let need_underscore = sanitize(&mut self.temp_buf, text);
-        let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
+        let _ = write!(
+            self.result,
+            "{}",
+            self.temp_buf.len() + (need_underscore as usize)
+        );
         if need_underscore {
             self.result.push('_');
         }
@@ -410,16 +424,13 @@ pub fn sanitize(result: &mut String, s: &str) -> bool {
             '-' | ':' => result.push('.'),
 
             // These are legal symbols
-            'a' ... 'z'
-            | 'A' ... 'Z'
-            | '0' ... '9'
-            | '_' | '.' | '$' => result.push(c),
+            'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | '.' | '$' => result.push(c),
 
             _ => {
                 result.push('$');
                 for c in c.escape_unicode().skip(1) {
                     match c {
-                        '{' => {},
+                        '{' => {}
                         '}' => result.push('$'),
                         c => result.push(c),
                     }
@@ -429,7 +440,6 @@ pub fn sanitize(result: &mut String, s: &str) -> bool {
     }
 
     // Underscore-qualify anything that didn't start as an ident.
-    !result.is_empty() &&
-        result.as_bytes()[0] != '_' as u8 &&
-        ! (result.as_bytes()[0] as char).is_xid_start()
+    !result.is_empty() && result.as_bytes()[0] != '_' as u8
+        && !(result.as_bytes()[0] as char).is_xid_start()
 }
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 6f1cbcad2f4..bb1fb84a0ce 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ path = "lib.rs"
 crate-type = ["dylib"]
 
 [dependencies]
-ena = "0.9.1"
+ena = "0.9.3"
 log = "0.4"
 rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
 serialize = { path = "../libserialize" }
diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs
index 28e3180063c..a22dd1fecec 100644
--- a/src/librustc_data_structures/bitvec.rs
+++ b/src/librustc_data_structures/bitvec.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::collections::BTreeMap;
+use indexed_vec::{Idx, IndexVec};
 use std::collections::btree_map::Entry;
-use std::marker::PhantomData;
+use std::collections::BTreeMap;
 use std::iter::FromIterator;
-use indexed_vec::{Idx, IndexVec};
+use std::marker::PhantomData;
 
 type Word = u128;
 const WORD_BITS: usize = 128;
@@ -317,14 +317,25 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
         if read != write {
             let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write);
 
-            for read_val in bit_set_read.iter() {
-                changed = changed | bit_set_write.insert(read_val);
+            for read_chunk in bit_set_read.chunks() {
+                changed = changed | bit_set_write.insert_chunk(read_chunk).any();
             }
         }
 
         changed
     }
 
+    /// True if `sub` is a subset of `sup`
+    pub fn is_subset(&self, sub: R, sup: R) -> bool {
+        sub == sup || {
+            let bit_set_sub = &self.vector[sub];
+            let bit_set_sup = &self.vector[sup];
+            bit_set_sub
+                .chunks()
+                .all(|read_chunk| read_chunk.bits_eq(bit_set_sup.contains_chunk(read_chunk)))
+        }
+    }
+
     /// Iterates through all the columns set to true in a given row of
     /// the matrix.
     pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
@@ -346,6 +357,7 @@ pub struct SparseChunk<I> {
 }
 
 impl<I: Idx> SparseChunk<I> {
+    #[inline]
     pub fn one(index: I) -> Self {
         let index = index.index();
         let key_usize = index / 128;
@@ -358,10 +370,16 @@ impl<I: Idx> SparseChunk<I> {
         }
     }
 
+    #[inline]
     pub fn any(&self) -> bool {
         self.bits != 0
     }
 
+    #[inline]
+    pub fn bits_eq(&self, other: SparseChunk<I>) -> bool {
+        self.bits == other.bits
+    }
+
     pub fn iter(&self) -> impl Iterator<Item = I> {
         let base = self.key as usize * 128;
         let mut bits = self.bits;
@@ -394,6 +412,10 @@ impl<I: Idx> SparseBitSet<I> {
         self.chunk_bits.len() * 128
     }
 
+    /// Returns a chunk containing only those bits that are already
+    /// present. You can test therefore if `self` contains all the
+    /// bits in chunk already by doing `chunk ==
+    /// self.contains_chunk(chunk)`.
     pub fn contains_chunk(&self, chunk: SparseChunk<I>) -> SparseChunk<I> {
         SparseChunk {
             bits: self.chunk_bits
@@ -403,6 +425,11 @@ impl<I: Idx> SparseBitSet<I> {
         }
     }
 
+    /// Modifies `self` to contain all the bits from `chunk` (in
+    /// addition to any pre-existing bits); returns a new chunk that
+    /// contains only those bits that were newly added. You can test
+    /// if anything was inserted by invoking `any()` on the returned
+    /// value.
     pub fn insert_chunk(&mut self, chunk: SparseChunk<I>) -> SparseChunk<I> {
         if chunk.bits == 0 {
             return chunk;
diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs
index cede6f14782..6ee8c3579f5 100644
--- a/src/librustc_data_structures/snapshot_map/mod.rs
+++ b/src/librustc_data_structures/snapshot_map/mod.rs
@@ -67,6 +67,12 @@ impl<K, V> SnapshotMap<K, V>
         }
     }
 
+    pub fn insert_noop(&mut self) {
+        if !self.undo_log.is_empty() {
+            self.undo_log.push(UndoLog::Noop);
+        }
+    }
+
     pub fn remove(&mut self, key: K) -> bool {
         match self.map.remove(&key) {
             Some(old_value) => {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 0b4b090f1f0..2f89814032e 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -108,7 +108,7 @@ use syntax::ast;
 use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
-use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
+use syntax_pos::{hygiene, DUMMY_SP, MultiSpan, FileName};
 
 #[cfg(test)]
 mod test;
@@ -466,6 +466,7 @@ pub fn run_compiler<'a>(args: &[String],
         };
 
         let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+        hygiene::set_default_edition(sopts.edition);
 
         driver::spawn_thread_pool(sopts, |sopts| {
             run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 0ae133640fa..cfd5cf5a0f9 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -177,6 +177,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                     UNUSED_DOC_COMMENT,
                     UNUSED_EXTERN_CRATES,
                     UNUSED_FEATURES,
+                    UNUSED_LABELS,
                     UNUSED_PARENS);
 
     add_lint_group!(sess,
@@ -226,11 +227,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             edition: None,
         },
         FutureIncompatibleInfo {
-            id: LintId::of(LEGACY_IMPORTS),
-            reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
             id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
             reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
             edition: None,
@@ -318,6 +314,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         "converted into hard error, see https://github.com/rust-lang/rust/issues/36892");
     store.register_removed("extra_requirement_in_impl",
         "converted into hard error, see https://github.com/rust-lang/rust/issues/37166");
+    store.register_removed("legacy_imports",
+        "converted into hard error, see https://github.com/rust-lang/rust/issues/38260");
     store.register_removed("coerce_never",
         "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
     store.register_removed("resolve_trait_on_defaulted_unit",
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 87b3a2dc69f..6c1f72f5f9c 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -35,6 +35,7 @@ use std::{cmp, fs};
 
 use syntax::ast;
 use syntax::attr;
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
 use syntax::visit;
@@ -535,7 +536,10 @@ impl<'a> CrateLoader<'a> {
             mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
         };
 
-        struct MyRegistrar(Vec<(ast::Name, Lrc<SyntaxExtension>)>);
+        struct MyRegistrar {
+            extensions: Vec<(ast::Name, Lrc<SyntaxExtension>)>,
+            edition: Edition,
+        }
 
         impl Registry for MyRegistrar {
             fn register_custom_derive(&mut self,
@@ -544,36 +548,38 @@ impl<'a> CrateLoader<'a> {
                                       attributes: &[&'static str]) {
                 let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
                 let derive = ProcMacroDerive::new(expand, attrs.clone());
-                let derive = SyntaxExtension::ProcMacroDerive(Box::new(derive), attrs);
-                self.0.push((Symbol::intern(trait_name), Lrc::new(derive)));
+                let derive = SyntaxExtension::ProcMacroDerive(
+                    Box::new(derive), attrs, self.edition
+                );
+                self.extensions.push((Symbol::intern(trait_name), Lrc::new(derive)));
             }
 
             fn register_attr_proc_macro(&mut self,
                                         name: &str,
                                         expand: fn(TokenStream, TokenStream) -> TokenStream) {
                 let expand = SyntaxExtension::AttrProcMacro(
-                    Box::new(AttrProcMacro { inner: expand })
+                    Box::new(AttrProcMacro { inner: expand }), self.edition
                 );
-                self.0.push((Symbol::intern(name), Lrc::new(expand)));
+                self.extensions.push((Symbol::intern(name), Lrc::new(expand)));
             }
 
             fn register_bang_proc_macro(&mut self,
                                         name: &str,
                                         expand: fn(TokenStream) -> TokenStream) {
                 let expand = SyntaxExtension::ProcMacro(
-                    Box::new(BangProcMacro { inner: expand })
+                    Box::new(BangProcMacro { inner: expand }), self.edition
                 );
-                self.0.push((Symbol::intern(name), Lrc::new(expand)));
+                self.extensions.push((Symbol::intern(name), Lrc::new(expand)));
             }
         }
 
-        let mut my_registrar = MyRegistrar(Vec::new());
+        let mut my_registrar = MyRegistrar { extensions: Vec::new(), edition: root.edition };
         registrar(&mut my_registrar);
 
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long.
         mem::forget(lib);
-        my_registrar.0
+        my_registrar.extensions
     }
 
     /// Look for a plugin registrar. Returns library path, crate
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 9bbce563b61..f2d2d090e0a 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -24,6 +24,7 @@ use rustc::util::nodemap::{FxHashMap, NodeMap};
 
 use rustc_data_structures::sync::{Lrc, RwLock, Lock};
 use syntax::{ast, attr};
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
 use syntax_pos;
@@ -234,4 +235,8 @@ impl CrateMetadata {
     pub fn panic_strategy(&self) -> PanicStrategy {
         self.root.panic_strategy.clone()
     }
+
+    pub fn edition(&self) -> Edition {
+        self.root.edition
+    }
 }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index fdfe2a98bf9..c8f25f935e9 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -38,6 +38,7 @@ use std::sync::Arc;
 use syntax::ast;
 use syntax::attr;
 use syntax::codemap;
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::parse::filemap_to_stream;
 use syntax::symbol::Symbol;
@@ -464,6 +465,11 @@ impl CrateStore for cstore::CStore {
         self.get_crate_data(cnum).hash()
     }
 
+    fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition
+    {
+        self.get_crate_data(cnum).edition()
+    }
+
     /// Returns the `DefKey` for a given `DefId`. This indicates the
     /// parent `DefId` as well as some idea of what kind of data the
     /// `DefId` refers to.
@@ -512,7 +518,8 @@ impl CrateStore for cstore::CStore {
             return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
         } else if data.name == "proc_macro" &&
                   self.get_crate_data(id.krate).item_name(id.index) == "quote" {
-            let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter));
+            let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter),
+                                                 data.edition());
             return LoadedMacro::ProcMacro(Lrc::new(ext));
         }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index bbc4120f060..d00f4f32c10 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -44,7 +44,7 @@ use syntax::ast::{self, CRATE_NODE_ID};
 use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
-use syntax_pos::{self, FileName, FileMap, Span, DUMMY_SP};
+use syntax_pos::{self, hygiene, FileName, FileMap, Span, DUMMY_SP};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -496,6 +496,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hash: link_meta.crate_hash,
             disambiguator: tcx.sess.local_crate_disambiguator(),
             panic_strategy: tcx.sess.panic_strategy(),
+            edition: hygiene::default_edition(),
             has_global_allocator: has_global_allocator,
             has_default_lib_allocator: has_default_lib_allocator,
             plugin_registrar_fn: tcx.sess
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index c9949389ace..8e17b7f8d69 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -23,6 +23,7 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
 
 use rustc_serialize as serialize;
 use syntax::{ast, attr};
+use syntax::edition::Edition;
 use syntax::symbol::Symbol;
 use syntax_pos::{self, Span};
 
@@ -189,6 +190,7 @@ pub struct CrateRoot {
     pub hash: hir::svh::Svh,
     pub disambiguator: CrateDisambiguator,
     pub panic_strategy: PanicStrategy,
+    pub edition: Edition,
     pub has_global_allocator: bool,
     pub has_default_lib_allocator: bool,
     pub plugin_registrar_fn: Option<DefIndex>,
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 1cc69351b47..5d6d4619c5e 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -10,7 +10,7 @@
 
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
-use borrow_check::nll::region_infer::{RegionCausalInfo, RegionInferenceContext};
+use borrow_check::nll::region_infer::RegionInferenceContext;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::definitions::DefPathData;
@@ -248,7 +248,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         nonlexical_regioncx: regioncx,
         used_mut: FxHashSet(),
         used_mut_upvars: SmallVec::new(),
-        nonlexical_cause_info: None,
         borrow_set,
         dominators,
     };
@@ -367,7 +366,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     /// contains the results from region inference and lets us e.g.
     /// find out which CFG points are contained in each borrow region.
     nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
-    nonlexical_cause_info: Option<RegionCausalInfo>,
 
     /// The set of borrows extracted from the MIR
     borrow_set: Rc<BorrowSet<'tcx>>,
@@ -1810,9 +1808,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 }
             }
             Reservation(WriteKind::Move)
+            | Write(WriteKind::Move)
             | Reservation(WriteKind::StorageDeadOrDrop)
             | Reservation(WriteKind::MutableBorrow(BorrowKind::Shared))
-            | Write(WriteKind::Move)
             | Write(WriteKind::StorageDeadOrDrop)
             | Write(WriteKind::MutableBorrow(BorrowKind::Shared)) => {
                 if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
@@ -1851,8 +1849,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     // mutated, then it is justified to be annotated with the `mut`
                     // keyword, since the mutation may be a possible reassignment.
                     let mpi = self.move_data.rev_lookup.find_local(*local);
-                    if flow_state.inits.contains(&mpi) {
-                        self.used_mut.insert(*local);
+                    let ii = &self.move_data.init_path_map[mpi];
+                    for index in ii {
+                        if flow_state.ever_inits.contains(index) {
+                            self.used_mut.insert(*local);
+                        }
                     }
                 }
             }
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index 56e388a5b60..2807a4e8857 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -32,13 +32,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let regioncx = &&self.nonlexical_regioncx;
         let mir = self.mir;
 
-        if self.nonlexical_cause_info.is_none() {
-            self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
-        }
-
-        let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
-        if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
-            match *cause.root_cause() {
+        let borrow_region_vid = regioncx.to_region_vid(borrow.region);
+        if let Some(cause) = regioncx.why_region_contains_point(borrow_region_vid, context.loc) {
+            match cause {
                 Cause::LiveVar(local, location) => {
                     match find_regular_use(mir, regioncx, borrow, location, local) {
                         Some(p) => {
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 0b1729294d8..a162ef36a60 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -240,11 +240,11 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
     });
 
     // Also dump the inference graph constraints as a graphviz file.
-    let _: io::Result<()> = do_catch! {{
+    let _: io::Result<()> = do catch {
         let mut file =
             pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?;
         regioncx.dump_graphviz(&mut file)?;
-    }};
+    };
 }
 
 fn dump_annotation<'a, 'gcx, 'tcx>(
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs b/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
deleted file mode 100644
index f68394d6149..00000000000
--- a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Module defining the `dfs` method on `RegionInferenceContext`, along with
-//! its associated helper traits.
-
-use borrow_check::nll::universal_regions::UniversalRegions;
-use borrow_check::nll::region_infer::RegionInferenceContext;
-use borrow_check::nll::region_infer::values::{RegionElementIndex, RegionValueElements,
-                                              RegionValues};
-use syntax::codemap::Span;
-use rustc::mir::{Location, Mir};
-use rustc::ty::RegionVid;
-use rustc_data_structures::bitvec::BitVector;
-use rustc_data_structures::indexed_vec::Idx;
-
-pub(super) struct DfsStorage {
-    stack: Vec<Location>,
-    visited: BitVector,
-}
-
-impl<'tcx> RegionInferenceContext<'tcx> {
-    /// Creates dfs storage for use by dfs; this should be shared
-    /// across as many calls to dfs as possible to amortize allocation
-    /// costs.
-    pub(super) fn new_dfs_storage(&self) -> DfsStorage {
-        let num_elements = self.elements.num_elements();
-        DfsStorage {
-            stack: vec![],
-            visited: BitVector::new(num_elements),
-        }
-    }
-
-    /// Function used to satisfy or test a `R1: R2 @ P`
-    /// constraint. The core idea is that it performs a DFS starting
-    /// from `P`. The precise actions *during* that DFS depend on the
-    /// `op` supplied, so see (e.g.) `CopyFromSourceToTarget` for more
-    /// details.
-    ///
-    /// Returns:
-    ///
-    /// - `Ok(true)` if the walk was completed and something changed
-    ///   along the way;
-    /// - `Ok(false)` if the walk was completed with no changes;
-    /// - `Err(early)` if the walk was existed early by `op`. `earlyelem` is the
-    ///   value that `op` returned.
-    #[inline(never)] // ensure dfs is identifiable in profiles
-    pub(super) fn dfs<C>(
-        &self,
-        mir: &Mir<'tcx>,
-        dfs: &mut DfsStorage,
-        mut op: C,
-    ) -> Result<bool, C::Early>
-    where
-        C: DfsOp,
-    {
-        let mut changed = false;
-
-        dfs.visited.clear();
-        dfs.stack.push(op.start_point());
-        while let Some(p) = dfs.stack.pop() {
-            let point_index = self.elements.index(p);
-
-            if !op.source_region_contains(point_index) {
-                debug!("            not in from-region");
-                continue;
-            }
-
-            if !dfs.visited.insert(point_index.index()) {
-                debug!("            already visited");
-                continue;
-            }
-
-            let new = op.add_to_target_region(point_index)?;
-            changed |= new;
-
-            let block_data = &mir[p.block];
-
-            let start_stack_len = dfs.stack.len();
-
-            if p.statement_index < block_data.statements.len() {
-                dfs.stack.push(Location {
-                    statement_index: p.statement_index + 1,
-                    ..p
-                });
-            } else {
-                dfs.stack.extend(
-                    block_data
-                        .terminator()
-                        .successors()
-                        .map(|&basic_block| Location {
-                            statement_index: 0,
-                            block: basic_block,
-                        }),
-                );
-            }
-
-            if dfs.stack.len() == start_stack_len {
-                // If we reach the END point in the graph, then copy
-                // over any skolemized end points in the `from_region`
-                // and make sure they are included in the `to_region`.
-                changed |= op.add_universal_regions_outlived_by_source_to_target()?;
-            }
-        }
-
-        Ok(changed)
-    }
-}
-
-/// Customizes the operation of the `dfs` function. This function is
-/// used during inference to satisfy a `R1: R2 @ P` constraint.
-pub(super) trait DfsOp {
-    /// If this op stops the walk early, what type does it propagate?
-    type Early;
-
-    /// Returns the point from which to start the DFS.
-    fn start_point(&self) -> Location;
-
-    /// Returns true if the source region contains the given point.
-    fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool;
-
-    /// Adds the given point to the target region, returning true if
-    /// something has changed. Returns `Err` if we should abort the
-    /// walk early.
-    fn add_to_target_region(
-        &mut self,
-        point_index: RegionElementIndex,
-    ) -> Result<bool, Self::Early>;
-
-    /// Adds all universal regions in the source region to the target region, returning
-    /// true if something has changed.
-    fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, Self::Early>;
-}
-
-/// Used during inference to enforce a `R1: R2 @ P` constraint.  For
-/// each point Q we reach along the DFS, we check if Q is in R2 (the
-/// "source region"). If not, we stop the walk. Otherwise, we add Q to
-/// R1 (the "target region") and continue to Q's successors. If we
-/// reach the end of the graph, then we add any universal regions from
-/// R2 into R1.
-pub(super) struct CopyFromSourceToTarget<'v> {
-    pub source_region: RegionVid,
-    pub target_region: RegionVid,
-    pub inferred_values: &'v mut RegionValues,
-    pub constraint_point: Location,
-    pub constraint_span: Span,
-}
-
-impl<'v> DfsOp for CopyFromSourceToTarget<'v> {
-    /// We never stop the walk early.
-    type Early = !;
-
-    fn start_point(&self) -> Location {
-        self.constraint_point
-    }
-
-    fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
-        self.inferred_values
-            .contains(self.source_region, point_index)
-    }
-
-    fn add_to_target_region(&mut self, point_index: RegionElementIndex) -> Result<bool, !> {
-        Ok(self.inferred_values.add_due_to_outlives(
-            self.source_region,
-            self.target_region,
-            point_index,
-            self.constraint_point,
-            self.constraint_span,
-        ))
-    }
-
-    fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, !> {
-        Ok(self.inferred_values.add_universal_regions_outlived_by(
-            self.source_region,
-            self.target_region,
-            self.constraint_point,
-            self.constraint_span,
-        ))
-    }
-}
-
-/// Used after inference to *test* a `R1: R2 @ P` constraint.  For
-/// each point Q we reach along the DFS, we check if Q in R2 is also
-/// contained in R1. If not, we abort the walk early with an `Err`
-/// condition. Similarly, if we reach the end of the graph and find
-/// that R1 contains some universal region that R2 does not contain,
-/// we abort the walk early.
-pub(super) struct TestTargetOutlivesSource<'v, 'tcx: 'v> {
-    pub source_region: RegionVid,
-    pub target_region: RegionVid,
-    pub elements: &'v RegionValueElements,
-    pub universal_regions: &'v UniversalRegions<'tcx>,
-    pub inferred_values: &'v RegionValues,
-    pub constraint_point: Location,
-}
-
-impl<'v, 'tcx> DfsOp for TestTargetOutlivesSource<'v, 'tcx> {
-    /// The element that was not found within R2.
-    type Early = RegionElementIndex;
-
-    fn start_point(&self) -> Location {
-        self.constraint_point
-    }
-
-    fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
-        self.inferred_values
-            .contains(self.source_region, point_index)
-    }
-
-    fn add_to_target_region(
-        &mut self,
-        point_index: RegionElementIndex,
-    ) -> Result<bool, RegionElementIndex> {
-        if !self.inferred_values
-            .contains(self.target_region, point_index)
-        {
-            return Err(point_index);
-        }
-
-        Ok(false)
-    }
-
-    fn add_universal_regions_outlived_by_source_to_target(
-        &mut self,
-    ) -> Result<bool, RegionElementIndex> {
-        // For all `ur_in_source` in `source_region`.
-        for ur_in_source in self.inferred_values
-            .universal_regions_outlived_by(self.source_region)
-        {
-            // Check that `target_region` outlives `ur_in_source`.
-
-            // If `ur_in_source` is a member of `target_region`, OK.
-            //
-            // (This is implied by the loop below, actually, just an
-            // irresistible micro-opt. Mm. Premature optimization. So
-            // tasty.)
-            if self.inferred_values
-                .contains(self.target_region, ur_in_source)
-            {
-                continue;
-            }
-
-            // If there is some other element X such that `target_region: X` and
-            // `X: ur_in_source`, OK.
-            if self.inferred_values
-                .universal_regions_outlived_by(self.target_region)
-                .any(|ur_in_target| self.universal_regions.outlives(ur_in_target, ur_in_source))
-            {
-                continue;
-            }
-
-            // Otherwise, not known to be true.
-            return Err(self.elements.index(ur_in_source));
-        }
-
-        Ok(false)
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 57b8824191f..5a1ab73b2b8 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -9,16 +9,19 @@
 // except according to those terms.
 
 use super::universal_regions::UniversalRegions;
+use borrow_check::nll::region_infer::values::ToElementIndex;
 use rustc::hir::def_id::DefId;
+use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
+use rustc::infer::region_constraints::{GenericKind, VarInfos};
 use rustc::infer::InferCtxt;
 use rustc::infer::NLLRegionVariableOrigin;
 use rustc::infer::RegionObligation;
 use rustc::infer::RegionVariableOrigin;
 use rustc::infer::SubregionOrigin;
-use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc::infer::region_constraints::{GenericKind, VarInfos};
-use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
-                 Local, Location, Mir};
+use rustc::mir::{
+    ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
+    Mir,
+};
 use rustc::traits::ObligationCause;
 use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
 use rustc::util::common::{self, ErrorReported};
@@ -30,8 +33,6 @@ use syntax::ast;
 use syntax_pos::Span;
 
 mod annotation;
-mod dfs;
-use self::dfs::{CopyFromSourceToTarget, TestTargetOutlivesSource};
 mod dump_mir;
 mod graphviz;
 mod values;
@@ -100,7 +101,7 @@ struct RegionDefinition<'tcx> {
 /// NB: The variants in `Cause` are intentionally ordered. Lower
 /// values are preferred when it comes to error messages. Do not
 /// reorder willy nilly.
-#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
 pub(crate) enum Cause {
     /// point inserted because Local was live at the given Location
     LiveVar(Local, Location),
@@ -114,23 +115,6 @@ pub(crate) enum Cause {
 
     /// part of the initial set of values for a universally quantified region
     UniversalRegion(RegionVid),
-
-    /// Element E was added to R because there was some
-    /// outlives obligation `R: R1 @ P` and `R1` contained `E`.
-    Outlives {
-        /// the reason that R1 had E
-        original_cause: Rc<Cause>,
-
-        /// the point P from the relation
-        constraint_location: Location,
-
-        /// The span indicating why we added the outlives constraint.
-        constraint_span: Span,
-    },
-}
-
-pub(crate) struct RegionCausalInfo {
-    inferred_values: RegionValues,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -325,7 +309,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             // Add all nodes in the CFG to liveness constraints
             for point_index in self.elements.all_point_indices() {
-                self.liveness_constraints.add(
+                self.liveness_constraints.add_element(
                     variable,
                     point_index,
                     &Cause::UniversalRegion(variable),
@@ -333,8 +317,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
 
             // Add `end(X)` into the set for X.
-            self.liveness_constraints
-                .add(variable, variable, &Cause::UniversalRegion(variable));
+            self.liveness_constraints.add_element(
+                variable,
+                variable,
+                &Cause::UniversalRegion(variable),
+            );
         }
     }
 
@@ -383,7 +370,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         debug!("add_live_point: @{:?} Adding cause {:?}", point, cause);
 
         let element = self.elements.index(point);
-        if self.liveness_constraints.add(v, element, &cause) {
+        if self.liveness_constraints.add_element(v, element, &cause) {
             true
         } else {
             false
@@ -438,9 +425,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> Option<ClosureRegionRequirements<'gcx>> {
         assert!(self.inferred_values.is_none(), "values already inferred");
 
-        let dfs_storage = &mut self.new_dfs_storage();
-
-        self.propagate_constraints(mir, dfs_storage);
+        self.propagate_constraints(mir);
 
         // If this is a closure, we can propagate unsatisfied
         // `outlives_requirements` to our creator, so create a vector
@@ -453,13 +438,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             None
         };
 
-        self.check_type_tests(
-            infcx,
-            mir,
-            dfs_storage,
-            mir_def_id,
-            outlives_requirements.as_mut(),
-        );
+        self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());
 
         self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut());
 
@@ -476,31 +455,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
     }
 
-    /// Re-execute the region inference, this time tracking causal information.
-    /// This is significantly slower, so it is done only when an error is being reported.
-    pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo {
-        let dfs_storage = &mut self.new_dfs_storage();
-        let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(true));
-        RegionCausalInfo { inferred_values }
-    }
-
     /// Propagate the region constraints: this will grow the values
     /// for each region variable until all the constraints are
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
-    fn propagate_constraints(&mut self, mir: &Mir<'tcx>, dfs_storage: &mut dfs::DfsStorage) {
+    fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
         self.dependency_map = Some(self.build_dependency_map());
-        let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(false));
+        let inferred_values = self.compute_region_values(mir);
         self.inferred_values = Some(inferred_values);
     }
 
     #[inline(never)] // ensure dfs is identifiable in profiles
-    fn compute_region_values(
-        &self,
-        mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
-        track_causes: TrackCauses,
-    ) -> RegionValues {
+    fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues {
         debug!("compute_region_values()");
         debug!("compute_region_values: constraints={:#?}", {
             let mut constraints: Vec<_> = self.constraints.iter().collect();
@@ -510,7 +476,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         // The initial values for each region are derived from the liveness
         // constraints we have accumulated.
-        let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
+        let mut inferred_values = self.liveness_constraints.duplicate(TrackCauses(false));
 
         let dependency_map = self.dependency_map.as_ref().unwrap();
 
@@ -527,21 +493,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let constraint = &self.constraints[constraint_idx];
             debug!("propagate_constraints: constraint={:?}", constraint);
 
-            // Grow the value as needed to accommodate the
-            // outlives constraint.
-            let Ok(made_changes) = self.dfs(
-                mir,
-                dfs_storage,
-                CopyFromSourceToTarget {
-                    source_region: constraint.sub,
-                    target_region: constraint.sup,
-                    inferred_values: &mut inferred_values,
-                    constraint_point: constraint.point,
-                    constraint_span: constraint.span,
-                },
-            );
-
-            if made_changes {
+            if inferred_values.add_region(constraint.sup, constraint.sub) {
                 debug!("propagate_constraints:   sub={:?}", constraint.sub);
                 debug!("propagate_constraints:   sup={:?}", constraint.sup);
 
@@ -586,7 +538,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
         mir_def_id: DefId,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
     ) {
@@ -595,13 +546,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         for type_test in &self.type_tests {
             debug!("check_type_test: {:?}", type_test);
 
-            if self.eval_region_test(
-                mir,
-                dfs_storage,
-                type_test.point,
-                type_test.lower_bound,
-                &type_test.test,
-            ) {
+            if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) {
                 continue;
             }
 
@@ -858,7 +803,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn eval_region_test(
         &self,
         mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
         point: Location,
         lower_bound: RegionVid,
         test: &RegionTest,
@@ -871,27 +815,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         match test {
             RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
                 .iter()
-                .all(|&r| self.eval_outlives(mir, dfs_storage, r, lower_bound, point)),
+                .all(|&r| self.eval_outlives(mir, r, lower_bound, point)),
 
             RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
                 .iter()
-                .any(|&r| self.eval_outlives(mir, dfs_storage, r, lower_bound, point)),
+                .any(|&r| self.eval_outlives(mir, r, lower_bound, point)),
 
             RegionTest::Any(tests) => tests
                 .iter()
-                .any(|test| self.eval_region_test(mir, dfs_storage, point, lower_bound, test)),
+                .any(|test| self.eval_region_test(mir, point, lower_bound, test)),
 
             RegionTest::All(tests) => tests
                 .iter()
-                .all(|test| self.eval_region_test(mir, dfs_storage, point, lower_bound, test)),
+                .all(|test| self.eval_region_test(mir, point, lower_bound, test)),
         }
     }
 
     // Evaluate whether `sup_region: sub_region @ point`.
     fn eval_outlives(
         &self,
-        mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
+        _mir: &Mir<'tcx>,
         sup_region: RegionVid,
         sub_region: RegionVid,
         point: Location,
@@ -901,36 +844,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             sup_region, sub_region, point
         );
 
-        // Roughly speaking, do a DFS of all region elements reachable
-        // from `point` contained in `sub_region`. If any of those are
-        // *not* present in `sup_region`, the DFS will abort early and
-        // yield an `Err` result.
-        match self.dfs(
-            mir,
-            dfs_storage,
-            TestTargetOutlivesSource {
-                source_region: sub_region,
-                target_region: sup_region,
-                constraint_point: point,
-                elements: &self.elements,
-                universal_regions: &self.universal_regions,
-                inferred_values: self.inferred_values.as_ref().unwrap(),
-            },
-        ) {
-            Ok(_) => {
-                debug!("eval_outlives: true");
-                true
-            }
+        let inferred_values = self.inferred_values
+            .as_ref()
+            .expect("values for regions not yet inferred");
 
-            Err(elem) => {
-                debug!(
-                    "eval_outlives: false because `{:?}` is not present in `{:?}`",
-                    self.elements.to_element(elem),
-                    sup_region
-                );
-                false
-            }
+        debug!(
+            "eval_outlives: sup_region's value = {:?}",
+            inferred_values.region_value_str(sup_region),
+        );
+        debug!(
+            "eval_outlives: sub_region's value = {:?}",
+            inferred_values.region_value_str(sub_region),
+        );
+
+        // Both the `sub_region` and `sup_region` consist of the union
+        // of some number of universal regions (along with the union
+        // of various points in the CFG; ignore those points for
+        // now). Therefore, the sup-region outlives the sub-region if,
+        // for each universal region R1 in the sub-region, there
+        // exists some region R2 in the sup-region that outlives R1.
+        let universal_outlives = inferred_values
+            .universal_regions_outlived_by(sub_region)
+            .all(|r1| {
+                inferred_values
+                    .universal_regions_outlived_by(sup_region)
+                    .any(|r2| self.universal_regions.outlives(r2, r1))
+            });
+
+        if !universal_outlives {
+            return false;
+        }
+
+        // Now we have to compare all the points in the sub region and make
+        // sure they exist in the sup region.
+
+        if self.universal_regions.is_universal_region(sup_region) {
+            // Micro-opt: universal regions contain all points.
+            return true;
         }
+
+        inferred_values.contains_points(sup_region, sub_region)
     }
 
     /// Once regions have been propagated, this method is used to see
@@ -1007,7 +960,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 longer_fr, shorter_fr,
             );
 
-            let blame_span = self.blame_span(longer_fr, shorter_fr);
+            let blame_index = self.blame_constraint(longer_fr, shorter_fr);
+            let blame_span = self.constraints[blame_index].span;
 
             if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
                 // Shrink `fr` until we find a non-local region (if we do).
@@ -1093,9 +1047,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         diag.emit();
     }
 
+    crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
+        // Find some constraint `X: Y` where:
+        // - `fr1: X` transitively
+        // - and `Y` is live at `elem`
+        let index = self.blame_constraint(fr1, elem);
+        let region_sub = self.constraints[index].sub;
+
+        // then return why `Y` was live at `elem`
+        self.liveness_constraints.cause(region_sub, elem)
+    }
+
     /// Tries to finds a good span to blame for the fact that `fr1`
     /// contains `fr2`.
-    fn blame_span(&self, fr1: RegionVid, fr2: RegionVid) -> Span {
+    fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex {
         // Find everything that influenced final value of `fr`.
         let influenced_fr1 = self.dependencies(fr1);
 
@@ -1108,23 +1073,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // of dependencies, which doesn't account for the locations of
         // contraints at all. But it will do for now.
         let relevant_constraint = self.constraints
-                .iter()
-                .filter_map(|constraint| {
-                    if constraint.sub != fr2 {
-                        None
-                    } else {
-                        influenced_fr1[constraint.sup]
-                            .map(|distance| (distance, constraint.span))
-                    }
-                })
-                .min() // constraining fr1 with fewer hops *ought* to be more obvious
-                .map(|(_dist, span)| span);
+            .iter_enumerated()
+            .filter_map(|(i, constraint)| {
+                if !self.liveness_constraints.contains(constraint.sub, elem) {
+                    None
+                } else {
+                    influenced_fr1[constraint.sup]
+                        .map(|distance| (distance, i))
+                }
+            })
+            .min() // constraining fr1 with fewer hops *ought* to be more obvious
+            .map(|(_dist, i)| i);
 
         relevant_constraint.unwrap_or_else(|| {
             bug!(
                 "could not find any constraint to blame for {:?}: {:?}",
                 fr1,
-                fr2
+                elem,
             );
         })
     }
@@ -1161,16 +1126,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 }
 
-impl RegionCausalInfo {
-    /// Returns the *reason* that the region `r` contains the given point.
-    pub(super) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
-    where
-        R: ToRegionVid,
-    {
-        self.inferred_values.cause(r.to_region_vid(), p)
-    }
-}
-
 impl<'tcx> RegionDefinition<'tcx> {
     fn new(origin: RegionVariableOrigin) -> Self {
         // Create a new region definition. Note that, for free
@@ -1314,31 +1269,3 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
         })
     }
 }
-
-trait CauseExt {
-    fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause;
-}
-
-impl CauseExt for Rc<Cause> {
-    /// Creates a derived cause due to an outlives constraint.
-    fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause {
-        Cause::Outlives {
-            original_cause: self.clone(),
-            constraint_location,
-            constraint_span,
-        }
-    }
-}
-
-impl Cause {
-    pub(crate) fn root_cause(&self) -> &Cause {
-        match self {
-            Cause::LiveVar(..)
-            | Cause::DropVar(..)
-            | Cause::LiveOther(..)
-            | Cause::UniversalRegion(..) => self,
-
-            Cause::Outlives { original_cause, .. } => original_cause.root_cause(),
-        }
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index d15d85792d9..e914be52db0 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -8,16 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::rc::Rc;
+use borrow_check::nll::region_infer::TrackCauses;
+use rustc::mir::{BasicBlock, Location, Mir};
+use rustc::ty::RegionVid;
 use rustc_data_structures::bitvec::SparseBitMatrix;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
-use rustc::mir::{BasicBlock, Location, Mir};
-use rustc::ty::{self, RegionVid};
-use syntax::codemap::Span;
+use std::fmt::Debug;
+use std::rc::Rc;
 
-use super::{Cause, CauseExt, TrackCauses};
+use super::Cause;
 
 /// Maps between the various kinds of elements of a region value to
 /// the internal indices that w use.
@@ -72,11 +73,6 @@ impl RegionValueElements {
         (0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions))
     }
 
-    /// Iterates over the `RegionElementIndex` for all points in the CFG.
-    pub(super) fn all_universal_region_indices(&self) -> impl Iterator<Item = RegionElementIndex> {
-        (0..self.num_universal_regions).map(move |i| RegionElementIndex::new(i))
-    }
-
     /// Converts a particular `RegionElementIndex` to the `RegionElement` it represents.
     pub(super) fn to_element(&self, i: RegionElementIndex) -> RegionElement {
         debug!("to_element(i={:?})", i);
@@ -152,7 +148,7 @@ pub(super) enum RegionElement {
     UniversalRegion(RegionVid),
 }
 
-pub(super) trait ToElementIndex {
+pub(super) trait ToElementIndex: Debug + Copy {
     fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex;
 }
 
@@ -195,7 +191,7 @@ pub(super) struct RegionValues {
     causes: Option<CauseMap>,
 }
 
-type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
+type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Cause>;
 
 impl RegionValues {
     /// Creates a new set of "region values" that tracks causal information.
@@ -237,11 +233,22 @@ impl RegionValues {
 
     /// Adds the given element to the value for the given region. Returns true if
     /// the element is newly added (i.e., was not already present).
-    pub(super) fn add<E: ToElementIndex>(&mut self, r: RegionVid, elem: E, cause: &Cause) -> bool {
+    pub(super) fn add_element<E: ToElementIndex>(
+        &mut self,
+        r: RegionVid,
+        elem: E,
+        cause: &Cause,
+    ) -> bool {
         let i = self.elements.index(elem);
         self.add_internal(r, i, |_| cause.clone())
     }
 
+    /// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
+    /// r_from`).
+    pub(super) fn add_region(&mut self, r_to: RegionVid, r_from: RegionVid) -> bool {
+        self.matrix.merge(r_from, r_to)
+    }
+
     /// Internal method to add an element to a region.
     ///
     /// Takes a "lazy" cause -- this function will return the cause, but it will only
@@ -254,7 +261,7 @@ impl RegionValues {
             debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i));
 
             if let Some(causes) = &mut self.causes {
-                let cause = Rc::new(make_cause(causes));
+                let cause = make_cause(causes);
                 causes.insert((r, i), cause);
             }
 
@@ -266,15 +273,8 @@ impl RegionValues {
                 // #49998: compare using root cause alone to avoid
                 // useless traffic from similar outlives chains.
 
-                let overwrite = if ty::tls::with(|tcx| {
-                    tcx.sess.opts.debugging_opts.nll_subminimal_causes
-                }) {
-                    cause.root_cause() < old_cause.root_cause()
-                } else {
-                    cause < **old_cause
-                };
-                if overwrite {
-                    *old_cause = Rc::new(cause);
+                if cause < *old_cause {
+                    *old_cause = cause;
                     return true;
                 }
             }
@@ -283,62 +283,22 @@ impl RegionValues {
         }
     }
 
-    /// Adds `elem` to `to_region` because of a relation:
-    ///
-    ///     to_region: from_region @ constraint_location
-    ///
-    /// that was added by the cod at `constraint_span`.
-    pub(super) fn add_due_to_outlives<T: ToElementIndex>(
-        &mut self,
-        from_region: RegionVid,
-        to_region: RegionVid,
-        elem: T,
-        constraint_location: Location,
-        constraint_span: Span,
-    ) -> bool {
-        let elem = self.elements.index(elem);
-        self.add_internal(to_region, elem, |causes| {
-            causes[&(from_region, elem)].outlives(constraint_location, constraint_span)
-        })
-    }
-
-    /// Adds all the universal regions outlived by `from_region` to
-    /// `to_region`.
-    pub(super) fn add_universal_regions_outlived_by(
-        &mut self,
-        from_region: RegionVid,
-        to_region: RegionVid,
-        constraint_location: Location,
-        constraint_span: Span,
-    ) -> bool {
-        // We could optimize this by improving `SparseBitMatrix::merge` so
-        // it does not always merge an entire row. That would
-        // complicate causal tracking though.
-        debug!(
-            "add_universal_regions_outlived_by(from_region={:?}, to_region={:?})",
-            from_region, to_region
-        );
-        let mut changed = false;
-        for elem in self.elements.all_universal_region_indices() {
-            if self.contains(from_region, elem) {
-                changed |= self.add_due_to_outlives(
-                    from_region,
-                    to_region,
-                    elem,
-                    constraint_location,
-                    constraint_span,
-                );
-            }
-        }
-        changed
-    }
-
     /// True if the region `r` contains the given element.
     pub(super) fn contains<E: ToElementIndex>(&self, r: RegionVid, elem: E) -> bool {
         let i = self.elements.index(elem);
         self.matrix.contains(r, i)
     }
 
+    /// True if `sup_region` contains all the CFG points that
+    /// `sub_region` contains. Ignores universal regions.
+    pub(super) fn contains_points(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
+        // This could be done faster by comparing the bitsets. But I
+        // am lazy.
+        self.element_indices_contained_in(sub_region)
+            .skip_while(|&i| self.elements.to_universal_region(i).is_some())
+            .all(|e| self.contains(sup_region, e))
+    }
+
     /// Iterate over the value of the region `r`, yielding up element
     /// indices. You may prefer `universal_regions_outlived_by` or
     /// `elements_contained_in`.
@@ -444,7 +404,7 @@ impl RegionValues {
     ///
     /// Returns None if cause tracking is disabled or `elem` is not
     /// actually found in `r`.
-    pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Rc<Cause>> {
+    pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Cause> {
         let index = self.elements.index(elem);
         if let Some(causes) = &self.causes {
             causes.get(&(r, index)).cloned()
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index b01b3542136..4739c0e92ed 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -21,7 +21,7 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::region;
 use rustc::infer::InferCtxt;
-use rustc::ty::layout::IntegerExt;
+use rustc::ty::layout::{IntegerExt, Size};
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt, layout};
 use rustc::ty::subst::Substs;
@@ -182,7 +182,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             LitKind::Str(ref s, _) => {
                 let s = s.as_str();
                 let id = self.tcx.allocate_cached(s.as_bytes());
-                let ptr = MemoryPointer::new(id, 0);
+                let ptr = MemoryPointer::new(id, Size::from_bytes(0));
                 ConstValue::ByValPair(
                     PrimVal::Ptr(ptr),
                     PrimVal::from_u128(s.len() as u128),
@@ -190,7 +190,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             },
             LitKind::ByteStr(ref data) => {
                 let id = self.tcx.allocate_cached(data);
-                let ptr = MemoryPointer::new(id, 0);
+                let ptr = MemoryPointer::new(id, Size::from_bytes(0));
                 ConstValue::ByVal(PrimVal::Ptr(ptr))
             },
             LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index f930d47dc0b..0c2645b4c5c 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -191,7 +191,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
                             .interpret_interner
                             .get_alloc(ptr.alloc_id)
                             .unwrap();
-                        assert_eq!(ptr.offset, 0);
+                        assert_eq!(ptr.offset.bytes(), 0);
                         // FIXME: check length
                         alloc.bytes.iter().map(|b| {
                             &*pattern_arena.alloc(Pattern {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 749e574ff7a..0368e6595c1 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -22,6 +22,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
 use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::layout::Size;
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
 use rustc::hir::def::{Def, CtorKind};
@@ -1083,7 +1084,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
         LitKind::Str(ref s, _) => {
             let s = s.as_str();
             let id = tcx.allocate_cached(s.as_bytes());
-            let ptr = MemoryPointer::new(id, 0);
+            let ptr = MemoryPointer::new(id, Size::from_bytes(0));
             ConstValue::ByValPair(
                 PrimVal::Ptr(ptr),
                 PrimVal::from_u128(s.len() as u128),
@@ -1091,7 +1092,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
         },
         LitKind::ByteStr(ref data) => {
             let id = tcx.allocate_cached(data);
-            let ptr = MemoryPointer::new(id, 0);
+            let ptr = MemoryPointer::new(id, Size::from_bytes(0));
             ConstValue::ByVal(PrimVal::Ptr(ptr))
         },
         LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 002b5eb187d..b5568b83339 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -73,7 +73,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         match dest_ty.sty {
             // float -> uint
             TyUint(t) => {
-                let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
+                let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8);
                 match fty {
                     FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
                     FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
@@ -81,7 +81,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             },
             // float -> int
             TyInt(t) => {
-                let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
+                let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8);
                 match fty {
                     FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
                     FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 7d0c16de0a4..c5143817030 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -95,62 +95,35 @@ pub fn eval_body<'a, 'tcx>(
 
 pub fn value_to_const_value<'tcx>(
     ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
-    mut val: Value,
+    val: Value,
     ty: Ty<'tcx>,
 ) -> &'tcx ty::Const<'tcx> {
-    let result = (|| {
-        // Convert to ByVal or ByValPair if possible
-        if let Value::ByRef(ptr, align) = val {
-            if let Some(read_val) = ecx.try_read_value(ptr, align, ty)? {
-                val = read_val;
+    let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+    match (val, &layout.abi) {
+        (Value::ByVal(PrimVal::Undef), _) if layout.is_zst() => {},
+        (Value::ByRef(..), _) |
+        (Value::ByVal(_), &layout::Abi::Scalar(_)) |
+        (Value::ByValPair(..), &layout::Abi::ScalarPair(..)) => {},
+        _ => bug!("bad value/layout combo: {:#?}, {:#?}", val, layout),
+    }
+    let val = (|| {
+        match val {
+            Value::ByVal(val) => Ok(ConstValue::ByVal(val)),
+            Value::ByValPair(a, b) => Ok(ConstValue::ByValPair(a, b)),
+            Value::ByRef(ptr, align) => {
+                let ptr = ptr.primval.to_ptr().unwrap();
+                let alloc = ecx.memory.get(ptr.alloc_id)?;
+                assert!(alloc.align.abi() >= align.abi());
+                assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= layout.size.bytes());
+                let mut alloc = alloc.clone();
+                alloc.align = align;
+                let alloc = ecx.tcx.intern_const_alloc(alloc);
+                Ok(ConstValue::ByRef(alloc, ptr.offset))
             }
         }
-
-        let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
-
-        if layout.is_zst() {
-            return Ok(ty::Const::from_const_value(
-                ecx.tcx.tcx,
-                ConstValue::ByVal(PrimVal::Undef),
-                ty));
-        }
-
-        let val = match layout.abi {
-            layout::Abi::Scalar(..) => {
-                if let Value::ByVal(val) = val {
-                    ConstValue::ByVal(val)
-                } else {
-                    bug!("expected ByVal value, got {:?}", val);
-                }
-            }
-            layout::Abi::ScalarPair(..) => {
-                if let Value::ByValPair(a, b) = val {
-                    ConstValue::ByValPair(a, b)
-                } else {
-                    bug!("expected ByValPair value, got {:?}", val);
-                }
-            }
-            _ => {
-                if let Value::ByRef(ptr, _) = val {
-                    let ptr = ptr.primval.to_ptr().unwrap();
-                    assert_eq!(ptr.offset, 0);
-                    let alloc = ecx.memory.get(ptr.alloc_id)?;
-                    assert!(alloc.align.abi() >= layout.align.abi());
-                    assert!(alloc.bytes.len() as u64 == layout.size.bytes());
-                    let mut alloc = alloc.clone();
-                    // The align field is meaningless for values, so just use the layout's align
-                    alloc.align = layout.align;
-                    let alloc = ecx.tcx.intern_const_alloc(alloc);
-                    ConstValue::ByRef(alloc)
-                } else {
-                    bug!("expected ByRef value, got {:?}", val);
-                }
-            },
-        };
-        Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, ty))
     })();
-    match result {
-        Ok(v) => v,
+    match val {
+        Ok(val) => ty::Const::from_const_value(ecx.tcx.tcx, val, ty),
         Err(mut err) => {
             ecx.report(&mut err, true, None);
             bug!("miri error occured when converting Value to ConstValue")
@@ -182,49 +155,49 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
 ) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
     debug!("eval_body: {:?}, {:?}", cid, param_env);
     let tcx = ecx.tcx.tcx;
-        let mut mir = match mir {
-            Some(mir) => mir,
-            None => ecx.load_mir(cid.instance.def)?,
-        };
-        if let Some(index) = cid.promoted {
-            mir = &mir.promoted[index];
-        }
-        let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
-        assert!(!layout.is_unsized());
-        let ptr = ecx.memory.allocate(
-            layout.size.bytes(),
-            layout.align,
-            None,
-        )?;
-        let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
-        let mutability = tcx.is_static(cid.instance.def_id());
-        let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable {
-            Mutability::Mutable
-        } else {
-            Mutability::Immutable
-        };
-        let cleanup = StackPopCleanup::MarkStatic(mutability);
-        let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
-        let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
-        trace!("const_eval: pushing stack frame for global: {}{}", name, prom);
-        assert!(mir.arg_count == 0);
-        ecx.push_stack_frame(
-            cid.instance,
-            mir.span,
-            mir,
-            Place::from_ptr(ptr, layout.align),
-            cleanup,
-        )?;
+    let mut mir = match mir {
+        Some(mir) => mir,
+        None => ecx.load_mir(cid.instance.def)?,
+    };
+    if let Some(index) = cid.promoted {
+        mir = &mir.promoted[index];
+    }
+    let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
+    assert!(!layout.is_unsized());
+    let ptr = ecx.memory.allocate(
+        layout.size,
+        layout.align,
+        None,
+    )?;
+    let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
+    let is_static = tcx.is_static(cid.instance.def_id());
+    let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable {
+        Mutability::Mutable
+    } else {
+        Mutability::Immutable
+    };
+    let cleanup = StackPopCleanup::MarkStatic(mutability);
+    let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
+    let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
+    trace!("const_eval: pushing stack frame for global: {}{}", name, prom);
+    assert!(mir.arg_count == 0);
+    ecx.push_stack_frame(
+        cid.instance,
+        mir.span,
+        mir,
+        Place::from_ptr(ptr, layout.align),
+        cleanup,
+    )?;
 
-        while ecx.step()? {}
-        let ptr = ptr.into();
-        // always try to read the value and report errors
-        let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
-            Some(val) => val,
-            // point at the allocation
-            _ => Value::ByRef(ptr, layout.align),
-        };
-        Ok((value, ptr, layout.ty))
+    while ecx.step()? {}
+    let ptr = ptr.into();
+    // always try to read the value and report errors
+    let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
+        Some(val) if is_static.is_none() => val,
+        // point at the allocation
+        _ => Value::ByRef(ptr, layout.align),
+    };
+    Ok((value, ptr, layout.ty))
 }
 
 pub struct CompileTimeEvaluator;
@@ -442,22 +415,37 @@ pub fn const_val_field<'a, 'tcx>(
     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
     let result = (|| {
         let value = ecx.const_value_to_value(value, ty)?;
-        let (field, ty) = match value {
-            Value::ByValPair(..) | Value::ByVal(_) => 
-                ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
-            Value::ByRef(ptr, align) => {
-                let place = Place::Ptr {
-                    ptr,
-                    align,
-                    extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
-                };
-                let layout = ecx.layout_of(ty)?;
-                let (place, layout) = ecx.place_field(place, field, layout)?;
-                let (ptr, align) = place.to_ptr_align();
-                (Value::ByRef(ptr, align), layout.ty)
-            }
+        let layout = ecx.layout_of(ty)?;
+        let (ptr, align) = match value {
+            Value::ByRef(ptr, align) => (ptr, align),
+            Value::ByValPair(..) | Value::ByVal(_) => {
+                let ptr = ecx.alloc_ptr(ty)?.into();
+                ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
+                (ptr, layout.align)
+            },
+        };
+        let place = Place::Ptr {
+            ptr,
+            align,
+            extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
         };
-        Ok(value_to_const_value(&ecx, field, ty))
+        let (place, layout) = ecx.place_field(place, field, layout)?;
+        let (ptr, align) = place.to_ptr_align();
+        let mut new_value = Value::ByRef(ptr, align);
+        new_value = ecx.try_read_by_ref(new_value, layout.ty)?;
+        use rustc_data_structures::indexed_vec::Idx;
+        match (value, new_value) {
+            (Value::ByVal(_), Value::ByRef(..)) |
+            (Value::ByValPair(..), Value::ByRef(..)) |
+            (Value::ByVal(_), Value::ByValPair(..)) => bug!(
+                "field {} of {:?} yielded {:?}",
+                field.index(),
+                value,
+                new_value,
+            ),
+            _ => {},
+        }
+        Ok(value_to_const_value(&ecx, new_value, layout.ty))
     })();
     result.map_err(|err| {
         let (trace, span) = ecx.generate_stacktrace(None);
@@ -482,7 +470,7 @@ pub fn const_variant_index<'a, 'tcx>(
     let (ptr, align) = match value {
         Value::ByValPair(..) | Value::ByVal(_) => {
             let layout = ecx.layout_of(ty)?;
-            let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
+            let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?;
             let ptr: Pointer = ptr.into();
             ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
             (ptr, layout.align)
@@ -498,7 +486,10 @@ pub fn const_value_to_allocation_provider<'a, 'tcx>(
     (val, ty): (ConstValue<'tcx>, Ty<'tcx>),
 ) -> &'tcx Allocation {
     match val {
-        ConstValue::ByRef(alloc) => return alloc,
+        ConstValue::ByRef(alloc, offset) => {
+            assert_eq!(offset.bytes(), 0);
+            return alloc;
+        },
         _ => ()
     }
     let result = || -> EvalResult<'tcx, &'tcx Allocation> {
@@ -509,7 +500,7 @@ pub fn const_value_to_allocation_provider<'a, 'tcx>(
             ());
         let value = ecx.const_value_to_value(val, ty)?;
         let layout = ecx.layout_of(ty)?;
-        let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
+        let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?;
         ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
         let alloc = ecx.memory.get(ptr.alloc_id)?;
         Ok(tcx.intern_const_alloc(alloc.clone()))
@@ -551,8 +542,11 @@ pub fn const_eval_provider<'a, 'tcx>(
     };
 
     let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
-    res.map(|(val, _, miri_ty)| {
-        value_to_const_value(&ecx, val, miri_ty)
+    res.and_then(|(mut val, _, miri_ty)| {
+        if tcx.is_static(def_id).is_none() {
+            val = ecx.try_read_by_ref(val, miri_ty)?;
+        }
+        Ok(value_to_const_value(&ecx, val, miri_ty))
     }).map_err(|mut err| {
         if tcx.is_static(def_id).is_some() {
             ecx.report(&mut err, true, None);
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 03137619eda..1b4cdccee76 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -207,8 +207,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         let layout = self.layout_of(ty)?;
         assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
 
-        let size = layout.size.bytes();
-        self.memory.allocate(size, layout.align, Some(MemoryKind::Stack))
+        self.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))
     }
 
     pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
@@ -243,10 +242,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         _ty: Ty<'tcx>,
     ) -> EvalResult<'tcx, Value> {
         match val {
-            ConstValue::ByRef(alloc) => {
+            ConstValue::ByRef(alloc, offset) => {
                 // FIXME: Allocate new AllocId for all constants inside
                 let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
-                Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align))
+                Ok(Value::ByRef(MemoryPointer::new(id, offset).into(), alloc.align))
             },
             ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
             ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
@@ -598,14 +597,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                         )
                     }
                 };
-                let elem_size = self.layout_of(elem_ty)?.size.bytes();
+                let elem_size = self.layout_of(elem_ty)?.size;
                 let value = self.eval_operand(operand)?.value;
 
                 let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
 
                 // FIXME: speed up repeat filling
                 for i in 0..length {
-                    let elem_dest = dest.offset(i * elem_size, &self)?;
+                    let elem_dest = dest.offset(elem_size * i as u64, &self)?;
                     self.write_value_to_ptr(value, elem_dest, dest_align, elem_ty)?;
                 }
             }
@@ -1027,7 +1026,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 .interpret_interner
                 .cache_static(gid.instance.def_id());
             let layout = self.layout_of(ty)?;
-            let ptr = MemoryPointer::new(alloc_id, 0);
+            let ptr = MemoryPointer::new(alloc_id, Size::from_bytes(0));
             return Ok(Value::ByRef(ptr.into(), layout.align))
         }
         let cv = self.const_eval(gid)?;
@@ -1195,7 +1194,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
             } else {
                 let dest_ptr = self.alloc_ptr(dest_ty)?.into();
                 let layout = self.layout_of(dest_ty)?;
-                self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size.bytes(), false)?;
+                self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size, false)?;
                 write_dest(self, Value::ByRef(dest_ptr, layout.align))?;
             }
         } else {
@@ -1217,7 +1216,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
         match value {
             Value::ByRef(ptr, align) => {
-                self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
+                self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size, false)
             }
             Value::ByVal(primval) => {
                 let signed = match layout.abi {
@@ -1228,7 +1227,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                     _ if primval.is_undef() => false,
                     _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
                 };
-                self.memory.write_primval(dest, dest_align, primval, layout.size.bytes(), signed)
+                self.memory.write_primval(dest, dest_align, primval, layout.size, signed)
             }
             Value::ByValPair(a_val, b_val) => {
                 trace!("write_value_to_ptr valpair: {:#?}", layout);
@@ -1239,10 +1238,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 let (a_size, b_size) = (a.size(&self), b.size(&self));
                 let a_ptr = dest;
                 let b_offset = a_size.abi_align(b.align(&self));
-                let b_ptr = dest.offset(b_offset.bytes(), &self)?.into();
+                let b_ptr = dest.offset(b_offset, &self)?.into();
                 // TODO: What about signedess?
-                self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?;
-                self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false)
+                self.memory.write_primval(a_ptr, dest_align, a_val, a_size, false)?;
+                self.memory.write_primval(b_ptr, dest_align, b_val, b_size, false)
             }
         }
     }
@@ -1257,11 +1256,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
             ty::TyInt(int_ty) => {
                 use syntax::ast::IntTy::*;
                 let size = match int_ty {
-                    I8 => 1,
-                    I16 => 2,
-                    I32 => 4,
-                    I64 => 8,
-                    I128 => 16,
+                    I8 => Size::from_bytes(1),
+                    I16 => Size::from_bytes(2),
+                    I32 => Size::from_bytes(4),
+                    I64 => Size::from_bytes(8),
+                    I128 => Size::from_bytes(16),
                     Isize => self.memory.pointer_size(),
                 };
                 PrimValKind::from_int_size(size)
@@ -1270,11 +1269,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
             ty::TyUint(uint_ty) => {
                 use syntax::ast::UintTy::*;
                 let size = match uint_ty {
-                    U8 => 1,
-                    U16 => 2,
-                    U32 => 4,
-                    U64 => 8,
-                    U128 => 16,
+                    U8 => Size::from_bytes(1),
+                    U16 => Size::from_bytes(2),
+                    U32 => Size::from_bytes(4),
+                    U64 => Size::from_bytes(8),
+                    U128 => Size::from_bytes(16),
                     Usize => self.memory.pointer_size(),
                 };
                 PrimValKind::from_uint_size(size)
@@ -1297,8 +1296,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                     layout::Abi::Scalar(ref scalar) => {
                         use rustc::ty::layout::Primitive::*;
                         match scalar.value {
-                            Int(i, false) => PrimValKind::from_uint_size(i.size().bytes()),
-                            Int(i, true) => PrimValKind::from_int_size(i.size().bytes()),
+                            Int(i, false) => PrimValKind::from_uint_size(i.size()),
+                            Int(i, true) => PrimValKind::from_int_size(i.size()),
                             F32 => PrimValKind::F32,
                             F64 => PrimValKind::F64,
                             Pointer => PrimValKind::Ptr,
@@ -1372,7 +1371,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
     ) -> EvalResult<'tcx> {
         match ty.sty {
             ty::TyBool => {
-                let val = self.memory.read_primval(ptr, ptr_align, 1)?;
+                let val = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(1))?;
                 match val {
                     PrimVal::Bytes(0) | PrimVal::Bytes(1) => (),
                     // TODO: This seems a little overeager, should reading at bool type already be insta-UB?
@@ -1380,7 +1379,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 }
             }
             ty::TyChar => {
-                let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
+                let c = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(4))?.to_bytes()? as u32;
                 match ::std::char::from_u32(c) {
                     Some(..) => (),
                     None => return err!(InvalidChar(c as u128)),
@@ -1402,7 +1401,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 }
 
                 if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
-                    let size = scalar.value.size(self).bytes();
+                    let size = scalar.value.size(self);
                     self.memory.read_primval(ptr, ptr_align, size)?;
                 }
             }
@@ -1412,6 +1411,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         Ok(())
     }
 
+    pub fn try_read_by_ref(&self, mut val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+        // Convert to ByVal or ByValPair if possible
+        if let Value::ByRef(ptr, align) = val {
+            if let Some(read_val) = self.try_read_value(ptr, align, ty)? {
+                val = read_val;
+            }
+        }
+        Ok(val)
+    }
+
     pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
         let layout = self.layout_of(ty)?;
         self.memory.check_align(ptr, ptr_align)?;
@@ -1427,7 +1436,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
 
         match layout.abi {
             layout::Abi::Scalar(..) => {
-                let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?;
+                let primval = self.memory.read_primval(ptr, ptr_align, layout.size)?;
                 Ok(Some(Value::ByVal(primval)))
             }
             layout::Abi::ScalarPair(ref a, ref b) => {
@@ -1435,9 +1444,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 let (a_size, b_size) = (a.size(self), b.size(self));
                 let a_ptr = ptr;
                 let b_offset = a_size.abi_align(b.align(self));
-                let b_ptr = ptr.offset(b_offset.bytes(), self)?.into();
-                let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?;
-                let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?;
+                let b_ptr = ptr.offset(b_offset, self)?.into();
+                let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size)?;
+                let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size)?;
                 Ok(Some(Value::ByValPair(a_val, b_val)))
             }
             _ => Ok(None),
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 5af0a053e92..a5c94e4fcec 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -7,6 +7,7 @@ use super::{EvalContext, Place, ValTy, Memory};
 
 use rustc::mir;
 use rustc::ty::{self, Ty};
+use rustc::ty::layout::Size;
 use syntax::codemap::Span;
 use syntax::ast::Mutability;
 
@@ -92,7 +93,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn check_locks<'a>(
         _mem: &Memory<'a, 'mir, 'tcx, Self>,
         _ptr: MemoryPointer,
-        _size: u64,
+        _size: Size,
         _access: AccessKind,
     ) -> EvalResult<'tcx> {
         Ok(())
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index ba1c05deef1..755eaa443b6 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId;
 use rustc::ty::Instance;
 use rustc::ty::ParamEnv;
 use rustc::ty::maps::TyCtxtAt;
-use rustc::ty::layout::{self, Align, TargetDataLayout};
+use rustc::ty::layout::{self, Align, TargetDataLayout, Size};
 use syntax::ast::Mutability;
 use rustc::middle::const_val::{ConstVal, ErrKind};
 
@@ -73,12 +73,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer {
         let id = self.tcx.interpret_interner.create_fn_alloc(instance);
-        MemoryPointer::new(id, 0)
+        MemoryPointer::new(id, Size::from_bytes(0))
     }
 
     pub fn allocate_cached(&mut self, bytes: &[u8]) -> MemoryPointer {
         let id = self.tcx.allocate_cached(bytes);
-        MemoryPointer::new(id, 0)
+        MemoryPointer::new(id, Size::from_bytes(0))
     }
 
     /// kind is `None` for statics
@@ -105,24 +105,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// kind is `None` for statics
     pub fn allocate(
         &mut self,
-        size: u64,
+        size: Size,
         align: Align,
         kind: Option<MemoryKind<M::MemoryKinds>>,
     ) -> EvalResult<'tcx, MemoryPointer> {
         let id = self.allocate_value(Allocation::undef(size, align), kind)?;
-        Ok(MemoryPointer::new(id, 0))
+        Ok(MemoryPointer::new(id, Size::from_bytes(0)))
     }
 
     pub fn reallocate(
         &mut self,
         ptr: MemoryPointer,
-        old_size: u64,
+        old_size: Size,
         old_align: Align,
-        new_size: u64,
+        new_size: Size,
         new_align: Align,
         kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx, MemoryPointer> {
-        if ptr.offset != 0 {
+        if ptr.offset.bytes() != 0 {
             return err!(ReallocateNonBasePtr);
         }
         if self.alloc_map.contains_key(&ptr.alloc_id) {
@@ -163,10 +163,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn deallocate(
         &mut self,
         ptr: MemoryPointer,
-        size_and_align: Option<(u64, Align)>,
+        size_and_align: Option<(Size, Align)>,
         kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx> {
-        if ptr.offset != 0 {
+        if ptr.offset.bytes() != 0 {
             return err!(DeallocateNonBasePtr);
         }
 
@@ -208,8 +208,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             ));
         }
         if let Some((size, align)) = size_and_align {
-            if size != alloc.bytes.len() as u64 || align != alloc.align {
-                return err!(IncorrectAllocationInformation(size, alloc.bytes.len(), align.abi(), alloc.align.abi()));
+            if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align {
+                return err!(IncorrectAllocationInformation(size, Size::from_bytes(alloc.bytes.len() as u64), align, alloc.align));
             }
         }
 
@@ -218,8 +218,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub fn pointer_size(&self) -> u64 {
-        self.tcx.data_layout.pointer_size.bytes()
+    pub fn pointer_size(&self) -> Size {
+        self.tcx.data_layout.pointer_size
     }
 
     pub fn endianness(&self) -> layout::Endian {
@@ -232,10 +232,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         let (offset, alloc_align) = match ptr.into_inner_primval() {
             PrimVal::Ptr(ptr) => {
                 let alloc = self.get(ptr.alloc_id)?;
-                (ptr.offset, alloc.align)
+                (ptr.offset.bytes(), alloc.align)
             }
             PrimVal::Bytes(bytes) => {
-                let v = ((bytes as u128) % (1 << self.pointer_size())) as u64;
+                let v = ((bytes as u128) % (1 << self.pointer_size().bytes())) as u64;
                 if v == 0 {
                     return err!(InvalidNullPointerUsage);
                 }
@@ -247,16 +247,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         // Check alignment
         if alloc_align.abi() < required_align.abi() {
             return err!(AlignmentCheckFailed {
-                has: alloc_align.abi(),
-                required: required_align.abi(),
+                has: alloc_align,
+                required: required_align,
             });
         }
         if offset % required_align.abi() == 0 {
             Ok(())
         } else {
+            let has = offset % required_align.abi();
             err!(AlignmentCheckFailed {
-                has: offset % required_align.abi(),
-                required: required_align.abi(),
+                has: Align::from_bytes(has, has).unwrap(),
+                required: required_align,
             })
         }
     }
@@ -264,11 +265,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx> {
         let alloc = self.get(ptr.alloc_id)?;
         let allocation_size = alloc.bytes.len() as u64;
-        if ptr.offset > allocation_size {
+        if ptr.offset.bytes() > allocation_size {
             return err!(PointerOutOfBounds {
                 ptr,
                 access,
-                allocation_size,
+                allocation_size: Size::from_bytes(allocation_size),
             });
         }
         Ok(())
@@ -354,7 +355,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     }
 
     pub fn get_fn(&self, ptr: MemoryPointer) -> EvalResult<'tcx, Instance<'tcx>> {
-        if ptr.offset != 0 {
+        if ptr.offset.bytes() != 0 {
             return err!(InvalidFunctionPointer);
         }
         debug!("reading fn ptr: {}", ptr.alloc_id);
@@ -419,15 +420,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                 };
 
             for i in 0..(alloc.bytes.len() as u64) {
+                let i = Size::from_bytes(i);
                 if let Some(&target_id) = alloc.relocations.get(&i) {
                     if allocs_seen.insert(target_id) {
                         allocs_to_print.push_back(target_id);
                     }
                     relocations.push((i, target_id));
                 }
-                if alloc.undef_mask.is_range_defined(i, i + 1) {
+                if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)) {
                     // this `as usize` is fine, since `i` came from a `usize`
-                    write!(msg, "{:02x} ", alloc.bytes[i as usize]).unwrap();
+                    write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap();
                 } else {
                     msg.push_str("__ ");
                 }
@@ -444,11 +446,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             if !relocations.is_empty() {
                 msg.clear();
                 write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces.
-                let mut pos = 0;
-                let relocation_width = (self.pointer_size() - 1) * 3;
+                let mut pos = Size::from_bytes(0);
+                let relocation_width = (self.pointer_size().bytes() - 1) * 3;
                 for (i, target_id) in relocations {
                     // this `as usize` is fine, since we can't print more chars than `usize::MAX`
-                    write!(msg, "{:1$}", "", ((i - pos) * 3) as usize).unwrap();
+                    write!(msg, "{:1$}", "", ((i - pos) * 3).bytes() as usize).unwrap();
                     let target = format!("({})", target_id);
                     // this `as usize` is fine, since we can't print more chars than `usize::MAX`
                     write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap();
@@ -476,45 +478,45 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     fn get_bytes_unchecked(
         &self,
         ptr: MemoryPointer,
-        size: u64,
+        size: Size,
         align: Align,
     ) -> EvalResult<'tcx, &[u8]> {
         // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
         self.check_align(ptr.into(), align)?;
-        if size == 0 {
+        if size.bytes() == 0 {
             return Ok(&[]);
         }
         M::check_locks(self, ptr, size, AccessKind::Read)?;
         self.check_bounds(ptr.offset(size, self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
         let alloc = self.get(ptr.alloc_id)?;
-        assert_eq!(ptr.offset as usize as u64, ptr.offset);
-        assert_eq!(size as usize as u64, size);
-        let offset = ptr.offset as usize;
-        Ok(&alloc.bytes[offset..offset + size as usize])
+        assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
+        assert_eq!(size.bytes() as usize as u64, size.bytes());
+        let offset = ptr.offset.bytes() as usize;
+        Ok(&alloc.bytes[offset..offset + size.bytes() as usize])
     }
 
     fn get_bytes_unchecked_mut(
         &mut self,
         ptr: MemoryPointer,
-        size: u64,
+        size: Size,
         align: Align,
     ) -> EvalResult<'tcx, &mut [u8]> {
         // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
         self.check_align(ptr.into(), align)?;
-        if size == 0 {
+        if size.bytes() == 0 {
             return Ok(&mut []);
         }
         M::check_locks(self, ptr, size, AccessKind::Write)?;
         self.check_bounds(ptr.offset(size, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
         let alloc = self.get_mut(ptr.alloc_id)?;
-        assert_eq!(ptr.offset as usize as u64, ptr.offset);
-        assert_eq!(size as usize as u64, size);
-        let offset = ptr.offset as usize;
-        Ok(&mut alloc.bytes[offset..offset + size as usize])
+        assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
+        assert_eq!(size.bytes() as usize as u64, size.bytes());
+        let offset = ptr.offset.bytes() as usize;
+        Ok(&mut alloc.bytes[offset..offset + size.bytes() as usize])
     }
 
-    fn get_bytes(&self, ptr: MemoryPointer, size: u64, align: Align) -> EvalResult<'tcx, &[u8]> {
-        assert_ne!(size, 0);
+    fn get_bytes(&self, ptr: MemoryPointer, size: Size, align: Align) -> EvalResult<'tcx, &[u8]> {
+        assert_ne!(size.bytes(), 0);
         if self.relocations(ptr, size)?.count() != 0 {
             return err!(ReadPointerAsBytes);
         }
@@ -525,10 +527,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     fn get_bytes_mut(
         &mut self,
         ptr: MemoryPointer,
-        size: u64,
+        size: Size,
         align: Align,
     ) -> EvalResult<'tcx, &mut [u8]> {
-        assert_ne!(size, 0);
+        assert_ne!(size.bytes(), 0);
         self.clear_relocations(ptr, size)?;
         self.mark_definedness(ptr.into(), size, true)?;
         self.get_bytes_unchecked_mut(ptr, size, align)
@@ -594,13 +596,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         src_align: Align,
         dest: Pointer,
         dest_align: Align,
-        size: u64,
+        size: Size,
         nonoverlapping: bool,
     ) -> EvalResult<'tcx> {
         // Empty accesses don't need to be valid pointers, but they should still be aligned
         self.check_align(src, src_align)?;
         self.check_align(dest, dest_align)?;
-        if size == 0 {
+        if size.bytes() == 0 {
             return Ok(());
         }
         let src = src.to_ptr()?;
@@ -625,7 +627,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
         // `dest` could possibly overlap.
         unsafe {
-            assert_eq!(size as usize as u64, size);
+            assert_eq!(size.bytes() as usize as u64, size.bytes());
             if src.alloc_id == dest.alloc_id {
                 if nonoverlapping {
                     if (src.offset <= dest.offset && src.offset + size > dest.offset) ||
@@ -636,9 +638,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                         ));
                     }
                 }
-                ptr::copy(src_bytes, dest_bytes, size as usize);
+                ptr::copy(src_bytes, dest_bytes, size.bytes() as usize);
             } else {
-                ptr::copy_nonoverlapping(src_bytes, dest_bytes, size as usize);
+                ptr::copy_nonoverlapping(src_bytes, dest_bytes, size.bytes() as usize);
             }
         }
 
@@ -651,26 +653,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     pub fn read_c_str(&self, ptr: MemoryPointer) -> EvalResult<'tcx, &[u8]> {
         let alloc = self.get(ptr.alloc_id)?;
-        assert_eq!(ptr.offset as usize as u64, ptr.offset);
-        let offset = ptr.offset as usize;
+        assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
+        let offset = ptr.offset.bytes() as usize;
         match alloc.bytes[offset..].iter().position(|&c| c == 0) {
             Some(size) => {
-                if self.relocations(ptr, (size + 1) as u64)?.count() != 0 {
+                let p1 = Size::from_bytes((size + 1) as u64);
+                if self.relocations(ptr, p1)?.count() != 0 {
                     return err!(ReadPointerAsBytes);
                 }
-                self.check_defined(ptr, (size + 1) as u64)?;
-                M::check_locks(self, ptr, (size + 1) as u64, AccessKind::Read)?;
+                self.check_defined(ptr, p1)?;
+                M::check_locks(self, ptr, p1, AccessKind::Read)?;
                 Ok(&alloc.bytes[offset..offset + size])
             }
             None => err!(UnterminatedCString(ptr)),
         }
     }
 
-    pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> {
+    pub fn read_bytes(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx, &[u8]> {
         // Empty accesses don't need to be valid pointers, but they should still be non-NULL
         let align = Align::from_bytes(1, 1).unwrap();
         self.check_align(ptr, align)?;
-        if size == 0 {
+        if size.bytes() == 0 {
             return Ok(&[]);
         }
         self.get_bytes(ptr.to_ptr()?, size, align)
@@ -683,16 +686,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         if src.is_empty() {
             return Ok(());
         }
-        let bytes = self.get_bytes_mut(ptr.to_ptr()?, src.len() as u64, align)?;
+        let bytes = self.get_bytes_mut(ptr.to_ptr()?, Size::from_bytes(src.len() as u64), align)?;
         bytes.clone_from_slice(src);
         Ok(())
     }
 
-    pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> {
+    pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: Size) -> EvalResult<'tcx> {
         // Empty accesses don't need to be valid pointers, but they should still be non-NULL
         let align = Align::from_bytes(1, 1).unwrap();
         self.check_align(ptr, align)?;
-        if count == 0 {
+        if count.bytes() == 0 {
             return Ok(());
         }
         let bytes = self.get_bytes_mut(ptr.to_ptr()?, count, align)?;
@@ -702,7 +705,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64) -> EvalResult<'tcx, PrimVal> {
+    pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: Size) -> EvalResult<'tcx, PrimVal> {
         self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer
         let endianness = self.endianness();
         let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
@@ -721,7 +724,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         } else {
             let alloc = self.get(ptr.alloc_id)?;
             match alloc.relocations.get(&ptr.offset) {
-                Some(&alloc_id) => return Ok(PrimVal::Ptr(MemoryPointer::new(alloc_id, bytes as u64))),
+                Some(&alloc_id) => return Ok(PrimVal::Ptr(MemoryPointer::new(alloc_id, Size::from_bytes(bytes as u64)))),
                 None => {},
             }
         }
@@ -733,13 +736,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         self.read_primval(ptr, ptr_align, self.pointer_size())
     }
 
-    pub fn write_primval(&mut self, ptr: Pointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
+    pub fn write_primval(&mut self, ptr: Pointer, ptr_align: Align, val: PrimVal, size: Size, signed: bool) -> EvalResult<'tcx> {
         let endianness = self.endianness();
 
         let bytes = match val {
             PrimVal::Ptr(val) => {
                 assert_eq!(size, self.pointer_size());
-                val.offset as u128
+                val.offset.bytes() as u128
             }
 
             PrimVal::Bytes(bytes) => bytes,
@@ -782,16 +785,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         self.write_primval(ptr.into(), ptr_align, val, ptr_size, false)
     }
 
-    fn int_align(&self, size: u64) -> Align {
+    fn int_align(&self, size: Size) -> Align {
         // We assume pointer-sized integers have the same alignment as pointers.
         // We also assume signed and unsigned integers of the same size have the same alignment.
-        let ity = match size {
+        let ity = match size.bytes() {
             1 => layout::I8,
             2 => layout::I16,
             4 => layout::I32,
             8 => layout::I64,
             16 => layout::I128,
-            _ => bug!("bad integer size: {}", size),
+            _ => bug!("bad integer size: {}", size.bytes()),
         };
         ity.align(self)
     }
@@ -802,14 +805,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     fn relocations(
         &self,
         ptr: MemoryPointer,
-        size: u64,
-    ) -> EvalResult<'tcx, btree_map::Range<u64, AllocId>> {
-        let start = ptr.offset.saturating_sub(self.pointer_size() - 1);
+        size: Size,
+    ) -> EvalResult<'tcx, btree_map::Range<Size, AllocId>> {
+        let start = ptr.offset.bytes().saturating_sub(self.pointer_size().bytes() - 1);
         let end = ptr.offset + size;
-        Ok(self.get(ptr.alloc_id)?.relocations.range(start..end))
+        Ok(self.get(ptr.alloc_id)?.relocations.range(Size::from_bytes(start)..end))
     }
 
-    fn clear_relocations(&mut self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> {
+    fn clear_relocations(&mut self, ptr: MemoryPointer, size: Size) -> EvalResult<'tcx> {
         // Find all relocations overlapping the given range.
         let keys: Vec<_> = self.relocations(ptr, size)?.map(|(&k, _)| k).collect();
         if keys.is_empty() {
@@ -841,9 +844,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    fn check_relocation_edges(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> {
-        let overlapping_start = self.relocations(ptr, 0)?.count();
-        let overlapping_end = self.relocations(ptr.offset(size, self)?, 0)?.count();
+    fn check_relocation_edges(&self, ptr: MemoryPointer, size: Size) -> EvalResult<'tcx> {
+        let overlapping_start = self.relocations(ptr, Size::from_bytes(0))?.count();
+        let overlapping_end = self.relocations(ptr.offset(size, self)?, Size::from_bytes(0))?.count();
         if overlapping_start + overlapping_end != 0 {
             return err!(ReadPointerAsBytes);
         }
@@ -858,26 +861,26 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         &mut self,
         src: MemoryPointer,
         dest: MemoryPointer,
-        size: u64,
+        size: Size,
     ) -> EvalResult<'tcx> {
         // The bits have to be saved locally before writing to dest in case src and dest overlap.
-        assert_eq!(size as usize as u64, size);
-        let mut v = Vec::with_capacity(size as usize);
-        for i in 0..size {
-            let defined = self.get(src.alloc_id)?.undef_mask.get(src.offset + i);
+        assert_eq!(size.bytes() as usize as u64, size.bytes());
+        let mut v = Vec::with_capacity(size.bytes() as usize);
+        for i in 0..size.bytes() {
+            let defined = self.get(src.alloc_id)?.undef_mask.get(src.offset + Size::from_bytes(i));
             v.push(defined);
         }
         for (i, defined) in v.into_iter().enumerate() {
             self.get_mut(dest.alloc_id)?.undef_mask.set(
                 dest.offset +
-                    i as u64,
+                    Size::from_bytes(i as u64),
                 defined,
             );
         }
         Ok(())
     }
 
-    fn check_defined(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> {
+    fn check_defined(&self, ptr: MemoryPointer, size: Size) -> EvalResult<'tcx> {
         let alloc = self.get(ptr.alloc_id)?;
         if !alloc.undef_mask.is_range_defined(
             ptr.offset,
@@ -892,10 +895,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn mark_definedness(
         &mut self,
         ptr: Pointer,
-        size: u64,
+        size: Size,
         new_state: bool,
     ) -> EvalResult<'tcx> {
-        if size == 0 {
+        if size.bytes() == 0 {
             return Ok(());
         }
         let ptr = ptr.to_ptr()?;
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 883b17b8584..6ccbcf07370 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -1,6 +1,6 @@
 use rustc::mir;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
+use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size};
 use rustc_data_structures::indexed_vec::Idx;
 
 use rustc::mir::interpret::{GlobalId, Value, PrimVal, EvalResult, Pointer, MemoryPointer};
@@ -210,7 +210,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 };
                 let alloc = Machine::init_static(self, cid)?;
                 Place::Ptr {
-                    ptr: MemoryPointer::new(alloc, 0).into(),
+                    ptr: MemoryPointer::new(alloc, Size::from_bytes(0)).into(),
                     align: layout.align,
                     extra: PlaceExtra::None,
                 }
@@ -267,9 +267,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     base_layout.ty,
                     base_ptr.to_value_with_vtable(tab),
                 )?;
-                offset.abi_align(align).bytes()
+                offset.abi_align(align)
             }
-            _ => offset.bytes(),
+            _ => offset,
         };
 
         let ptr = base_ptr.offset(offset, &self)?;
@@ -325,14 +325,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         let (base_ptr, align) = base.to_ptr_align();
 
         let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx);
-        let elem_size = self.layout_of(elem_ty)?.size.bytes();
+        let elem_size = self.layout_of(elem_ty)?.size;
         assert!(
             n < len,
             "Tried to access element {} of array/slice with length {}",
             n,
             len
         );
-        let ptr = base_ptr.offset(n * elem_size, &*self)?;
+        let ptr = base_ptr.offset(elem_size * n, &*self)?;
         Ok(Place::Ptr {
             ptr,
             align,
@@ -401,7 +401,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let (base_ptr, align) = base.to_ptr_align();
 
                 let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
-                let elem_size = self.layout_of(elem_ty)?.size.bytes();
+                let elem_size = self.layout_of(elem_ty)?.size;
                 assert!(n >= min_length as u64);
 
                 let index = if from_end {
@@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     u64::from(offset)
                 };
 
-                let ptr = base_ptr.offset(index * elem_size, &self)?;
+                let ptr = base_ptr.offset(elem_size * index, &self)?;
                 Ok(Place::Ptr { ptr, align, extra: PlaceExtra::None })
             }
 
@@ -420,9 +420,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let (base_ptr, align) = base.to_ptr_align();
 
                 let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
-                let elem_size = self.layout_of(elem_ty)?.size.bytes();
+                let elem_size = self.layout_of(elem_ty)?.size;
                 assert!(u64::from(from) <= n - u64::from(to));
-                let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
+                let ptr = base_ptr.offset(elem_size * u64::from(from), &self)?;
                 // sublicing arrays produces arrays
                 let extra = if self.type_is_sized(base_ty) {
                     PlaceExtra::None
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index c61487f106b..c5b823ca87b 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -341,7 +341,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                                     Value::ByRef(ptr, align) => {
                                         for (i, arg_local) in arg_locals.enumerate() {
                                             let field = layout.field(&self, i)?;
-                                            let offset = layout.fields.offset(i).bytes();
+                                            let offset = layout.fields.offset(i);
                                             let arg = Value::ByRef(ptr.offset(offset, &self)?,
                                                                    align.min(field.align));
                                             let dest =
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index ecced1b8168..3bf9453fb51 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -24,17 +24,15 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
 #![feature(decl_macro)]
-#![cfg_attr(stage0, feature(dyn_trait))]
 #![feature(fs_read_write)]
 #![feature(macro_vis_matcher)]
 #![feature(exhaustive_patterns)]
 #![feature(range_contains)]
 #![feature(rustc_diagnostic_macros)]
-#![feature(inclusive_range_methods)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
 #![feature(specialization)]
-#![cfg_attr(stage0, feature(try_trait))]
+#![feature(try_trait)]
 
 extern crate arena;
 #[macro_use]
@@ -54,16 +52,6 @@ extern crate log_settings;
 extern crate rustc_apfloat;
 extern crate byteorder;
 
-#[cfg(stage0)]
-macro_rules! do_catch {
-  ($t:expr) => { (|| ::std::ops::Try::from_ok($t) )() }
-}
-
-#[cfg(not(stage0))]
-macro_rules! do_catch {
-  ($t:expr) => { do catch { $t } }
-}
-
 mod diagnostics;
 
 mod borrow_check;
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index c62eb1cf185..100edd6b4ff 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1249,7 +1249,7 @@ fn collect_const<'a, 'tcx>(
         ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
         ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
             collect_miri(tcx, ptr.alloc_id, output),
-        ConstVal::Value(ConstValue::ByRef(alloc)) => {
+        ConstVal::Value(ConstValue::ByRef(alloc, _offset)) => {
             for &id in alloc.relocations.values() {
                 collect_miri(tcx, id, output);
             }
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index b732eeb624c..5af19ab3646 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -25,14 +25,12 @@
 use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
 use rustc::mir::traversal::ReversePostorder;
-use rustc::ty::TyCtxt;
+use rustc::ty::{self, TyCtxt};
 use syntax_pos::Span;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
-use std::iter;
-use std::mem;
-use std::usize;
+use std::{cmp, iter, mem, usize};
 
 /// State of a temporary during collection and promotion.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -150,9 +148,11 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, T
 }
 
 struct Promoter<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     source: &'a mut Mir<'tcx>,
     promoted: Mir<'tcx>,
     temps: &'a mut IndexVec<Local, TempState>,
+    extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -288,38 +288,90 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
     }
 
     fn promote_candidate(mut self, candidate: Candidate) {
-        let span = self.promoted.span;
-        let new_operand = Operand::Constant(box Constant {
-            span,
-            ty: self.promoted.return_ty(),
-            literal: Literal::Promoted {
+        let mut rvalue = {
+            let promoted = &mut self.promoted;
+            let literal = Literal::Promoted {
                 index: Promoted::new(self.source.promoted.len())
-            }
-        });
-        let mut rvalue = match candidate {
-            Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
-                let ref mut statement = self.source[bb].statements[stmt_idx];
-                match statement.kind {
-                    StatementKind::Assign(_, ref mut rvalue) => {
-                        mem::replace(rvalue, Rvalue::Use(new_operand))
+            };
+            let operand = |ty, span| {
+                promoted.span = span;
+                promoted.local_decls[RETURN_PLACE] =
+                    LocalDecl::new_return_place(ty, span);
+                Operand::Constant(box Constant {
+                    span,
+                    ty,
+                    literal
+                })
+            };
+            let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
+            match candidate {
+                Candidate::Ref(loc) => {
+                    let ref mut statement = blocks[loc.block].statements[loc.statement_index];
+                    match statement.kind {
+                        StatementKind::Assign(_, Rvalue::Ref(r, bk, ref mut place)) => {
+                            // Find the underlying local for this (necessarilly interior) borrow.
+                            // HACK(eddyb) using a recursive function because of mutable borrows.
+                            fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>)
+                                                       -> &'a mut Place<'tcx> {
+                                if let Place::Projection(ref mut proj) = *place {
+                                    assert_ne!(proj.elem, ProjectionElem::Deref);
+                                    return interior_base(&mut proj.base);
+                                }
+                                place
+                            }
+                            let place = interior_base(place);
+
+                            let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx);
+                            let ref_ty = self.tcx.mk_ref(r,
+                                ty::TypeAndMut {
+                                    ty,
+                                    mutbl: bk.to_mutbl_lossy()
+                                }
+                            );
+                            let span = statement.source_info.span;
+
+                            // Create a temp to hold the promoted reference.
+                            // This is because `*r` requires `r` to be a local,
+                            // otherwise we would use the `promoted` directly.
+                            let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
+                            promoted_ref.source_info = statement.source_info;
+                            let promoted_ref = local_decls.push(promoted_ref);
+                            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+                            self.extra_statements.push((loc, Statement {
+                                source_info: statement.source_info,
+                                kind: StatementKind::Assign(
+                                    Place::Local(promoted_ref),
+                                    Rvalue::Use(operand(ref_ty, span)),
+                                )
+                            }));
+                            let promoted_place = Place::Local(promoted_ref).deref();
+
+                            Rvalue::Ref(r, bk, mem::replace(place, promoted_place))
+                        }
+                        _ => bug!()
                     }
-                    _ => bug!()
                 }
-            }
-            Candidate::Argument { bb, index } => {
-                match self.source[bb].terminator_mut().kind {
-                    TerminatorKind::Call { ref mut args, .. } => {
-                        Rvalue::Use(mem::replace(&mut args[index], new_operand))
+                Candidate::Argument { bb, index } => {
+                    let terminator = blocks[bb].terminator_mut();
+                    match terminator.kind {
+                        TerminatorKind::Call { ref mut args, .. } => {
+                            let ty = args[index].ty(local_decls, self.tcx);
+                            let span = terminator.source_info.span;
+                            Rvalue::Use(mem::replace(&mut args[index], operand(ty, span)))
+                        }
+                        _ => bug!()
                     }
-                    _ => bug!()
                 }
             }
         };
+
+        assert_eq!(self.new_block(), START_BLOCK);
         self.visit_rvalue(&mut rvalue, Location {
             block: BasicBlock::new(0),
             statement_index: usize::MAX
         });
 
+        let span = self.promoted.span;
         self.assign(RETURN_PLACE, rvalue, span);
         self.source.promoted.push(self.promoted);
     }
@@ -343,43 +395,29 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                     candidates: Vec<Candidate>) {
     // Visit candidates in reverse, in case they're nested.
     debug!("promote_candidates({:?})", candidates);
+
+    let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
-        let (span, ty) = match candidate {
-            Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
-                let statement = &mir[bb].statements[stmt_idx];
-                let dest = match statement.kind {
-                    StatementKind::Assign(ref dest, _) => dest,
-                    _ => {
-                        span_bug!(statement.source_info.span,
-                                  "expected assignment to promote");
-                    }
-                };
-                if let Place::Local(index) = *dest {
-                    if temps[index] == TempState::PromotedOut {
-                        // Already promoted.
-                        continue;
+        match candidate {
+            Candidate::Ref(Location { block, statement_index }) => {
+                match mir[block].statements[statement_index].kind {
+                    StatementKind::Assign(Place::Local(local), _) => {
+                        if temps[local] == TempState::PromotedOut {
+                            // Already promoted.
+                            continue;
+                        }
                     }
+                    _ => {}
                 }
-                (statement.source_info.span, dest.ty(mir, tcx).to_ty(tcx))
-            }
-            Candidate::Argument { bb, index } => {
-                let terminator = mir[bb].terminator();
-                let ty = match terminator.kind {
-                    TerminatorKind::Call { ref args, .. } => {
-                        args[index].ty(mir, tcx)
-                    }
-                    _ => {
-                        span_bug!(terminator.source_info.span,
-                                  "expected call argument to promote");
-                    }
-                };
-                (terminator.source_info.span, ty)
             }
-        };
+            Candidate::Argument { .. } => {}
+        }
+
 
-        // Declare return place local
-        let initial_locals = iter::once(LocalDecl::new_return_place(ty, span))
-            .collect();
+        // Declare return place local so that `Mir::new` doesn't complain.
+        let initial_locals = iter::once(
+            LocalDecl::new_return_place(tcx.types.never, mir.span)
+        ).collect();
 
         let mut promoter = Promoter {
             promoted: Mir::new(
@@ -393,16 +431,24 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                 initial_locals,
                 0,
                 vec![],
-                span
+                mir.span
             ),
+            tcx,
             source: mir,
             temps: &mut temps,
+            extra_statements: &mut extra_statements,
             keep_original: false
         };
-        assert_eq!(promoter.new_block(), START_BLOCK);
         promoter.promote_candidate(candidate);
     }
 
+    // Insert each of `extra_statements` before its indicated location, which
+    // has to be done in reverse location order, to not invalidate the rest.
+    extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc));
+    for (loc, statement) in extra_statements {
+        mir[loc.block].statements.insert(loc.statement_index, statement);
+    }
+
     // Eliminate assignments to, and drops of promoted temps.
     let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in mir.basic_blocks_mut() {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 28ab3d6a857..fd4ba1d7562 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -229,12 +229,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
     }
 
     /// Check if a Local with the current qualifications is promotable.
-    fn can_promote(&mut self) -> bool {
+    fn can_promote(&self, qualif: Qualif) -> bool {
         // References to statics are allowed, but only in other statics.
         if self.mode == Mode::Static || self.mode == Mode::StaticMut {
-            (self.qualif - Qualif::STATIC_REF).is_empty()
+            (qualif - Qualif::STATIC_REF).is_empty()
         } else {
-            self.qualif.is_empty()
+            qualif.is_empty()
         }
     }
 
@@ -679,24 +679,31 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 }
 
                 let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
+
+                // Default to forbidding the borrow and/or its promotion,
+                // due to the potential for direct or interior mutability,
+                // and only proceed by setting `forbidden_mut` to `false`.
+                let mut forbidden_mut = true;
+
                 if let BorrowKind::Mut { .. } = kind {
                     // In theory, any zero-sized value could be borrowed
                     // mutably without consequences. However, only &mut []
                     // is allowed right now, and only in functions.
-                    let allow = if self.mode == Mode::StaticMut {
+                    if self.mode == Mode::StaticMut {
                         // Inside a `static mut`, &mut [...] is also allowed.
                         match ty.sty {
-                            ty::TyArray(..) | ty::TySlice(_) => true,
-                            _ => false
+                            ty::TyArray(..) | ty::TySlice(_) => forbidden_mut = false,
+                            _ => {}
                         }
                     } else if let ty::TyArray(_, len) = ty.sty {
-                        len.unwrap_usize(self.tcx) == 0 &&
-                            self.mode == Mode::Fn
-                    } else {
-                        false
-                    };
+                        // FIXME(eddyb) the `self.mode == Mode::Fn` condition
+                        // seems unnecessary, given that this is merely a ZST.
+                        if len.unwrap_usize(self.tcx) == 0 && self.mode == Mode::Fn {
+                            forbidden_mut = false;
+                        }
+                    }
 
-                    if !allow {
+                    if forbidden_mut {
                         self.add(Qualif::NOT_CONST);
                         if self.mode != Mode::Fn {
                             let mut err = struct_span_err!(self.tcx.sess,  self.span, E0017,
@@ -722,25 +729,46 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     // it means that our "silent insertion of statics" could change
                     // initializer values (very bad).
                     if self.qualif.intersects(Qualif::MUTABLE_INTERIOR) {
-                        // Replace MUTABLE_INTERIOR with NOT_CONST to avoid
+                        // A reference of a MUTABLE_INTERIOR place is instead
+                        // NOT_CONST (see `if forbidden_mut` below), to avoid
                         // duplicate errors (from reborrowing, for example).
                         self.qualif = self.qualif - Qualif::MUTABLE_INTERIOR;
-                        self.add(Qualif::NOT_CONST);
                         if self.mode != Mode::Fn {
                             span_err!(self.tcx.sess, self.span, E0492,
                                       "cannot borrow a constant which may contain \
                                        interior mutability, create a static instead");
                         }
+                    } else {
+                        // We allow immutable borrows of frozen data.
+                        forbidden_mut = false;
                     }
                 }
 
-                // We might have a candidate for promotion.
-                let candidate = Candidate::Ref(location);
-                if self.can_promote() {
-                    // We can only promote direct borrows of temps.
+                if forbidden_mut {
+                    self.add(Qualif::NOT_CONST);
+                } else {
+                    // We might have a candidate for promotion.
+                    let candidate = Candidate::Ref(location);
+                    // We can only promote interior borrows of promotable temps.
+                    let mut place = place;
+                    while let Place::Projection(ref proj) = *place {
+                        if proj.elem == ProjectionElem::Deref {
+                            break;
+                        }
+                        place = &proj.base;
+                    }
                     if let Place::Local(local) = *place {
                         if self.mir.local_kind(local) == LocalKind::Temp {
-                            self.promotion_candidates.push(candidate);
+                            if let Some(qualif) = self.temp_qualif[local] {
+                                // `forbidden_mut` is false, so we can safely ignore
+                                // `MUTABLE_INTERIOR` from the local's qualifications.
+                                // This allows borrowing fields which don't have
+                                // `MUTABLE_INTERIOR`, from a type that does, e.g.:
+                                // `let _: &'static _ = &(Cell::new(1), 2).1;`
+                                if self.can_promote(qualif - Qualif::MUTABLE_INTERIOR) {
+                                    self.promotion_candidates.push(candidate);
+                                }
+                            }
                         }
                     }
                 }
@@ -897,7 +925,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                     }
                     let candidate = Candidate::Argument { bb, index: i };
                     if is_shuffle && i == 2 {
-                        if this.can_promote() {
+                        if this.can_promote(this.qualif) {
                             this.promotion_candidates.push(candidate);
                         } else {
                             span_err!(this.tcx.sess, this.span, E0526,
@@ -913,7 +941,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                     if !constant_arguments.contains(&i) {
                         return
                     }
-                    if this.can_promote() {
+                    if this.can_promote(this.qualif) {
                         this.promotion_candidates.push(candidate);
                     } else {
                         this.tcx.sess.span_err(this.span,
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 9d74ad0830f..9e1ce9b2851 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -137,7 +137,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
 ) where
     F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
 {
-    let _: io::Result<()> = do_catch! {{
+    let _: io::Result<()> = do catch {
         let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?;
         writeln!(file, "// MIR for `{}`", node_path)?;
         writeln!(file, "// source = {:?}", source)?;
@@ -150,14 +150,14 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
         extra_data(PassWhere::BeforeCFG, &mut file)?;
         write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?;
         extra_data(PassWhere::AfterCFG, &mut file)?;
-    }};
+    };
 
     if tcx.sess.opts.debugging_opts.dump_mir_graphviz {
-        let _: io::Result<()> = do_catch! {{
+        let _: io::Result<()> = do catch {
             let mut file =
                 create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
             write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?;
-        }};
+        };
     }
 }
 
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 4789e2e50ca..4f239a0868e 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -21,7 +21,6 @@ use rustc::session::Session;
 use syntax::ast::*;
 use syntax::attr;
 use syntax::codemap::Spanned;
-use syntax::parse::token;
 use syntax::symbol::keywords;
 use syntax::visit::{self, Visitor};
 use syntax_pos::Span;
@@ -40,14 +39,13 @@ impl<'a> AstValidator<'a> {
         let valid_names = [keywords::UnderscoreLifetime.name(),
                            keywords::StaticLifetime.name(),
                            keywords::Invalid.name()];
-        if !valid_names.contains(&ident.name) &&
-            token::is_reserved_ident(ident.without_first_quote()) {
+        if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
             self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
         }
     }
 
     fn check_label(&self, ident: Ident) {
-        if token::is_reserved_ident(ident.without_first_quote()) {
+        if ident.without_first_quote().is_reserved() {
             self.err_handler()
                 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
         }
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 2368b1aca69..ac37937509e 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -89,6 +89,8 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 self.with_context(LabeledBlock, |v| v.visit_block(&b));
             }
             hir::ExprBreak(label, ref opt_expr) => {
+                opt_expr.as_ref().map(|e| self.visit_expr(e));
+
                 if self.require_label_in_labeled_block(e.span, &label, "break") {
                     // If we emitted an error about an unlabeled break in a labeled
                     // block, we don't need any further checking for this break any more
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index 7e3c411c1d2..ea15f4c75b9 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -15,6 +15,7 @@ use rustc::session::Session;
 
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
 use syntax::ext::base::MacroExpanderFn;
+use syntax::ext::hygiene;
 use syntax::symbol::Symbol;
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
@@ -107,7 +108,8 @@ impl<'a> Registry<'a> {
                 def_info: _,
                 allow_internal_unstable,
                 allow_internal_unsafe,
-                unstable_feature
+                unstable_feature,
+                edition,
             } => {
                 let nid = ast::CRATE_NODE_ID;
                 NormalTT {
@@ -115,7 +117,8 @@ impl<'a> Registry<'a> {
                     def_info: Some((nid, self.krate_span)),
                     allow_internal_unstable,
                     allow_internal_unsafe,
-                    unstable_feature
+                    unstable_feature,
+                    edition,
                 }
             }
             IdentTT(ext, _, allow_internal_unstable) => {
@@ -150,6 +153,7 @@ impl<'a> Registry<'a> {
             allow_internal_unstable: false,
             allow_internal_unsafe: false,
             unstable_feature: None,
+            edition: hygiene::default_edition(),
         });
     }
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index ef5cc958283..d3cc533cd36 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -588,7 +588,8 @@ impl<'a> Resolver<'a> {
 
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
                                                &self.session.features_untracked(),
-                                               &macro_def));
+                                               &macro_def,
+                                               self.cstore.crate_edition_untracked(def_id.krate)));
         self.macro_map.insert(def_id, ext.clone());
         ext
     }
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index 163f6a64010..590ce168d5d 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -142,6 +142,10 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
         }
     }
 
+    for (id, span) in resolver.unused_labels.iter() {
+        resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
+    }
+
     let mut visitor = UnusedImportCheckVisitor {
         resolver,
         unused_imports: NodeMap(),
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 5a5f5ce2e38..bc5d50491ad 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -58,7 +58,6 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
 use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
 use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 use syntax::feature_gate::{feature_err, GateIssue};
-use syntax::parse::token;
 use syntax::ptr::P;
 
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
@@ -1225,12 +1224,10 @@ enum NameBindingKind<'a> {
         binding: &'a NameBinding<'a>,
         directive: &'a ImportDirective<'a>,
         used: Cell<bool>,
-        legacy_self_import: bool,
     },
     Ambiguity {
         b1: &'a NameBinding<'a>,
         b2: &'a NameBinding<'a>,
-        legacy: bool,
     }
 }
 
@@ -1252,7 +1249,6 @@ struct AmbiguityError<'a> {
     lexical: bool,
     b1: &'a NameBinding<'a>,
     b2: &'a NameBinding<'a>,
-    legacy: bool,
 }
 
 impl<'a> NameBinding<'a> {
@@ -1260,7 +1256,6 @@ impl<'a> NameBinding<'a> {
         match self.kind {
             NameBindingKind::Module(module) => Some(module),
             NameBindingKind::Import { binding, .. } => binding.module(),
-            NameBindingKind::Ambiguity { legacy: true, b1, .. } => b1.module(),
             _ => None,
         }
     }
@@ -1270,7 +1265,6 @@ impl<'a> NameBinding<'a> {
             NameBindingKind::Def(def) => def,
             NameBindingKind::Module(module) => module.def().unwrap(),
             NameBindingKind::Import { binding, .. } => binding.def(),
-            NameBindingKind::Ambiguity { legacy: true, b1, .. } => b1.def(),
             NameBindingKind::Ambiguity { .. } => Def::Err,
         }
     }
@@ -1474,6 +1468,10 @@ pub struct Resolver<'a> {
     pub maybe_unused_trait_imports: NodeSet,
     pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
 
+    /// A list of labels as of yet unused. Labels will be removed from this map when
+    /// they are used (in a `break` or `continue` statement)
+    pub unused_labels: FxHashMap<NodeId, Span>,
+
     /// privacy errors are delayed until the end in order to deduplicate them
     privacy_errors: Vec<PrivacyError<'a>>,
     /// ambiguity errors are delayed for deduplication
@@ -1753,6 +1751,8 @@ impl<'a> Resolver<'a> {
             maybe_unused_trait_imports: NodeSet(),
             maybe_unused_extern_crates: Vec::new(),
 
+            unused_labels: FxHashMap(),
+
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
             use_injections: Vec::new(),
@@ -1853,27 +1853,20 @@ impl<'a> Resolver<'a> {
     fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
                   -> bool /* true if an error was reported */ {
         match binding.kind {
-            NameBindingKind::Import { directive, binding, ref used, legacy_self_import }
+            NameBindingKind::Import { directive, binding, ref used }
                     if !used.get() => {
                 used.set(true);
                 directive.used.set(true);
-                if legacy_self_import {
-                    self.warn_legacy_self_import(directive);
-                    return false;
-                }
                 self.used_imports.insert((directive.id, ns));
                 self.add_to_glob_map(directive.id, ident);
                 self.record_use(ident, ns, binding, span)
             }
             NameBindingKind::Import { .. } => false,
-            NameBindingKind::Ambiguity { b1, b2, legacy } => {
+            NameBindingKind::Ambiguity { b1, b2 } => {
                 self.ambiguity_errors.push(AmbiguityError {
-                    span: span, name: ident.name, lexical: false, b1: b1, b2: b2, legacy,
+                    span, name: ident.name, lexical: false, b1, b2,
                 });
-                if legacy {
-                    self.record_use(ident, ns, b1, span);
-                }
-                !legacy
+                true
             }
             _ => false
         }
@@ -3274,7 +3267,7 @@ impl<'a> Resolver<'a> {
                     // `$crate::a::b`
                     module = Some(self.resolve_crate_root(ident.span.ctxt(), true));
                     continue
-                } else if i == 1 && !token::is_path_segment_keyword(ident) {
+                } else if i == 1 && !ident.is_path_segment_keyword() {
                     let prev_name = path[0].name;
                     if prev_name == keywords::Extern.name() ||
                        prev_name == keywords::CrateRoot.name() &&
@@ -3695,6 +3688,7 @@ impl<'a> Resolver<'a> {
         where F: FnOnce(&mut Resolver)
     {
         if let Some(label) = label {
+            self.unused_labels.insert(id, label.ident.span);
             let def = Def::Label(id);
             self.with_label_rib(|this| {
                 this.label_ribs.last_mut().unwrap().bindings.insert(label.ident, def);
@@ -3743,9 +3737,10 @@ impl<'a> Resolver<'a> {
                                       ResolutionError::UndeclaredLabel(&label.ident.name.as_str(),
                                                                        close_match));
                     }
-                    Some(def @ Def::Label(_)) => {
+                    Some(Def::Label(id)) => {
                         // Since this def is a label, it is never read.
-                        self.record_def(expr.id, PathResolution::new(def));
+                        self.record_def(expr.id, PathResolution::new(Def::Label(id)));
+                        self.unused_labels.remove(&id);
                     }
                     Some(_) => {
                         span_bug!(expr.span, "label wasn't mapped to a label def!");
@@ -4129,7 +4124,7 @@ impl<'a> Resolver<'a> {
         self.report_proc_macro_import(krate);
         let mut reported_spans = FxHashSet();
 
-        for &AmbiguityError { span, name, b1, b2, lexical, legacy } in &self.ambiguity_errors {
+        for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
             if !reported_spans.insert(span) { continue }
             let participle = |binding: &NameBinding| {
                 if binding.is_import() { "imported" } else { "defined" }
@@ -4145,27 +4140,15 @@ impl<'a> Resolver<'a> {
                 format!("macro-expanded {} do not shadow when used in a macro invocation path",
                         if b1.is_import() { "imports" } else { "items" })
             };
-            if legacy {
-                let id = match b2.kind {
-                    NameBindingKind::Import { directive, .. } => directive.id,
-                    _ => unreachable!(),
-                };
-                let mut span = MultiSpan::from_span(span);
-                span.push_span_label(b1.span, msg1);
-                span.push_span_label(b2.span, msg2);
-                let msg = format!("`{}` is ambiguous", name);
-                self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, &msg);
-            } else {
-                let mut err =
-                    struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
-                err.span_note(b1.span, &msg1);
-                match b2.def() {
-                    Def::Macro(..) if b2.span == DUMMY_SP =>
-                        err.note(&format!("`{}` is also a builtin macro", name)),
-                    _ => err.span_note(b2.span, &msg2),
-                };
-                err.note(&note).emit();
-            }
+
+            let mut err = struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
+            err.span_note(b1.span, &msg1);
+            match b2.def() {
+                Def::Macro(..) if b2.span == DUMMY_SP =>
+                    err.note(&format!("`{}` is also a builtin macro", name)),
+                _ => err.span_note(b2.span, &msg2),
+            };
+            err.note(&note).emit();
         }
 
         for &PrivacyError(span, name, binding) in &self.privacy_errors {
@@ -4316,12 +4299,6 @@ impl<'a> Resolver<'a> {
         self.name_already_seen.insert(name, span);
     }
 
-    fn warn_legacy_self_import(&self, directive: &'a ImportDirective<'a>) {
-        let (id, span) = (directive.id, directive.span);
-        let msg = "`self` no longer imports values";
-        self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
-    }
-
     fn check_proc_macro_attrs(&mut self, attrs: &[ast::Attribute]) {
         if self.proc_macro_enabled { return; }
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 4afc621ad8b..57d7b1fac48 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -24,7 +24,7 @@ use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
 use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
 use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc};
-use syntax::ext::hygiene::{Mark, MarkKind};
+use syntax::ext::hygiene::{self, Mark, MarkKind};
 use syntax::ext::placeholders::placeholder;
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{self, emit_feature_err, GateIssue};
@@ -328,7 +328,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         for did in self.unused_macros.iter() {
             let id_span = match *self.macro_map[did] {
                 SyntaxExtension::NormalTT { def_info, .. } => def_info,
-                SyntaxExtension::DeclMacro(.., osp) => osp,
+                SyntaxExtension::DeclMacro(.., osp, _) => osp,
                 _ => None,
             };
             if let Some((id, span)) = id_span {
@@ -371,7 +371,7 @@ impl<'a> Resolver<'a> {
         };
         for path in traits {
             match self.resolve_macro(scope, path, MacroKind::Derive, force) {
-                Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
+                Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
                     if inert_attrs.contains(&attr_name) {
                         // FIXME(jseyfried) Avoid `mem::replace` here.
                         let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
@@ -528,7 +528,6 @@ impl<'a> Resolver<'a> {
                                 b1: shadower,
                                 b2: binding,
                                 lexical: true,
-                                legacy: false,
                             });
                             return potential_illegal_shadower;
                         }
@@ -755,7 +754,7 @@ impl<'a> Resolver<'a> {
         let def_id = self.definitions.local_def_id(item.id);
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
                                                &self.session.features_untracked(),
-                                               item));
+                                               item, hygiene::default_edition()));
         self.macro_map.insert(def_id, ext);
 
         let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
@@ -803,14 +802,15 @@ impl<'a> Resolver<'a> {
 
         match *ext {
             // If `ext` is a procedural macro, check if we've already warned about it
-            AttrProcMacro(_) | ProcMacro(_) => if !self.warned_proc_macros.insert(name) { return; },
+            AttrProcMacro(..) | ProcMacro(..) =>
+                if !self.warned_proc_macros.insert(name) { return; },
             _ => return,
         }
 
         let warn_msg = match *ext {
-            AttrProcMacro(_) => "attribute procedural macros cannot be \
-                                 imported with `#[macro_use]`",
-            ProcMacro(_) => "procedural macros cannot be imported with `#[macro_use]`",
+            AttrProcMacro(..) => "attribute procedural macros cannot be \
+                                  imported with `#[macro_use]`",
+            ProcMacro(..) => "procedural macros cannot be imported with `#[macro_use]`",
             _ => return,
         };
 
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 09c421fba47..cf1fc7675fe 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -27,7 +27,6 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use syntax::ast::{Ident, Name, NodeId};
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::hygiene::Mark;
-use syntax::parse::token;
 use syntax::symbol::keywords;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
@@ -179,7 +178,6 @@ impl<'a> Resolver<'a> {
                             lexical: false,
                             b1: binding,
                             b2: shadowed_glob,
-                            legacy: false,
                         });
                     }
                 }
@@ -351,7 +349,6 @@ impl<'a> Resolver<'a> {
                 binding,
                 directive,
                 used: Cell::new(false),
-                legacy_self_import: false,
             },
             span: directive.span,
             vis,
@@ -400,7 +397,7 @@ impl<'a> Resolver<'a> {
     pub fn ambiguity(&self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
                      -> &'a NameBinding<'a> {
         self.arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: false },
+            kind: NameBindingKind::Ambiguity { b1, b2 },
             vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis },
             span: b1.span,
             expansion: Mark::root(),
@@ -667,7 +664,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                         } else {
                             Some(self.resolve_crate_root(source.span.ctxt().modern(), false))
                         }
-                    } else if is_extern && !token::is_path_segment_keyword(source) {
+                    } else if is_extern && !source.is_path_segment_keyword() {
                         let crate_id =
                             self.resolver.crate_loader.process_use_extern(
                                 source.name,
@@ -692,7 +689,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                                 binding,
                                 directive,
                                 used: Cell::new(false),
-                                legacy_self_import: false,
                             },
                             vis: directive.vis.get(),
                             span: directive.span,
@@ -715,8 +711,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             }
             PathResult::Failed(span, msg, true) => {
                 let (mut self_path, mut self_result) = (module_path.clone(), None);
-                let is_special = |ident| token::is_path_segment_keyword(ident) &&
-                                         ident.name != keywords::CrateRoot.name();
+                let is_special = |ident: Ident| ident.is_path_segment_keyword() &&
+                                                ident.name != keywords::CrateRoot.name();
                 if !self_path.is_empty() && !is_special(self_path[0]) &&
                    !(self_path.len() > 1 && is_special(self_path[1])) {
                     self_path[0].name = keywords::SelfValue.name();
@@ -752,7 +748,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         };
 
         let mut all_ns_err = true;
-        let mut legacy_self_import = None;
         self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
             if let Ok(binding) = result[ns].get() {
                 all_ns_err = false;
@@ -761,30 +756,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                         Some(this.dummy_binding);
                 }
             }
-        } else if let Ok(binding) = this.resolve_ident_in_module(module,
-                                                                 ident,
-                                                                 ns,
-                                                                 false,
-                                                                 false,
-                                                                 directive.span) {
-            legacy_self_import = Some(directive);
-            let binding = this.arenas.alloc_name_binding(NameBinding {
-                kind: NameBindingKind::Import {
-                    binding,
-                    directive,
-                    used: Cell::new(false),
-                    legacy_self_import: true,
-                },
-                ..*binding
-            });
-            let _ = this.try_define(directive.parent, ident, ns, binding);
         });
 
         if all_ns_err {
-            if let Some(directive) = legacy_self_import {
-                self.warn_legacy_self_import(directive);
-                return None;
-            }
             let mut all_ns_failed = true;
             self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
                 match this.resolve_ident_in_module(module, ident, ns, false, true, span) {
@@ -1051,23 +1025,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                             err.emit();
                     }
                 }
-                NameBindingKind::Ambiguity { b1, b2, .. }
-                        if b1.is_glob_import() && b2.is_glob_import() => {
-                    let (orig_b1, orig_b2) = match (&b1.kind, &b2.kind) {
-                        (&NameBindingKind::Import { binding: b1, .. },
-                         &NameBindingKind::Import { binding: b2, .. }) => (b1, b2),
-                        _ => continue,
-                    };
-                    let (b1, b2) = match (orig_b1.vis, orig_b2.vis) {
-                        (ty::Visibility::Public, ty::Visibility::Public) => continue,
-                        (ty::Visibility::Public, _) => (b1, b2),
-                        (_, ty::Visibility::Public) => (b2, b1),
-                        _ => continue,
-                    };
-                    resolution.binding = Some(self.arenas.alloc_name_binding(NameBinding {
-                        kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: true }, ..*b1
-                    }));
-                }
                 _ => {}
             }
         }
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 6cd8e267ec5..2075400d04f 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -221,7 +221,7 @@ pub enum Endian {
 }
 
 /// Size of a type in bytes.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct Size {
     raw: u64
 }
diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs
index 45f2ee13bbd..8f491157439 100644
--- a/src/librustc_target/lib.rs
+++ b/src/librustc_target/lib.rs
@@ -29,7 +29,6 @@
 #![feature(const_fn)]
 #![feature(fs_read_write)]
 #![feature(inclusive_range)]
-#![feature(inclusive_range_methods)]
 #![feature(slice_patterns)]
 
 #[macro_use]
diff --git a/src/librustc_target/spec/linux_musl_base.rs b/src/librustc_target/spec/linux_musl_base.rs
index 4594d450c15..293f23eab38 100644
--- a/src/librustc_target/spec/linux_musl_base.rs
+++ b/src/librustc_target/spec/linux_musl_base.rs
@@ -15,8 +15,7 @@ pub fn opts() -> TargetOptions {
 
     // Make sure that the linker/gcc really don't pull in anything, including
     // default objects, libs, etc.
-    base.pre_link_args_crt.insert(LinkerFlavor::Gcc, Vec::new());
-    base.pre_link_args_crt.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
 
     // At least when this was tested, the linker would not add the
     // `GNU_EH_FRAME` program header to executables generated, which is required
@@ -56,11 +55,9 @@ pub fn opts() -> TargetOptions {
     //
     // Each target directory for musl has these object files included in it so
     // they'll be included from there.
-    base.pre_link_objects_exe_crt.push("crt1.o".to_string());
-    base.pre_link_objects_exe_crt.push("crti.o".to_string());
-    base.pre_link_objects_exe_crt_sys.push("crtbegin.o".to_string());
-    base.post_link_objects_crt_sys.push("crtend.o".to_string());
-    base.post_link_objects_crt.push("crtn.o".to_string());
+    base.pre_link_objects_exe.push("crt1.o".to_string());
+    base.pre_link_objects_exe.push("crti.o".to_string());
+    base.post_link_objects.push("crtn.o".to_string());
 
     // These targets statically link libc by default
     base.crt_static_default = true;
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index fb20fe9c891..0f870b5b957 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -422,26 +422,20 @@ pub struct TargetOptions {
     /// Linker to invoke
     pub linker: Option<String>,
 
-    /// Linker arguments that are passed *before* any user-defined libraries.
-    pub pre_link_args: LinkArgs, // ... unconditionally
-    pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
-    /// Objects to link before all others, all except *_sys found within the
+    /// Linker arguments that are unconditionally passed *before* any
+    /// user-defined libraries.
+    pub pre_link_args: LinkArgs,
+    /// Objects to link before all others, always found within the
     /// sysroot folder.
-    pub pre_link_objects_exe: Vec<String>, // ... when linking an executable, unconditionally
-    pub pre_link_objects_exe_crt: Vec<String>, // ... when linking an executable with a bundled crt
-    pub pre_link_objects_exe_crt_sys: Vec<String>, // ... when linking an executable with a bundled
-                                                   //  crt, from the system library search path
+    pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
     pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
     /// Linker arguments that are unconditionally passed after any
     /// user-defined but before post_link_objects.  Standard platform
     /// libraries that should be always be linked to, usually go here.
     pub late_link_args: LinkArgs,
-    /// Objects to link after all others, all except *_sys found within the
+    /// Objects to link after all others, always found within the
     /// sysroot folder.
-    pub post_link_objects: Vec<String>, // ... unconditionally
-    pub post_link_objects_crt: Vec<String>, // ... when linking with a bundled crt
-    pub post_link_objects_crt_sys: Vec<String>, // ... when linking with a bundled crt, from the
-                                                //  system library search path
+    pub post_link_objects: Vec<String>,
     /// Linker arguments that are unconditionally passed *after* any
     /// user-defined libraries.
     pub post_link_args: LinkArgs,
@@ -641,7 +635,6 @@ impl Default for TargetOptions {
             is_builtin: false,
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             pre_link_args: LinkArgs::new(),
-            pre_link_args_crt: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
             asm_args: Vec::new(),
             cpu: "generic".to_string(),
@@ -675,12 +668,8 @@ impl Default for TargetOptions {
             position_independent_executables: false,
             relro_level: RelroLevel::None,
             pre_link_objects_exe: Vec::new(),
-            pre_link_objects_exe_crt: Vec::new(),
-            pre_link_objects_exe_crt_sys: Vec::new(),
             pre_link_objects_dll: Vec::new(),
             post_link_objects: Vec::new(),
-            post_link_objects_crt: Vec::new(),
-            post_link_objects_crt_sys: Vec::new(),
             late_link_args: LinkArgs::new(),
             link_env: Vec::new(),
             archive_format: "gnu".to_string(),
@@ -899,15 +888,10 @@ impl Target {
         key!(is_builtin, bool);
         key!(linker, optional);
         key!(pre_link_args, link_args);
-        key!(pre_link_args_crt, link_args);
         key!(pre_link_objects_exe, list);
-        key!(pre_link_objects_exe_crt, list);
-        key!(pre_link_objects_exe_crt_sys, list);
         key!(pre_link_objects_dll, list);
         key!(late_link_args, link_args);
         key!(post_link_objects, list);
-        key!(post_link_objects_crt, list);
-        key!(post_link_objects_crt_sys, list);
         key!(post_link_args, link_args);
         key!(link_env, env);
         key!(asm_args, list);
@@ -1109,15 +1093,10 @@ impl ToJson for Target {
         target_option_val!(is_builtin);
         target_option_val!(linker);
         target_option_val!(link_args - pre_link_args);
-        target_option_val!(link_args - pre_link_args_crt);
         target_option_val!(pre_link_objects_exe);
-        target_option_val!(pre_link_objects_exe_crt);
-        target_option_val!(pre_link_objects_exe_crt_sys);
         target_option_val!(pre_link_objects_dll);
         target_option_val!(link_args - late_link_args);
         target_option_val!(post_link_objects);
-        target_option_val!(post_link_objects_crt);
-        target_option_val!(post_link_objects_crt_sys);
         target_option_val!(link_args - post_link_args);
         target_option_val!(env - link_env);
         target_option_val!(asm_args);
diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs
index 8fc00c937e6..a9ac53972e4 100644
--- a/src/librustc_traits/normalize_projection_ty.rs
+++ b/src/librustc_traits/normalize_projection_ty.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use rustc::infer::canonical::{Canonical, QueryResult};
-use rustc::traits::{self, FulfillmentContext, Normalized, ObligationCause,
-                    SelectionContext};
+use rustc::traits::{self, FulfillmentContext, ObligationCause, SelectionContext};
 use rustc::traits::query::{CanonicalProjectionGoal, NoSolution, normalize::NormalizationResult};
 use rustc::ty::{ParamEnvAnd, TyCtxt};
 use rustc_data_structures::sync::Lrc;
@@ -37,10 +36,9 @@ crate fn normalize_projection_ty<'tcx>(
         let fulfill_cx = &mut FulfillmentContext::new();
         let selcx = &mut SelectionContext::new(infcx);
         let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
-        let Normalized {
-            value: answer,
-            obligations,
-        } = traits::normalize_projection_type(selcx, param_env, goal, cause, 0);
+        let mut obligations = vec![];
+        let answer =
+            traits::normalize_projection_type(selcx, param_env, goal, cause, 0, &mut obligations);
         fulfill_cx.register_predicate_obligations(infcx, obligations);
 
         // Now that we have fulfilled as much as we can, create a solution
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index e1ce6073ce4..4274e5c1e1f 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -129,20 +129,20 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
         }
 
         let mut selcx = traits::SelectionContext::new(self.fcx);
-        let normalized = traits::normalize_projection_type(&mut selcx,
-                                                           self.fcx.param_env,
-                                                           ty::ProjectionTy::from_ref_and_name(
-                                                               tcx,
-                                                               trait_ref,
-                                                               Symbol::intern("Target"),
-                                                           ),
-                                                           cause,
-                                                           0);
-
-        debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized);
-        self.obligations.extend(normalized.obligations);
-
-        Some(self.fcx.resolve_type_vars_if_possible(&normalized.value))
+        let normalized_ty = traits::normalize_projection_type(&mut selcx,
+                                                              self.fcx.param_env,
+                                                              ty::ProjectionTy::from_ref_and_name(
+                                                                  tcx,
+                                                                  trait_ref,
+                                                                  Symbol::intern("Target"),
+                                                              ),
+                                                              cause,
+                                                              0,
+                                                              &mut self.obligations);
+
+        debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty);
+
+        Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty))
     }
 
     /// Returns the final type, generating an error if it is an
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index feb26e76162..af1f1044edf 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -314,11 +314,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
             }
 
-            "align_offset" => {
-                let ptr_ty = tcx.mk_imm_ptr(tcx.mk_nil());
-                (0, vec![ptr_ty, tcx.types.usize], tcx.types.usize)
-            },
-
             "nontemporal_store" => {
                 (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil())
             }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 99744d5b4b6..7a572bbbffd 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4519,6 +4519,32 @@ impl Foo for () {
 ```
 "##,
 
+E0646: r##"
+It is not possible to define `main` with a where clause.
+Erroneous code example:
+
+```compile_fail,E0646
+fn main() where i32: Copy { // error: main function is not allowed to have
+                            // a where clause
+}
+```
+"##,
+
+E0647: r##"
+It is not possible to define `start` with a where clause.
+Erroneous code example:
+
+```compile_fail,E0647
+#![feature(start)]
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize where (): Copy {
+    //^ error: start function is not allowed to have a where clause
+    0
+}
+```
+"##,
+
 E0689: r##"
 This error indicates that the numeric value for the method being passed exists
 but the type of the numeric value or binding could not be identified.
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 350b53a406b..ea48e839a7f 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -71,8 +71,6 @@ This API is completely unstable and subject to change.
 
 #![allow(non_camel_case_types)]
 
-#![cfg_attr(stage0, feature(dyn_trait))]
-
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
@@ -196,6 +194,12 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     .emit();
                                 return;
                             }
+                            if !generics.where_clause.predicates.is_empty() {
+                                struct_span_err!(tcx.sess, main_span, E0646,
+                                         "main function is not allowed to have a where clause")
+                                         .emit();
+                                return;
+                            }
                         }
                         _ => ()
                     }
@@ -247,14 +251,21 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             match tcx.hir.find(start_id) {
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
-                        hir::ItemFn(..,ref ps,_)
-                        if !ps.params.is_empty() => {
-                            struct_span_err!(tcx.sess, ps.span, E0132,
-                                "start function is not allowed to have type parameters")
-                                .span_label(ps.span,
-                                            "start function cannot have type parameters")
-                                .emit();
-                            return;
+                        hir::ItemFn(..,ref ps,_) => {
+                            if !ps.params.is_empty() {
+                                struct_span_err!(tcx.sess, ps.span, E0132,
+                                    "start function is not allowed to have type parameters")
+                                    .span_label(ps.span,
+                                                "start function cannot have type parameters")
+                                    .emit();
+                                return;
+                            }
+                            if !ps.where_clause.predicates.is_empty() {
+                                struct_span_err!(tcx.sess, start_span, E0647,
+                                            "start function is not allowed to have a where clause")
+                                            .emit();
+                                return;
+                            }
                         }
                         _ => ()
                     }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index d7646ce7bfc..73a7e0e690f 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -35,10 +35,29 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                 AdtKind::Enum => Def::Enum,
                 AdtKind::Union => Def::Union,
             }
-            _ => panic!("Unexpected type {:?}", def_id),
+            ty::TyInt(_) |
+            ty::TyUint(_) |
+            ty::TyFloat(_) |
+            ty::TyStr |
+            ty::TyBool |
+            ty::TyChar => return self.get_auto_trait_impls(def_id, &move |_: DefId| {
+                match ty.sty {
+                    ty::TyInt(x) => Def::PrimTy(hir::TyInt(x)),
+                    ty::TyUint(x) => Def::PrimTy(hir::TyUint(x)),
+                    ty::TyFloat(x) => Def::PrimTy(hir::TyFloat(x)),
+                    ty::TyStr => Def::PrimTy(hir::TyStr),
+                    ty::TyBool => Def::PrimTy(hir::TyBool),
+                    ty::TyChar => Def::PrimTy(hir::TyChar),
+                    _ => unreachable!(),
+                }
+            }, None),
+            _ => {
+                debug!("Unexpected type {:?}", def_id);
+                return Vec::new()
+            }
         };
 
-        self.get_auto_trait_impls(def_id, def_ctor, None)
+        self.get_auto_trait_impls(def_id, &def_ctor, None)
     }
 
     pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
@@ -52,15 +71,16 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
             _ => panic!("Unexpected type {:?} {:?}", item, id),
         };
 
-        self.get_auto_trait_impls(did, def_ctor, Some(name))
+        self.get_auto_trait_impls(did, &def_ctor, Some(name))
     }
 
-    pub fn get_auto_trait_impls(
+    pub fn get_auto_trait_impls<F>(
         &self,
         def_id: DefId,
-        def_ctor: fn(DefId) -> Def,
+        def_ctor: &F,
         name: Option<String>,
-    ) -> Vec<Item> {
+    ) -> Vec<Item>
+    where F: Fn(DefId) -> Def {
         if self.cx
             .tcx
             .get_attrs(def_id)
@@ -68,9 +88,9 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
             .has_word("hidden")
         {
             debug!(
-                "get_auto_trait_impls(def_id={:?}, def_ctor={:?}): item has doc('hidden'), \
+                "get_auto_trait_impls(def_id={:?}, def_ctor=...): item has doc('hidden'), \
                  aborting",
-                def_id, def_ctor
+                def_id
             );
             return Vec::new();
         }
@@ -79,8 +99,8 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
         let generics = self.cx.tcx.generics_of(def_id);
 
         debug!(
-            "get_auto_trait_impls(def_id={:?}, def_ctor={:?}, generics={:?}",
-            def_id, def_ctor, generics
+            "get_auto_trait_impls(def_id={:?}, def_ctor=..., generics={:?}",
+            def_id, generics
         );
         let auto_traits: Vec<_> = self.cx
             .send_trait
@@ -110,23 +130,24 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
         auto_traits
     }
 
-    fn get_auto_trait_impl_for(
+    fn get_auto_trait_impl_for<F>(
         &self,
         def_id: DefId,
         name: Option<String>,
         generics: ty::Generics,
-        def_ctor: fn(DefId) -> Def,
+        def_ctor: &F,
         trait_def_id: DefId,
-    ) -> Option<Item> {
+    ) -> Option<Item>
+    where F: Fn(DefId) -> Def {
         if !self.cx
             .generated_synthetics
             .borrow_mut()
             .insert((def_id, trait_def_id))
         {
             debug!(
-                "get_auto_trait_impl_for(def_id={:?}, generics={:?}, def_ctor={:?}, \
+                "get_auto_trait_impl_for(def_id={:?}, generics={:?}, def_ctor=..., \
                  trait_def_id={:?}): already generated, aborting",
-                def_id, generics, def_ctor, trait_def_id
+                def_id, generics, trait_def_id
             );
             return None;
         }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index a8f4848bf89..da04068107d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -302,6 +302,14 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
     for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
         if !def_id.is_local() {
             build_impl(cx, def_id, &mut impls);
+
+            let auto_impls = get_auto_traits_with_def_id(cx, def_id);
+            let mut renderinfo = cx.renderinfo.borrow_mut();
+
+            let new_impls: Vec<clean::Item> = auto_impls.into_iter()
+                .filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
+
+            impls.extend(new_impls);
         }
     }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c233e57a801..6beb64dced1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -4183,7 +4183,8 @@ pub fn path_to_def(tcx: &TyCtxt, path: &[&str]) -> Option<DefId> {
     }
 }
 
-fn get_path_for_type(tcx: TyCtxt, def_id: DefId, def_ctor: fn(DefId) -> Def) -> hir::Path {
+fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
+where F: Fn(DefId) -> Def {
     struct AbsolutePathBuffer {
         names: Vec<String>,
     }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 3ce95c78a90..1b713a446a0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -13,8 +13,6 @@
        html_root_url = "https://doc.rust-lang.org/nightly/",
        html_playground_url = "https://play.rust-lang.org/")]
 
-#![cfg_attr(stage0, feature(dyn_trait))]
-
 #![feature(ascii_ctype)]
 #![feature(rustc_private)]
 #![feature(box_patterns)]
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index a8578404467..78d3d6d5e60 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -17,7 +17,6 @@
 #[doc(inline)] pub use alloc_system::System;
 #[doc(inline)] pub use core::alloc::*;
 
-#[cfg(not(stage0))]
 #[cfg(not(test))]
 #[doc(hidden)]
 #[lang = "oom"]
@@ -43,13 +42,6 @@ pub mod __default_lib_allocator {
         System.alloc(layout) as *mut u8
     }
 
-    #[cfg(stage0)]
-    #[no_mangle]
-    #[rustc_std_internal_symbol]
-    pub unsafe extern fn __rdl_oom() -> ! {
-        super::oom()
-    }
-
     #[no_mangle]
     #[rustc_std_internal_symbol]
     pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
@@ -74,57 +66,4 @@ pub mod __default_lib_allocator {
         let layout = Layout::from_size_align_unchecked(size, align);
         System.alloc_zeroed(layout) as *mut u8
     }
-
-    #[cfg(stage0)]
-    pub mod stage0 {
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_usable_size(_layout: *const u8,
-                                               _min: *mut usize,
-                                               _max: *mut usize) {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_alloc_excess(_size: usize,
-                                                _align: usize,
-                                                _excess: *mut usize,
-                                                _err: *mut u8) -> *mut u8 {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8,
-                                                  _old_size: usize,
-                                                  _old_align: usize,
-                                                  _new_size: usize,
-                                                  _new_align: usize,
-                                                  _excess: *mut usize,
-                                                  _err: *mut u8) -> *mut u8 {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8,
-                                                 _old_size: usize,
-                                                 _old_align: usize,
-                                                 _new_size: usize,
-                                                 _new_align: usize) -> u8 {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8,
-                                                   _old_size: usize,
-                                                   _old_align: usize,
-                                                   _new_size: usize,
-                                                   _new_align: usize) -> u8 {
-            unimplemented!()
-        }
-
-    }
 }
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 7314d32b020..ae30321f46d 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -19,14 +19,8 @@
 #![allow(missing_docs)]
 
 #[cfg(not(test))]
-#[cfg(stage0)]
-use core::num::Float;
-#[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-#[cfg(stage0)]
-use num::FpCategory;
-#[cfg(not(test))]
 use sys::cmath;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -41,12 +35,8 @@ pub use core::f32::{MIN, MIN_POSITIVE, MAX};
 pub use core::f32::consts;
 
 #[cfg(not(test))]
-#[cfg_attr(stage0, lang = "f32")]
-#[cfg_attr(not(stage0), lang = "f32_runtime")]
+#[lang = "f32_runtime"]
 impl f32 {
-    #[cfg(stage0)]
-    f32_core_methods!();
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// # Examples
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index 75edba8979f..7950d434b77 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -19,14 +19,8 @@
 #![allow(missing_docs)]
 
 #[cfg(not(test))]
-#[cfg(stage0)]
-use core::num::Float;
-#[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-#[cfg(stage0)]
-use num::FpCategory;
-#[cfg(not(test))]
 use sys::cmath;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -41,12 +35,8 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX};
 pub use core::f64::consts;
 
 #[cfg(not(test))]
-#[cfg_attr(stage0, lang = "f64")]
-#[cfg_attr(not(stage0), lang = "f64_runtime")]
+#[lang = "f64_runtime"]
 impl f64 {
-    #[cfg(stage0)]
-    f64_core_methods!();
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// # Examples
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 9cdc6a21622..f7d06852f27 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -252,7 +252,6 @@
 #![feature(collections_range)]
 #![feature(compiler_builtins_lib)]
 #![feature(const_fn)]
-#![cfg_attr(stage0, feature(core_float))]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
@@ -260,10 +259,8 @@
 #![feature(fs_read_write)]
 #![feature(fixed_size_array)]
 #![feature(float_from_str_radix)]
-#![cfg_attr(stage0, feature(float_internals))]
 #![feature(fn_traits)]
 #![feature(fnbox)]
-#![cfg_attr(stage0, feature(generic_param_attrs))]
 #![feature(hashmap_internals)]
 #![feature(heap_api)]
 #![feature(int_error_internals)]
@@ -319,6 +316,7 @@
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(windows, feature(used))]
 #![feature(doc_alias)]
+#![feature(float_internals)]
 
 #![default_lib_allocator]
 
@@ -364,11 +362,6 @@ extern crate libc;
 #[allow(unused_extern_crates)]
 extern crate unwind;
 
-// compiler-rt intrinsics
-#[doc(masked)]
-#[cfg(stage0)]
-extern crate compiler_builtins;
-
 // During testing, this crate is not actually the "real" std library, but rather
 // it links to the real std library, which was compiled from this same source
 // code. So any lang items std defines are conditionally excluded (or else they
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 2b6635ec783..1817726d6a1 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -107,8 +107,7 @@ impl Path {
     // or starts with something like `self`/`super`/`$crate`/etc.
     pub fn make_root(&self) -> Option<PathSegment> {
         if let Some(ident) = self.segments.get(0).map(|seg| seg.ident) {
-            if ::parse::token::is_path_segment_keyword(ident) &&
-               ident.name != keywords::Crate.name() {
+            if ident.is_path_segment_keyword() && ident.name != keywords::Crate.name() {
                 return None;
             }
         }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 3b76084f2fb..f7d4227977c 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -14,9 +14,10 @@ use ast::{self, Attribute, Name, PatKind, MetaItem};
 use attr::HasAttrs;
 use codemap::{self, CodeMap, Spanned, respan};
 use syntax_pos::{Span, MultiSpan, DUMMY_SP};
+use edition::Edition;
 use errors::{DiagnosticBuilder, DiagnosticId};
 use ext::expand::{self, Expansion, Invocation};
-use ext::hygiene::{Mark, SyntaxContext};
+use ext::hygiene::{self, Mark, SyntaxContext};
 use fold::{self, Folder};
 use parse::{self, parser, DirectoryOwnership};
 use parse::token;
@@ -586,13 +587,13 @@ pub enum SyntaxExtension {
     MultiModifier(Box<MultiItemModifier + sync::Sync + sync::Send>),
 
     /// A function-like procedural macro. TokenStream -> TokenStream.
-    ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>),
+    ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>, Edition),
 
     /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream.
     /// The first TokenSteam is the attribute, the second is the annotated item.
     /// Allows modification of the input items and adding new items, similar to
     /// MultiModifier, but uses TokenStreams, rather than AST nodes.
-    AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>),
+    AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>, Edition),
 
     /// A normal, function-like syntax extension.
     ///
@@ -608,6 +609,8 @@ pub enum SyntaxExtension {
         allow_internal_unsafe: bool,
         /// The macro's feature name if it is unstable, and the stability feature
         unstable_feature: Option<(Symbol, u32)>,
+        /// Edition of the crate in which the macro is defined
+        edition: Edition,
     },
 
     /// A function-like syntax extension that has an extra ident before
@@ -619,9 +622,8 @@ pub enum SyntaxExtension {
     /// The input is the annotated item.
     /// Allows generating code to implement a Trait for a given struct
     /// or enum item.
-    ProcMacroDerive(Box<MultiItemModifier +
-                        sync::Sync +
-                        sync::Send>, Vec<Symbol> /* inert attribute names */),
+    ProcMacroDerive(Box<MultiItemModifier + sync::Sync + sync::Send>,
+                    Vec<Symbol> /* inert attribute names */, Edition),
 
     /// An attribute-like procedural macro that derives a builtin trait.
     BuiltinDerive(BuiltinDeriveFn),
@@ -629,7 +631,7 @@ pub enum SyntaxExtension {
     /// A declarative macro, e.g. `macro m() {}`.
     ///
     /// The second element is the definition site span.
-    DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>),
+    DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>, Edition),
 }
 
 impl SyntaxExtension {
@@ -660,6 +662,21 @@ impl SyntaxExtension {
             _ => false,
         }
     }
+
+    pub fn edition(&self) -> Edition {
+        match *self {
+            SyntaxExtension::NormalTT { edition, .. } |
+            SyntaxExtension::DeclMacro(.., edition) |
+            SyntaxExtension::ProcMacro(.., edition) |
+            SyntaxExtension::AttrProcMacro(.., edition) |
+            SyntaxExtension::ProcMacroDerive(.., edition) => edition,
+            // Unstable legacy stuff
+            SyntaxExtension::IdentTT(..) |
+            SyntaxExtension::MultiDecorator(..) |
+            SyntaxExtension::MultiModifier(..) |
+            SyntaxExtension::BuiltinDerive(..) => hygiene::default_edition(),
+        }
+    }
 }
 
 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 6bf166dfe95..0b6a7e1c4f4 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -10,7 +10,7 @@
 
 use attr::HasAttrs;
 use ast;
-use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
+use codemap::{hygiene, ExpnInfo, NameAndSpan, ExpnFormat};
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use parse::parser::PathStyle;
@@ -65,6 +65,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         },
     });
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 584b9455a93..ee96963362b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -16,7 +16,7 @@ use config::{is_test_or_bench, StripUnconfigured};
 use errors::FatalError;
 use ext::base::*;
 use ext::derive::{add_derived_markers, collect_derives};
-use ext::hygiene::{Mark, SyntaxContext};
+use ext::hygiene::{self, Mark, SyntaxContext};
 use ext::placeholders::{placeholder, PlaceholderExpander};
 use feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
 use fold;
@@ -502,6 +502,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 span: None,
                 allow_internal_unstable: false,
                 allow_internal_unsafe: false,
+                edition: ext.edition(),
             }
         });
 
@@ -520,7 +521,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 items.push(item);
                 Some(kind.expect_from_annotatables(items))
             }
-            AttrProcMacro(ref mac) => {
+            AttrProcMacro(ref mac, ..) => {
                 self.gate_proc_macro_attr_item(attr.span, &item);
                 let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
                     Annotatable::Item(item) => token::NtItem(item),
@@ -609,7 +610,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                           allow_internal_unstable,
                                           allow_internal_unsafe,
                                           // can't infer this type
-                                          unstable_feature: Option<(Symbol, u32)>| {
+                                          unstable_feature: Option<(Symbol, u32)>,
+                                          edition| {
 
             // feature-gate the macro invocation
             if let Some((feature, issue)) = unstable_feature {
@@ -642,15 +644,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     span: def_site_span,
                     allow_internal_unstable,
                     allow_internal_unsafe,
+                    edition,
                 },
             });
             Ok(())
         };
 
         let opt_expanded = match *ext {
-            DeclMacro(ref expand, def_span) => {
+            DeclMacro(ref expand, def_span, edition) => {
                 if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s),
-                                                                    false, false, None) {
+                                                                    false, false, None,
+                                                                    edition) {
                     dummy_span
                 } else {
                     kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
@@ -663,11 +667,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 allow_internal_unstable,
                 allow_internal_unsafe,
                 unstable_feature,
+                edition,
             } => {
                 if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
                                                                     allow_internal_unstable,
                                                                     allow_internal_unsafe,
-                                                                    unstable_feature) {
+                                                                    unstable_feature,
+                                                                    edition) {
                     dummy_span
                 } else {
                     kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
@@ -688,6 +694,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             span: tt_span,
                             allow_internal_unstable,
                             allow_internal_unsafe: false,
+                            edition: hygiene::default_edition(),
                         }
                     });
 
@@ -709,7 +716,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 kind.dummy(span)
             }
 
-            ProcMacro(ref expandfun) => {
+            ProcMacro(ref expandfun, edition) => {
                 if ident.name != keywords::Invalid.name() {
                     let msg =
                         format!("macro {}! expects no ident argument, given '{}'", path, ident);
@@ -728,6 +735,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             // FIXME probably want to follow macro_rules macros here.
                             allow_internal_unstable: false,
                             allow_internal_unsafe: false,
+                            edition,
                         },
                     });
 
@@ -802,11 +810,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 span: None,
                 allow_internal_unstable: false,
                 allow_internal_unsafe: false,
+                edition: ext.edition(),
             }
         };
 
         match *ext {
-            ProcMacroDerive(ref ext, _) => {
+            ProcMacroDerive(ref ext, ..) => {
                 invoc.expansion_data.mark.set_expn_info(expn_info);
                 let span = span.with_ctxt(self.cx.backtrace());
                 let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index e96a0e838cf..d1a7e7aac26 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -10,6 +10,7 @@
 
 use {ast, attr};
 use syntax_pos::{Span, DUMMY_SP};
+use edition::Edition;
 use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
 use ext::base::{NormalTT, TTMacroExpander};
 use ext::expand::{Expansion, ExpansionKind};
@@ -183,7 +184,8 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
 // Holy self-referential!
 
 /// Converts a `macro_rules!` invocation into a syntax extension.
-pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension {
+pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition: Edition)
+               -> SyntaxExtension {
     let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
     let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
 
@@ -298,10 +300,11 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> Syntax
             def_info: Some((def.id, def.span)),
             allow_internal_unstable,
             allow_internal_unsafe,
-            unstable_feature
+            unstable_feature,
+            edition,
         }
     } else {
-        SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)))
+        SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)), edition)
     }
 }
 
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 90af3ba51ec..e9817034569 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -22,7 +22,6 @@
 #![feature(unicode_internals)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
-#![feature(non_exhaustive)]
 #![feature(const_atomic_usize_new)]
 #![feature(rustc_attrs)]
 #![feature(str_escape)]
@@ -142,7 +141,6 @@ pub mod codemap;
 #[macro_use]
 pub mod config;
 pub mod entry;
-pub mod edition;
 pub mod feature_gate;
 pub mod fold;
 pub mod parse;
@@ -150,6 +148,7 @@ pub mod ptr;
 pub mod show_span;
 pub mod std_inject;
 pub mod str;
+pub use syntax_pos::edition;
 pub use syntax_pos::symbol;
 pub mod test;
 pub mod tokenstream;
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index 63aa5d28ce8..672b0b9bbd1 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -238,7 +238,19 @@ fn read_block_comment(rdr: &mut StringReader,
     debug!(">>> block comment");
     let p = rdr.pos;
     let mut lines: Vec<String> = Vec::new();
-    let col = rdr.col;
+
+    // Count the number of chars since the start of the line by rescanning.
+    let mut src_index = rdr.src_index(rdr.filemap.line_begin_pos());
+    let end_src_index = rdr.src_index(rdr.pos);
+    assert!(src_index <= end_src_index);
+    let mut n = 0;
+    while src_index < end_src_index {
+        let c = char_at(&rdr.src, src_index);
+        src_index += c.len_utf8();
+        n += 1;
+    }
+    let col = CharPos(n);
+
     rdr.bump();
     rdr.bump();
 
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 3e22598043a..bbece1ee5e3 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -44,13 +44,11 @@ pub struct StringReader<'a> {
     pub next_pos: BytePos,
     /// The absolute offset within the codemap of the current character
     pub pos: BytePos,
-    /// The column of the next character to read
-    pub col: CharPos,
     /// The current character (which has been read from self.pos)
     pub ch: Option<char>,
     pub filemap: Lrc<syntax_pos::FileMap>,
-    /// If Some, stop reading the source at this position (inclusive).
-    pub terminator: Option<BytePos>,
+    /// Stop reading src at this index.
+    pub end_src_index: usize,
     /// Whether to record new-lines and multibyte chars in filemap.
     /// This is only necessary the first time a filemap is lexed.
     /// If part of a filemap is being re-lexed, this should be set to false.
@@ -61,7 +59,7 @@ pub struct StringReader<'a> {
     pub fatal_errs: Vec<DiagnosticBuilder<'a>>,
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.filemap.src.as_ref().unwrap()` all the time.
-    source_text: Lrc<String>,
+    src: Lrc<String>,
     /// Stack of open delimiters and their spans. Used for error message.
     token: token::Token,
     span: Span,
@@ -113,14 +111,7 @@ impl<'a> StringReader<'a> {
         self.unwrap_or_abort(res)
     }
     fn is_eof(&self) -> bool {
-        if self.ch.is_none() {
-            return true;
-        }
-
-        match self.terminator {
-            Some(t) => self.next_pos > t,
-            None => false,
-        }
+        self.ch.is_none()
     }
     /// Return the next token. EFFECT: advances the string_reader.
     pub fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
@@ -176,21 +167,20 @@ impl<'a> StringReader<'a> {
                                               filemap.name));
         }
 
-        let source_text = (*filemap.src.as_ref().unwrap()).clone();
+        let src = (*filemap.src.as_ref().unwrap()).clone();
 
         StringReader {
             sess,
             next_pos: filemap.start_pos,
             pos: filemap.start_pos,
-            col: CharPos(0),
             ch: Some('\n'),
             filemap,
-            terminator: None,
+            end_src_index: src.len(),
             save_new_lines_and_multibyte: true,
             // dummy values; not read
             peek_tok: token::Eof,
             peek_span: syntax_pos::DUMMY_SP,
-            source_text,
+            src,
             fatal_errs: Vec::new(),
             token: token::Eof,
             span: syntax_pos::DUMMY_SP,
@@ -222,7 +212,7 @@ impl<'a> StringReader<'a> {
         // Seek the lexer to the right byte range.
         sr.save_new_lines_and_multibyte = false;
         sr.next_pos = span.lo();
-        sr.terminator = Some(span.hi());
+        sr.end_src_index = sr.src_index(span.hi());
 
         sr.bump();
 
@@ -326,9 +316,7 @@ impl<'a> StringReader<'a> {
     /// offending string to the error message
     fn fatal_span_verbose(&self, from_pos: BytePos, to_pos: BytePos, mut m: String) -> FatalError {
         m.push_str(": ");
-        let from = self.byte_offset(from_pos).to_usize();
-        let to = self.byte_offset(to_pos).to_usize();
-        m.push_str(&self.source_text[from..to]);
+        m.push_str(&self.src[self.src_index(from_pos)..self.src_index(to_pos)]);
         self.fatal_span_(from_pos, to_pos, &m[..])
     }
 
@@ -354,8 +342,9 @@ impl<'a> StringReader<'a> {
         Ok(())
     }
 
-    fn byte_offset(&self, pos: BytePos) -> BytePos {
-        (pos - self.filemap.start_pos)
+    #[inline]
+    fn src_index(&self, pos: BytePos) -> usize {
+        (pos - self.filemap.start_pos).to_usize()
     }
 
     /// Calls `f` with a string slice of the source text spanning from `start`
@@ -386,7 +375,7 @@ impl<'a> StringReader<'a> {
     fn with_str_from_to<T, F>(&self, start: BytePos, end: BytePos, f: F) -> T
         where F: FnOnce(&str) -> T
     {
-        f(&self.source_text[self.byte_offset(start).to_usize()..self.byte_offset(end).to_usize()])
+        f(&self.src[self.src_index(start)..self.src_index(end)])
     }
 
     /// Converts CRLF to LF in the given string, raising an error on bare CR.
@@ -438,47 +427,39 @@ impl<'a> StringReader<'a> {
         }
     }
 
-
     /// Advance the StringReader by one character. If a newline is
     /// discovered, add it to the FileMap's list of line start offsets.
     pub fn bump(&mut self) {
-        let new_pos = self.next_pos;
-        let new_byte_offset = self.byte_offset(new_pos).to_usize();
-        let end = self.terminator.map_or(self.source_text.len(), |t| {
-            self.byte_offset(t).to_usize()
-        });
-        if new_byte_offset < end {
-            let old_ch_is_newline = self.ch.unwrap() == '\n';
-            let new_ch = char_at(&self.source_text, new_byte_offset);
-            let new_ch_len = new_ch.len_utf8();
-
-            self.ch = Some(new_ch);
-            self.pos = new_pos;
-            self.next_pos = new_pos + Pos::from_usize(new_ch_len);
-            if old_ch_is_newline {
+        let next_src_index = self.src_index(self.next_pos);
+        if next_src_index < self.end_src_index {
+            let next_ch = char_at(&self.src, next_src_index);
+            let next_ch_len = next_ch.len_utf8();
+
+            if self.ch.unwrap() == '\n' {
                 if self.save_new_lines_and_multibyte {
-                    self.filemap.next_line(self.pos);
+                    self.filemap.next_line(self.next_pos);
                 }
-                self.col = CharPos(0);
-            } else {
-                self.col = self.col + CharPos(1);
             }
-            if new_ch_len > 1 {
+            if next_ch_len > 1 {
                 if self.save_new_lines_and_multibyte {
-                    self.filemap.record_multibyte_char(self.pos, new_ch_len);
+                    self.filemap.record_multibyte_char(self.next_pos, next_ch_len);
                 }
             }
-            self.filemap.record_width(self.pos, new_ch);
+            self.filemap.record_width(self.next_pos, next_ch);
+
+            self.ch = Some(next_ch);
+            self.pos = self.next_pos;
+            self.next_pos = self.next_pos + Pos::from_usize(next_ch_len);
         } else {
             self.ch = None;
-            self.pos = new_pos;
+            self.pos = self.next_pos;
         }
     }
 
     pub fn nextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.next_pos).to_usize();
-        if offset < self.source_text.len() {
-            Some(char_at(&self.source_text, offset))
+        let next_src_index = self.src_index(self.next_pos);
+        if next_src_index < self.end_src_index {
+            Some(char_at(&self.src, next_src_index))
         } else {
             None
         }
@@ -489,17 +470,15 @@ impl<'a> StringReader<'a> {
     }
 
     pub fn nextnextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.next_pos).to_usize();
-        let s = &self.source_text[..];
-        if offset >= s.len() {
-            return None;
-        }
-        let next = offset + char_at(s, offset).len_utf8();
-        if next < s.len() {
-            Some(char_at(s, next))
-        } else {
-            None
+        let next_src_index = self.src_index(self.next_pos);
+        if next_src_index < self.end_src_index {
+            let next_next_src_index =
+                next_src_index + char_at(&self.src, next_src_index).len_utf8();
+            if next_next_src_index < self.end_src_index {
+                return Some(char_at(&self.src, next_next_src_index));
+            }
         }
+        None
     }
 
     pub fn nextnextch_is(&self, c: char) -> bool {
@@ -1149,7 +1128,7 @@ impl<'a> StringReader<'a> {
                 return Ok(self.with_str_from(start, |string| {
                     // FIXME: perform NFKC normalization here. (Issue #2253)
                     let ident = self.mk_ident(string);
-                    if is_raw_ident && (token::is_path_segment_keyword(ident) ||
+                    if is_raw_ident && (ident.is_path_segment_keyword() ||
                                         ident.name == keywords::Underscore.name()) {
                         self.fatal_span_(raw_start, self.pos,
                             &format!("`r#{}` is not currently supported.", ident.name)
@@ -1359,8 +1338,8 @@ impl<'a> StringReader<'a> {
                     loop {
                         self.bump();
                         if self.ch_is('\'') {
-                            let start = self.byte_offset(start).to_usize();
-                            let end = self.byte_offset(self.pos).to_usize();
+                            let start = self.src_index(start);
+                            let end = self.src_index(self.pos);
                             self.bump();
                             let span = self.mk_sp(start_with_quote, self.pos);
                             self.sess.span_diagnostic
@@ -1369,8 +1348,7 @@ impl<'a> StringReader<'a> {
                                 .span_suggestion(span,
                                                  "if you meant to write a `str` literal, \
                                                   use double quotes",
-                                                 format!("\"{}\"",
-                                                         &self.source_text[start..end]))
+                                                 format!("\"{}\"", &self.src[start..end]))
                                 .emit();
                             return Ok(token::Literal(token::Str_(Symbol::intern("??")), None))
                         }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index a1c056cbb2c..5575614a4d4 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -138,44 +138,6 @@ fn ident_can_begin_type(ident: ast::Ident, is_raw: bool) -> bool {
     ].contains(&ident.name)
 }
 
-pub fn is_path_segment_keyword(id: ast::Ident) -> bool {
-    id.name == keywords::Super.name() ||
-    id.name == keywords::SelfValue.name() ||
-    id.name == keywords::SelfType.name() ||
-    id.name == keywords::Extern.name() ||
-    id.name == keywords::Crate.name() ||
-    id.name == keywords::CrateRoot.name() ||
-    id.name == keywords::DollarCrate.name()
-}
-
-// We see this identifier in a normal identifier position, like variable name or a type.
-// How was it written originally? Did it use the raw form? Let's try to guess.
-pub fn is_raw_guess(ident: ast::Ident) -> bool {
-    ident.name != keywords::Invalid.name() &&
-    is_reserved_ident(ident) && !is_path_segment_keyword(ident)
-}
-
-// Returns true for reserved identifiers used internally for elided lifetimes,
-// unnamed method parameters, crate root module, error recovery etc.
-pub fn is_special_ident(id: ast::Ident) -> bool {
-    id.name <= keywords::Underscore.name()
-}
-
-/// Returns `true` if the token is a keyword used in the language.
-pub fn is_used_keyword(id: ast::Ident) -> bool {
-    id.name >= keywords::As.name() && id.name <= keywords::While.name()
-}
-
-/// Returns `true` if the token is a keyword reserved for possible future use.
-pub fn is_unused_keyword(id: ast::Ident) -> bool {
-    id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name()
-}
-
-/// Returns `true` if the token is either a special identifier or a keyword.
-pub fn is_reserved_ident(id: ast::Ident) -> bool {
-    is_special_ident(id) || is_used_keyword(id) || is_unused_keyword(id)
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)]
 pub enum Token {
     /* Expression-operator symbols. */
@@ -251,7 +213,7 @@ impl Token {
 
     /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
     pub fn from_ast_ident(ident: ast::Ident) -> Token {
-        Ident(ident, is_raw_guess(ident))
+        Ident(ident, ident.is_raw_guess())
     }
 
     /// Returns `true` if the token starts with '>'.
@@ -431,7 +393,7 @@ impl Token {
 
     pub fn is_path_segment_keyword(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_path_segment_keyword(id),
+            Some((id, false)) => id.is_path_segment_keyword(),
             _ => false,
         }
     }
@@ -440,7 +402,7 @@ impl Token {
     // unnamed method parameters, crate root module, error recovery etc.
     pub fn is_special_ident(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_special_ident(id),
+            Some((id, false)) => id.is_special(),
             _ => false,
         }
     }
@@ -448,7 +410,7 @@ impl Token {
     /// Returns `true` if the token is a keyword used in the language.
     pub fn is_used_keyword(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_used_keyword(id),
+            Some((id, false)) => id.is_used_keyword(),
             _ => false,
         }
     }
@@ -456,7 +418,7 @@ impl Token {
     /// Returns `true` if the token is a keyword reserved for possible future use.
     pub fn is_unused_keyword(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_unused_keyword(id),
+            Some((id, false)) => id.is_unused_keyword(),
             _ => false,
         }
     }
@@ -464,7 +426,7 @@ impl Token {
     /// Returns `true` if the token is either a special identifier or a keyword.
     pub fn is_reserved_ident(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_reserved_ident(id),
+            Some((id, false)) => id.is_reserved(),
             _ => false,
         }
     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index a700799cde5..17f83a09c77 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2374,7 +2374,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        if token::is_raw_guess(ident) {
+        if ident.is_raw_guess() {
             self.s.word(&format!("r#{}", ident))?;
         } else {
             self.s.word(&ident.name.as_str())?;
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index 53dc19ba37d..e9cd7adb9c1 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -14,7 +14,7 @@ use std::cell::Cell;
 use ext::hygiene::{Mark, SyntaxContext};
 use symbol::{Symbol, keywords};
 use syntax_pos::{DUMMY_SP, Span};
-use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, respan};
+use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, hygiene, respan};
 use ptr::P;
 use tokenstream::TokenStream;
 
@@ -30,6 +30,7 @@ fn ignored_span(sp: Span) -> Span {
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         }
     });
     sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
diff --git a/src/libsyntax/str.rs b/src/libsyntax/str.rs
index d0f47629b10..281861918fd 100644
--- a/src/libsyntax/str.rs
+++ b/src/libsyntax/str.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[inline]
 pub fn char_at(s: &str, byte: usize) -> char {
     s[byte..].chars().next().unwrap()
 }
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 1734692f9e7..1dfd48a24c3 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -29,7 +29,7 @@ use entry::{self, EntryPointType};
 use ext::base::{ExtCtxt, Resolver};
 use ext::build::AstBuilder;
 use ext::expand::ExpansionConfig;
-use ext::hygiene::{Mark, SyntaxContext};
+use ext::hygiene::{self, Mark, SyntaxContext};
 use fold::Folder;
 use feature_gate::Features;
 use util::move_map::MoveMap;
@@ -300,6 +300,7 @@ fn generate_test_harness(sess: &ParseSess,
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         }
     });
 
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 369c5b1ff60..dd8f79d20ab 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -45,17 +45,6 @@ impl State {
     }
 }
 
-macro_rules! span_err_if_not_stage0 {
-    ($cx:expr, $sp:expr, $code:ident, $text:tt) => {
-        #[cfg(not(stage0))] {
-            span_err!($cx, $sp, $code, $text)
-        }
-        #[cfg(stage0)] {
-            $cx.span_err($sp, $text)
-        }
-    }
-}
-
 const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
 
 pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
@@ -100,7 +89,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                 if asm_str_style.is_some() {
                     // If we already have a string with instructions,
                     // ending up in Asm state again is an error.
-                    span_err_if_not_stage0!(cx, sp, E0660, "malformed inline assembly");
+                    span_err!(cx, sp, E0660, "malformed inline assembly");
                     return DummyResult::expr(sp);
                 }
                 // Nested parser, stop before the first colon (see above).
@@ -153,7 +142,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                             Some(Symbol::intern(&format!("={}", ch.as_str())))
                         }
                         _ => {
-                            span_err_if_not_stage0!(cx, span, E0661,
+                            span_err!(cx, span, E0661,
                                                     "output operand constraint lacks '=' or '+'");
                             None
                         }
@@ -179,10 +168,10 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     let (constraint, _str_style) = panictry!(p.parse_str());
 
                     if constraint.as_str().starts_with("=") {
-                        span_err_if_not_stage0!(cx, p.prev_span, E0662,
+                        span_err!(cx, p.prev_span, E0662,
                                                 "input operand constraint contains '='");
                     } else if constraint.as_str().starts_with("+") {
-                        span_err_if_not_stage0!(cx, p.prev_span, E0663,
+                        span_err!(cx, p.prev_span, E0663,
                                                 "input operand constraint contains '+'");
                     }
 
@@ -205,7 +194,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     if OPTIONS.iter().any(|&opt| s == opt) {
                         cx.span_warn(p.prev_span, "expected a clobber, found an option");
                     } else if s.as_str().starts_with("{") || s.as_str().ends_with("}") {
-                        span_err_if_not_stage0!(cx, p.prev_span, E0664,
+                        span_err!(cx, p.prev_span, E0664,
                                                 "clobber should not be surrounded by braces");
                     }
 
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index f29cc75664d..b22098408a3 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -767,9 +767,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
     }
 
     if !parser.errors.is_empty() {
-        let (err, note) = parser.errors.remove(0);
-        let mut e = cx.ecx.struct_span_err(cx.fmtsp, &format!("invalid format string: {}", err));
-        if let Some(note) = note {
+        let err = parser.errors.remove(0);
+        let sp = cx.fmtsp.from_inner_byte_pos(err.start, err.end);
+        let mut e = cx.ecx.struct_span_err(sp, &format!("invalid format string: {}",
+                                                        err.description));
+        e.span_label(sp, err.label + " in format string");
+        if let Some(note) = err.note {
             e.note(&note);
         }
         e.emit();
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index b6721dd28f3..15fcfac13ad 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -18,7 +18,7 @@
 #![feature(decl_macro)]
 #![feature(str_escape)]
 
-#![cfg_attr(not(stage0), feature(rustc_diagnostic_macros))]
+#![feature(rustc_diagnostic_macros)]
 
 extern crate fmt_macros;
 #[macro_use]
@@ -29,7 +29,6 @@ extern crate rustc_data_structures;
 extern crate rustc_errors as errors;
 extern crate rustc_target;
 
-#[cfg(not(stage0))]
 mod diagnostics;
 
 mod assert;
@@ -55,6 +54,7 @@ pub mod proc_macro_impl;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
 use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension};
+use syntax::ext::hygiene;
 use syntax::symbol::Symbol;
 
 pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
@@ -75,6 +75,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
                         allow_internal_unstable: false,
                         allow_internal_unsafe: false,
                         unstable_feature: None,
+                        edition: hygiene::default_edition(),
                     });
         )* }
     }
@@ -129,7 +130,8 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
                 def_info: None,
                 allow_internal_unstable: true,
                 allow_internal_unsafe: false,
-                unstable_feature: None
+                unstable_feature: None,
+                edition: hygiene::default_edition(),
             });
 
     for (name, ext) in user_exts {
diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs
index d684e8b4ffe..3593165023a 100644
--- a/src/libsyntax_ext/proc_macro_registrar.rs
+++ b/src/libsyntax_ext/proc_macro_registrar.rs
@@ -14,7 +14,7 @@ use errors;
 
 use syntax::ast::{self, Ident, NodeId};
 use syntax::attr;
-use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, respan};
+use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, hygiene, respan};
 use syntax::ext::base::ExtCtxt;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
@@ -369,6 +369,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         }
     });
     let span = DUMMY_SP.apply_mark(mark);
diff --git a/src/libsyntax/edition.rs b/src/libsyntax_pos/edition.rs
index c98b54581f3..18446c10996 100644
--- a/src/libsyntax/edition.rs
+++ b/src/libsyntax_pos/edition.rs
@@ -12,7 +12,7 @@ use std::fmt;
 use std::str::FromStr;
 
 /// The edition of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)]
+#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 #[non_exhaustive]
 pub enum Edition {
     // editions must be kept in order, newest to oldest
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index be031ea98c9..1365ac396ff 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -17,6 +17,7 @@
 
 use GLOBALS;
 use Span;
+use edition::Edition;
 use symbol::{Ident, Symbol};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
@@ -151,6 +152,7 @@ pub struct HygieneData {
     syntax_contexts: Vec<SyntaxContextData>,
     markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
     gensym_to_ctxt: HashMap<Symbol, Span>,
+    default_edition: Edition,
 }
 
 impl HygieneData {
@@ -168,6 +170,7 @@ impl HygieneData {
             }],
             markings: HashMap::new(),
             gensym_to_ctxt: HashMap::new(),
+            default_edition: Edition::Edition2015,
         }
     }
 
@@ -176,6 +179,14 @@ impl HygieneData {
     }
 }
 
+pub fn default_edition() -> Edition {
+    HygieneData::with(|data| data.default_edition)
+}
+
+pub fn set_default_edition(edition: Edition) {
+    HygieneData::with(|data| data.default_edition = edition);
+}
+
 pub fn clear_markings() {
     HygieneData::with(|data| data.markings = HashMap::new());
 }
@@ -443,6 +454,8 @@ pub struct NameAndSpan {
     /// Whether the macro is allowed to use `unsafe` internally
     /// even if the user crate has `#![forbid(unsafe_code)]`.
     pub allow_internal_unsafe: bool,
+    /// Edition of the crate in which the macro is defined.
+    pub edition: Edition,
     /// The span of the macro definition itself. The macro may not
     /// have a sensible definition span (e.g. something defined
     /// completely inside libsyntax) in which case this is None.
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index d30d3d78ca5..17163576901 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -20,6 +20,7 @@
 
 #![feature(const_fn)]
 #![feature(custom_attribute)]
+#![feature(non_exhaustive)]
 #![feature(optin_builtin_traits)]
 #![allow(unused_attributes)]
 #![feature(specialization)]
@@ -48,6 +49,7 @@ extern crate serialize as rustc_serialize; // used by deriving
 
 extern crate unicode_width;
 
+pub mod edition;
 pub mod hygiene;
 pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan, CompilerDesugaringKind};
 
@@ -298,6 +300,12 @@ impl Span {
         self.ctxt().outer().expn_info().map(|i| i.call_site)
     }
 
+    /// Edition of the crate from which this span came.
+    pub fn edition(self) -> edition::Edition {
+        self.ctxt().outer().expn_info().map_or_else(|| hygiene::default_edition(),
+                                                    |einfo| einfo.callee.edition)
+    }
+
     /// Return the source callee.
     ///
     /// Returns None if the supplied span has no expansion trace,
@@ -428,6 +436,13 @@ impl Span {
         )
     }
 
+    pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
+        let span = self.data();
+        Span::new(span.lo + BytePos::from_usize(start),
+                  span.lo + BytePos::from_usize(end),
+                  span.ctxt)
+    }
+
     #[inline]
     pub fn apply_mark(self, mark: Mark) -> Span {
         let span = self.data();
@@ -971,6 +986,15 @@ impl FileMap {
         lines.push(pos);
     }
 
+    /// Return the BytePos of the beginning of the current line.
+    pub fn line_begin_pos(&self) -> BytePos {
+        let lines = self.lines.borrow();
+        match lines.last() {
+            Some(&line_pos) => line_pos,
+            None => self.start_pos,
+        }
+    }
+
     /// Add externally loaded source.
     /// If the hash of the input doesn't match or no input is supplied via None,
     /// it is interpreted as an error and the corresponding enum variant is set.
@@ -1047,6 +1071,7 @@ impl FileMap {
         self.multibyte_chars.borrow_mut().push(mbc);
     }
 
+    #[inline]
     pub fn record_width(&self, pos: BytePos, ch: char) {
         let width = match ch {
             '\t' =>
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 2258ed12779..a08f9b2e54a 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -12,6 +12,7 @@
 //! allows bidirectional lookup; i.e. given a value, one can easily find the
 //! type, and vice versa.
 
+use edition::Edition;
 use hygiene::SyntaxContext;
 use {Span, DUMMY_SP, GLOBALS};
 
@@ -318,7 +319,7 @@ macro_rules! declare_keywords {(
 // NB: leaving holes in the ident table is bad! a different ident will get
 // interned with the id from the hole, but it will be between the min and max
 // of the reserved words, and thus tagged as "reserved".
-// After modifying this list adjust `is_special_ident`, `is_used_keyword`/`is_unused_keyword`,
+// After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
 // this should be rarely necessary though if the keywords are kept in alphabetic order.
 declare_keywords! {
     // Special reserved identifiers used internally for elided lifetimes,
@@ -383,16 +384,68 @@ declare_keywords! {
     (53, Virtual,            "virtual")
     (54, Yield,              "yield")
 
+    // Edition-specific keywords reserved for future use.
+    (55, Async,              "async") // >= 2018 Edition Only
+
     // Special lifetime names
-    (55, UnderscoreLifetime, "'_")
-    (56, StaticLifetime,     "'static")
+    (56, UnderscoreLifetime, "'_")
+    (57, StaticLifetime,     "'static")
 
     // Weak keywords, have special meaning only in specific contexts.
-    (57, Auto,               "auto")
-    (58, Catch,              "catch")
-    (59, Default,            "default")
-    (60, Dyn,                "dyn")
-    (61, Union,              "union")
+    (58, Auto,               "auto")
+    (59, Catch,              "catch")
+    (60, Default,            "default")
+    (61, Dyn,                "dyn")
+    (62, Union,              "union")
+}
+
+impl Symbol {
+    fn is_unused_keyword_2018(self) -> bool {
+        self == keywords::Async.name()
+    }
+}
+
+impl Ident {
+    // Returns true for reserved identifiers used internally for elided lifetimes,
+    // unnamed method parameters, crate root module, error recovery etc.
+    pub fn is_special(self) -> bool {
+        self.name <= keywords::Underscore.name()
+    }
+
+    /// Returns `true` if the token is a keyword used in the language.
+    pub fn is_used_keyword(self) -> bool {
+        self.name >= keywords::As.name() && self.name <= keywords::While.name()
+    }
+
+    /// Returns `true` if the token is a keyword reserved for possible future use.
+    pub fn is_unused_keyword(self) -> bool {
+        // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
+        self.name >= keywords::Abstract.name() && self.name <= keywords::Yield.name() ||
+        self.name.is_unused_keyword_2018() && self.span.edition() == Edition::Edition2018
+    }
+
+    /// Returns `true` if the token is either a special identifier or a keyword.
+    pub fn is_reserved(self) -> bool {
+        self.is_special() || self.is_used_keyword() || self.is_unused_keyword()
+    }
+
+    /// A keyword or reserved identifier that can be used as a path segment.
+    pub fn is_path_segment_keyword(self) -> bool {
+        self.name == keywords::Super.name() ||
+        self.name == keywords::SelfValue.name() ||
+        self.name == keywords::SelfType.name() ||
+        self.name == keywords::Extern.name() ||
+        self.name == keywords::Crate.name() ||
+        self.name == keywords::CrateRoot.name() ||
+        self.name == keywords::DollarCrate.name()
+    }
+
+    // We see this identifier in a normal identifier position, like variable name or a type.
+    // How was it written originally? Did it use the raw form? Let's try to guess.
+    pub fn is_raw_guess(self) -> bool {
+        self.name != keywords::Invalid.name() &&
+        self.is_reserved() && !self.is_path_segment_keyword()
+    }
 }
 
 // If an interner exists, return it. Otherwise, prepare a fresh one.
diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs
index 8e5fa00b5f2..f94780682a0 100644
--- a/src/libtest/formatters/pretty.rs
+++ b/src/libtest/formatters/pretty.rs
@@ -101,7 +101,7 @@ impl<T: Write> PrettyFormatter<T> {
         for &(ref f, ref stdout) in &state.not_failures {
             successes.push(f.name.to_string());
             if !stdout.is_empty() {
-                stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 stdouts.push_str(&output);
                 stdouts.push_str("\n");
@@ -127,7 +127,7 @@ impl<T: Write> PrettyFormatter<T> {
         for &(ref f, ref stdout) in &state.failures {
             failures.push(f.name.to_string());
             if !stdout.is_empty() {
-                fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 fail_out.push_str(&output);
                 fail_out.push_str("\n");
diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs
index 85286027d69..22a06b9f605 100644
--- a/src/libtest/formatters/terse.rs
+++ b/src/libtest/formatters/terse.rs
@@ -105,7 +105,7 @@ impl<T: Write> TerseFormatter<T> {
         for &(ref f, ref stdout) in &state.not_failures {
             successes.push(f.name.to_string());
             if !stdout.is_empty() {
-                stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 stdouts.push_str(&output);
                 stdouts.push_str("\n");
@@ -131,7 +131,7 @@ impl<T: Write> TerseFormatter<T> {
         for &(ref f, ref stdout) in &state.failures {
             failures.push(f.name.to_string());
             if !stdout.is_empty() {
-                fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 fail_out.push_str(&output);
                 fail_out.push_str("\n");
diff --git a/src/llvm b/src/llvm
-Subproject 1abfd0e562cc8f7a9577d97ee92246699093b95
+Subproject 56c931901cfb85cd6f7ed44c7d7520a8de1edf9
diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs
index 7d5581bb774..8ff401164c1 100644
--- a/src/rtstartup/rsbegin.rs
+++ b/src/rtstartup/rsbegin.rs
@@ -23,7 +23,7 @@
 // of other runtime components (registered via yet another special image section).
 
 #![feature(no_core, lang_items, optin_builtin_traits)]
-#![crate_type="rlib"]
+#![crate_type = "rlib"]
 #![no_core]
 #![allow(non_camel_case_types)]
 
@@ -43,7 +43,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     drop_in_place(to_drop);
 }
 
-#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
+#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))]
 pub mod eh_frames {
     #[no_mangle]
     #[link_section = ".eh_frame"]
@@ -54,6 +54,21 @@ pub mod eh_frames {
     // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h.
     static mut OBJ: [isize; 6] = [0; 6];
 
+    macro_rules! impl_copy {
+        ($($t:ty)*) => {
+            $(
+                impl ::Copy for $t {}
+            )*
+        }
+    }
+
+    impl_copy! {
+        usize u8 u16 u32 u64 u128
+        isize i8 i16 i32 i64 i128
+        f32 f64
+        bool char
+    }
+
     // Unwind info registration/deregistration routines.
     // See the docs of `unwind` module in libstd.
     extern "C" {
@@ -63,14 +78,18 @@ pub mod eh_frames {
 
     unsafe fn init() {
         // register unwind info on module startup
-        rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8,
-                                &mut OBJ as *mut _ as *mut u8);
+        rust_eh_register_frames(
+            &__EH_FRAME_BEGIN__ as *const u8,
+            &mut OBJ as *mut _ as *mut u8,
+        );
     }
 
     unsafe fn uninit() {
         // unregister on shutdown
-        rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8,
-                                  &mut OBJ as *mut _ as *mut u8);
+        rust_eh_unregister_frames(
+            &__EH_FRAME_BEGIN__ as *const u8,
+            &mut OBJ as *mut _ as *mut u8,
+        );
     }
 
     // MSVC-specific init/uninit routine registration
diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml
index 9986e0b512a..9ccd37a6a45 100644
--- a/src/rustc/Cargo.toml
+++ b/src/rustc/Cargo.toml
@@ -4,7 +4,7 @@ name = "rustc-main"
 version = "0.0.0"
 
 [[bin]]
-name = "rustc"
+name = "rustc_binary"
 path = "rustc.rs"
 
 [dependencies]
diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger
index c3fc3e5452c..5a0292bb6a1 100644
--- a/src/rustllvm/llvm-rebuild-trigger
+++ b/src/rustllvm/llvm-rebuild-trigger
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2018-04-05
+2018-05-18
\ No newline at end of file
diff --git a/src/stage0.txt b/src/stage0.txt
index a5ad2b315a1..435cfd2f6db 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.x.0` for Cargo where they were released on `date`.
 
-date: 2018-04-24
+date: 2018-05-10
 rustc: beta
 cargo: beta
 
diff --git a/src/test/COMPILER_TESTS.md b/src/test/COMPILER_TESTS.md
index 29f1e2e5b78..7dabb1bddea 100644
--- a/src/test/COMPILER_TESTS.md
+++ b/src/test/COMPILER_TESTS.md
@@ -140,13 +140,9 @@ check that the test compiles successfully.
 ### Editing and updating the reference files
 
 If you have changed the compiler's output intentionally, or you are
-making a new test, you can use the script `ui/update-references.sh` to
-update the references. When you run the test framework, it will report
-various errors: in those errors is a command you can use to run the
-`ui/update-references.sh` script, which will then copy over the files
-from the build directory and use them as the new reference. You can
-also just run `ui/update-all-references.sh`. In both cases, you can run
-the script with `--help` to get a help message.
+making a new test, you can pass `--bless` to the command you used to
+run the tests. This will then copy over the files
+from the build directory and use them as the new reference.
 
 ### Normalization
 
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index 40a9ea5a181..e3fa7a7db39 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -10,6 +10,7 @@
 
 // compile-flags: -C no-prepopulate-passes
 // ignore-tidy-linelength
+// min-llvm-version 6.0
 
 #![crate_type = "lib"]
 #![feature(custom_attribute)]
@@ -52,16 +53,14 @@ pub fn named_borrow<'r>(_: &'r i32) {
 pub fn unsafe_borrow(_: &UnsafeInner) {
 }
 
-// CHECK: @mutable_unsafe_borrow(i16* dereferenceable(2) %arg0)
+// CHECK: @mutable_unsafe_borrow(i16* noalias dereferenceable(2) %arg0)
 // ... unless this is a mutable borrow, those never alias
-// ... except that there's this LLVM bug that forces us to not use noalias, see #29485
 #[no_mangle]
 pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 }
 
-// CHECK: @mutable_borrow(i32* dereferenceable(4) %arg0)
+// CHECK: @mutable_borrow(i32* noalias dereferenceable(4) %arg0)
 // FIXME #25759 This should also have `nocapture`
-// ... there's this LLVM bug that forces us to not use noalias, see #29485
 #[no_mangle]
 pub fn mutable_borrow(_: &mut i32) {
 }
@@ -103,9 +102,8 @@ pub fn helper(_: usize) {
 pub fn slice(_: &[u8]) {
 }
 
-// CHECK: @mutable_slice([0 x i8]* nonnull %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @mutable_slice([0 x i8]* noalias nonnull %arg0.0, [[USIZE]] %arg0.1)
 // FIXME #25759 This should also have `nocapture`
-// ... there's this LLVM bug that forces us to not use noalias, see #29485
 #[no_mangle]
 pub fn mutable_slice(_: &mut [u8]) {
 }
diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs
index 1879002e7f3..415ee6eb7ea 100644
--- a/src/test/codegen/link_section.rs
+++ b/src/test/codegen/link_section.rs
@@ -12,11 +12,17 @@
 
 #![crate_type = "lib"]
 
-// CHECK: @VAR1 = constant i32 1, section ".test_one"
+// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
 #[no_mangle]
 #[link_section = ".test_one"]
+#[cfg(target_endian = "little")]
 pub static VAR1: u32 = 1;
 
+#[no_mangle]
+#[link_section = ".test_one"]
+#[cfg(target_endian = "big")]
+pub static VAR1: u32 = 0x01000000;
+
 pub enum E {
     A(u32),
     B(f32)
diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs
index 9b9deb4ca8d..91007fcd63a 100644
--- a/src/test/compile-fail/array_const_index-0.rs
+++ b/src/test/compile-fail/array_const_index-0.rs
@@ -10,9 +10,8 @@
 
 const A: &'static [i32] = &[];
 const B: i32 = (&A)[1];
-//~^ ERROR constant evaluation error
-//~| index out of bounds: the len is 0 but the index is 1
-//~| WARN this constant cannot be used
+//~^ index out of bounds: the len is 0 but the index is 1
+//~| ERROR this constant cannot be used
 
 fn main() {
     let _ = B;
diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs
index 46feb20cf11..66739d308a7 100644
--- a/src/test/compile-fail/array_const_index-1.rs
+++ b/src/test/compile-fail/array_const_index-1.rs
@@ -10,9 +10,8 @@
 
 const A: [i32; 0] = [];
 const B: i32 = A[1];
-//~^ ERROR constant evaluation error
-//~| index out of bounds: the len is 0 but the index is 1
-//~| WARN this constant cannot be used
+//~^ index out of bounds: the len is 0 but the index is 1
+//~| ERROR this constant cannot be used
 
 fn main() {
     let _ = B;
diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs
index 7da5a2f17ea..6d51ff30998 100644
--- a/src/test/compile-fail/const-slice-oob.rs
+++ b/src/test/compile-fail/const-slice-oob.rs
@@ -12,9 +12,8 @@
 
 const FOO: &'static[u32] = &[1, 2, 3];
 const BAR: u32 = FOO[5];
-//~^ ERROR constant evaluation error [E0080]
-//~| index out of bounds: the len is 3 but the index is 5
-//~| WARN this constant cannot be used
+//~^ index out of bounds: the len is 3 but the index is 5
+//~| ERROR this constant cannot be used
 
 fn main() {
     let _ = BAR;
diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs
index 49f76c532df..73156168602 100644
--- a/src/test/compile-fail/eval-enum.rs
+++ b/src/test/compile-fail/eval-enum.rs
@@ -12,11 +12,11 @@ enum Test {
     DivZero = 1/0,
     //~^ attempt to divide by zero
     //~| ERROR constant evaluation error
-    //~| WARN constant evaluation error
+    //~| ERROR constant evaluation error
     RemZero = 1%0,
     //~^ attempt to calculate the remainder with a divisor of zero
     //~| ERROR constant evaluation error
-    //~| WARN constant evaluation error
+    //~| ERROR constant evaluation error
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-38293.rs b/src/test/compile-fail/issue-38293.rs
index bd352b204bd..1867bafa7e3 100644
--- a/src/test/compile-fail/issue-38293.rs
+++ b/src/test/compile-fail/issue-38293.rs
@@ -10,23 +10,17 @@
 
 // Test that `fn foo::bar::{self}` only imports `bar` in the type namespace.
 
-#![allow(unused)]
-
 mod foo {
     pub fn f() { }
 }
-use foo::f::{self};
-//~^ ERROR `self` no longer imports values
-//~| WARN hard error
+use foo::f::{self}; //~ ERROR unresolved import `foo::f`
 
 mod bar {
     pub fn baz() {}
     pub mod baz {}
 }
 use bar::baz::{self};
-//~^ ERROR `self` no longer imports values
-//~| WARN hard error
 
 fn main() {
-    baz();
+    baz(); //~ ERROR expected function, found module `baz`
 }
diff --git a/src/test/incremental/warnings-reemitted.rs b/src/test/incremental/warnings-reemitted.rs
index d50ffff5c1e..1ea436d8ad1 100644
--- a/src/test/incremental/warnings-reemitted.rs
+++ b/src/test/incremental/warnings-reemitted.rs
@@ -13,6 +13,7 @@
 // compile-pass
 
 #![allow(warnings)]
+#![warn(const_err)]
 
 fn main() {
     255u8 + 1; //~ WARNING this expression will panic at run-time
diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs
index e189f2e3b34..15b104f6c2f 100644
--- a/src/test/mir-opt/end_region_destruction_extents_1.rs
+++ b/src/test/mir-opt/end_region_destruction_extents_1.rs
@@ -130,17 +130,21 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 //     let mut _7: &'10s S1;
 //     let mut _8: &'10s S1;
 //     let mut _9: S1;
+//     let mut _10: &'10s S1;
+//     let mut _11: &'12ds S1;
 //
 //     bb0: {
 //         StorageLive(_2);
 //         StorageLive(_3);
 //         StorageLive(_4);
 //         StorageLive(_5);
-//         _5 = promoted[1];
+//         _11 = promoted[1];
+//         _5 = &'12ds (*_11);
 //         _4 = &'12ds (*_5);
 //         StorageLive(_7);
 //         StorageLive(_8);
-//         _8 = promoted[0];
+//         _10 = promoted[0];
+//         _8 = &'10s (*_10);
 //         _7 = &'10s (*_8);
 //         _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7);
 //         EndRegion('10s);
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index a31298a0f51..c2a40399efe 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -88,7 +88,8 @@ fn main() {
 //  }
 //  bb9: { // binding1 and guard
 //      StorageLive(_5);
-//      _5 = &((_2 as Some).0: i32);
+//      _11 = promoted[0];
+//      _5 = &(((*_11) as Some).0: i32);
 //      StorageLive(_8);
 //      _8 = const guard() -> [return: bb10, unwind: bb1];
 //  }
diff --git a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs
index 153739133ac..62064fa94f2 100644
--- a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs
+++ b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs
@@ -13,6 +13,9 @@
 // borrows in `&v[0]` and `&v[1]` each (in theory) have to outlive R3,
 // but only at a particular point, and hence they wind up including
 // distinct regions.
+//
+// FIXME(#43234) -- Well, this used to be true, but we modified NLL
+// for the time being to not take location into account.
 
 // compile-flags:-Zborrowck=mir -Zverbose
 //                              ^^^^^^^^^ force compiler to dump more region information
@@ -36,9 +39,9 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#2r    | {bb2[0..=1], bb3[0..=1]}
+// | '_#2r    | {bb2[0..=1], bb3[0..=1], bb8[2..=4]}
 // ...
-// | '_#4r    | {bb8[1..=4]}
+// | '_#4r    | {bb2[1], bb3[0..=1], bb8[1..=4]}
 // | '_#5r    | {bb2[1], bb3[0..=1], bb8[2..=4]}
 // ...
 // let mut _2: &'_#5r usize;
diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs
index 250f0726dc9..584701410ef 100644
--- a/src/test/run-fail/overflowing-add.rs
+++ b/src/test/run-fail/overflowing-add.rs
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to add with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let _x = 200u8 + 200u8 + 200u8;
 }
diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs
index b47d0fc4136..5d6f59e0229 100644
--- a/src/test/run-fail/overflowing-mul.rs
+++ b/src/test/run-fail/overflowing-mul.rs
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to multiply with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let x = 200u8 * 4;
 }
diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs
index 836d7e37319..e7c518f1286 100644
--- a/src/test/run-fail/overflowing-neg.rs
+++ b/src/test/run-fail/overflowing-neg.rs
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to negate with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let _x = -std::i8::MIN;
 }
diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs
index f94cb31b168..404921a1af5 100644
--- a/src/test/run-fail/overflowing-sub.rs
+++ b/src/test/run-fail/overflowing-sub.rs
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to subtract with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let _x = 42u8 - (42u8 + 1);
 }
diff --git a/src/test/run-make-fulldeps/issue-36710/Makefile b/src/test/run-make-fulldeps/issue-36710/Makefile
deleted file mode 100644
index 2cb0b4ccf26..00000000000
--- a/src/test/run-make-fulldeps/issue-36710/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
--include ../tools.mk
-
-all: foo
-	$(call RUN,foo)
-
-foo: foo.rs $(call NATIVE_STATICLIB,foo)
-	$(RUSTC) $< -lfoo $(EXTRACXXFLAGS)
-
-$(TMPDIR)/libfoo.o: foo.cpp
-	$(call COMPILE_OBJ_CXX,$@,$<)
-
-.PHONY: all
diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk
index 3de358fa500..af1707de6c0 100644
--- a/src/test/run-make-fulldeps/tools.mk
+++ b/src/test/run-make-fulldeps/tools.mk
@@ -59,14 +59,12 @@ endif
 
 ifdef IS_MSVC
 COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
-COMPILE_OBJ_CXX = $(CXX) -c -Fo:`cygpath -w $(1)` $(2)
 NATIVE_STATICLIB_FILE = $(1).lib
 NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
 OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
 	-Fo:`cygpath -w $(TMPDIR)/$(1).obj`
 else
 COMPILE_OBJ = $(CC) -c -o $(1) $(2)
-COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
 NATIVE_STATICLIB_FILE = lib$(1).a
 NATIVE_STATICLIB = $(call STATICLIB,$(1))
 OUT_EXE=-o $(TMPDIR)/$(1)
diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
index 231ed2898f1..d7ede763838 100644
--- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
@@ -20,6 +20,7 @@ extern crate rustc_plugin;
 
 use std::borrow::ToOwned;
 use syntax::ast;
+use syntax::ext::hygiene;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
 use syntax::print::pprust;
@@ -54,5 +55,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
             allow_internal_unstable: false,
             allow_internal_unsafe: false,
             unstable_feature: None,
+            edition: hygiene::default_edition(),
         });
 }
diff --git a/src/test/run-pass/auxiliary/edition-kw-macro-2015.rs b/src/test/run-pass/auxiliary/edition-kw-macro-2015.rs
new file mode 100644
index 00000000000..9127c8e350a
--- /dev/null
+++ b/src/test/run-pass/auxiliary/edition-kw-macro-2015.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
diff --git a/src/test/run-pass/auxiliary/edition-kw-macro-2018.rs b/src/test/run-pass/auxiliary/edition-kw-macro-2018.rs
new file mode 100644
index 00000000000..4fef77d67ea
--- /dev/null
+++ b/src/test/run-pass/auxiliary/edition-kw-macro-2018.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
diff --git a/src/test/run-pass/edition-keywords-2015-2015.rs b/src/test/run-pass/edition-keywords-2015-2015.rs
new file mode 100644
index 00000000000..41480bb978e
--- /dev/null
+++ b/src/test/run-pass/edition-keywords-2015-2015.rs
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    one_async::async(); // OK
+    one_async::r#async(); // OK
+    two_async::async(); // OK
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/edition-keywords-2015-2018.rs b/src/test/run-pass/edition-keywords-2015-2018.rs
new file mode 100644
index 00000000000..78835d51063
--- /dev/null
+++ b/src/test/run-pass/edition-keywords-2015-2018.rs
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    // one_async::async(); // ERROR, unresolved name
+    // one_async::r#async(); // ERROR, unresolved name
+    two_async::async(); // OK
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    // produces_async! {} // ERROR, reserved
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/edition-keywords-2018-2015.rs b/src/test/run-pass/edition-keywords-2018-2015.rs
new file mode 100644
index 00000000000..46d5f222cbb
--- /dev/null
+++ b/src/test/run-pass/edition-keywords-2018-2015.rs
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    // let mut async = 1; // ERROR, reserved
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    // if passes_ident!(async) == 1 {} // ERROR, reserved
+    if passes_ident!(r#async) == 1 {} // OK
+    // one_async::async(); // ERROR, reserved
+    one_async::r#async(); // OK
+    // two_async::async(); // ERROR, reserved
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/edition-keywords-2018-2018.rs b/src/test/run-pass/edition-keywords-2018-2018.rs
new file mode 100644
index 00000000000..06482988937
--- /dev/null
+++ b/src/test/run-pass/edition-keywords-2018-2018.rs
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    // let mut async = 1; // ERROR, reserved
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    // if passes_ident!(async) == 1 {} // ERROR, reserved
+    if passes_ident!(r#async) == 1 {} // OK
+    // one_async::async(); // ERROR, reserved
+    // one_async::r#async(); // ERROR, unresolved name
+    // two_async::async(); // ERROR, reserved
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    // produces_async! {} // ERROR, reserved
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-49955-2.rs b/src/test/run-pass/issue-49955-2.rs
new file mode 100644
index 00000000000..17e1de95dd3
--- /dev/null
+++ b/src/test/run-pass/issue-49955-2.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z borrowck=mir
+
+use std::cell::Cell;
+
+#[inline(never)]
+fn tuple_field() -> &'static u32 {
+    // This test is MIR-borrowck-only because the old borrowck
+    // doesn't agree that borrows of "frozen" (i.e. without any
+    // interior mutability) fields of non-frozen temporaries,
+    // should be promoted, while MIR promotion does promote them.
+    &(Cell::new(5), 42).1
+}
+
+fn main() {
+    assert_eq!(tuple_field().to_string(), "42");
+}
diff --git a/src/test/run-pass/issue-49955.rs b/src/test/run-pass/issue-49955.rs
new file mode 100644
index 00000000000..57a1264aaee
--- /dev/null
+++ b/src/test/run-pass/issue-49955.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z borrowck=compare
+
+const ALL_THE_NUMS: [u32; 1] = [
+    1
+];
+
+#[inline(never)]
+fn array(i: usize) -> &'static u32 {
+    return &ALL_THE_NUMS[i];
+}
+
+#[inline(never)]
+fn tuple_field() -> &'static u32 {
+    &(42,).0
+}
+
+fn main() {
+    assert_eq!(tuple_field().to_string(), "42");
+    assert_eq!(array(0).to_string(), "1");
+}
diff --git a/src/test/run-pass/nll/get_default.rs b/src/test/run-pass/nll/get_default.rs
deleted file mode 100644
index 13ef907d8d0..00000000000
--- a/src/test/run-pass/nll/get_default.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(nll)]
-
-use std::collections::HashMap;
-
-fn get_default(map: &mut HashMap<usize, String>, key: usize) -> &mut String {
-    match map.get_mut(&key) {
-        Some(value) => value,
-        None => {
-            map.insert(key, "".to_string());
-            map.get_mut(&key).unwrap()
-        }
-    }
-}
-
-fn main() {
-    let map = &mut HashMap::new();
-    map.insert(22, format!("Hello, world"));
-    map.insert(44, format!("Goodbye, world"));
-    assert_eq!(&*get_default(map, 22), "Hello, world");
-    assert_eq!(&*get_default(map, 66), "");
-}
diff --git a/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs b/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs
new file mode 100644
index 00000000000..d5cf122bf3b
--- /dev/null
+++ b/src/test/run-pass/nll/issue-50461-used-mut-from-moves.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.
+
+#![feature(nll)]
+#![deny(unused_mut)]
+
+struct Foo {
+    pub value: i32
+}
+
+fn use_foo_mut(mut foo: Foo) {
+    foo = foo;
+    println!("{}", foo.value);
+}
+
+fn main() {
+    use_foo_mut(Foo { value: 413 });
+}
diff --git a/src/test/rustdoc/auto-impl-primitive.rs b/src/test/rustdoc/auto-impl-primitive.rs
new file mode 100644
index 00000000000..a3887b33cc2
--- /dev/null
+++ b/src/test/rustdoc/auto-impl-primitive.rs
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+pub use std::fs::File;
+
+// @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation'
+#[doc(primitive = "i16")]
+/// I love poneys!
+mod prim {}
diff --git a/src/test/ui/E0508.ast.nll.stderr b/src/test/ui/E0508.ast.nll.stderr
new file mode 100644
index 00000000000..28403644a23
--- /dev/null
+++ b/src/test/ui/E0508.ast.nll.stderr
@@ -0,0 +1,9 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508.rs:18:18
+   |
+LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
+   |                  ^^^^^^^^ cannot move out of here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/src/test/ui/E0508.ast.stderr b/src/test/ui/E0508.ast.stderr
new file mode 100644
index 00000000000..5878b795b77
--- /dev/null
+++ b/src/test/ui/E0508.ast.stderr
@@ -0,0 +1,12 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508.rs:18:18
+   |
+LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
+   |                  ^^^^^^^^
+   |                  |
+   |                  cannot move out of here
+   |                  help: consider using a reference instead: `&array[0]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/src/test/ui/E0508.mir.stderr b/src/test/ui/E0508.mir.stderr
new file mode 100644
index 00000000000..28403644a23
--- /dev/null
+++ b/src/test/ui/E0508.mir.stderr
@@ -0,0 +1,9 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508.rs:18:18
+   |
+LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
+   |                  ^^^^^^^^ cannot move out of here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/src/test/ui/E0508.rs b/src/test/ui/E0508.rs
new file mode 100644
index 00000000000..0c3dce6b034
--- /dev/null
+++ b/src/test/ui/E0508.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.
+
+// revisions: ast mir
+//[mir]compile-flags: -Z borrowck=mir
+
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = array[0];  //[ast]~ ERROR [E0508]
+                            //[mir]~^ ERROR [E0508]
+}
diff --git a/src/test/ui/auxiliary/edition-kw-macro-2015.rs b/src/test/ui/auxiliary/edition-kw-macro-2015.rs
new file mode 100644
index 00000000000..9127c8e350a
--- /dev/null
+++ b/src/test/ui/auxiliary/edition-kw-macro-2015.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
diff --git a/src/test/ui/auxiliary/edition-kw-macro-2018.rs b/src/test/ui/auxiliary/edition-kw-macro-2018.rs
new file mode 100644
index 00000000000..4fef77d67ea
--- /dev/null
+++ b/src/test/ui/auxiliary/edition-kw-macro-2018.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr b/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr
index fc288e6b1d6..2284f0784c5 100644
--- a/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr
+++ b/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr
@@ -2,19 +2,28 @@ error[E0499]: cannot borrow `*arg` as mutable more than once at a time
   --> $DIR/mut-borrow-in-loop.rs:20:25
    |
 LL |             (self.func)(arg) //~ ERROR cannot borrow
-   |                         ^^^ mutable borrow starts here in previous iteration of loop
+   |             ------------^^^-
+   |             |           |
+   |             |           mutable borrow starts here in previous iteration of loop
+   |             borrow later used here
 
 error[E0499]: cannot borrow `*arg` as mutable more than once at a time
   --> $DIR/mut-borrow-in-loop.rs:26:25
    |
 LL |             (self.func)(arg) //~ ERROR cannot borrow
-   |                         ^^^ mutable borrow starts here in previous iteration of loop
+   |             ------------^^^-
+   |             |           |
+   |             |           mutable borrow starts here in previous iteration of loop
+   |             borrow later used here
 
 error[E0499]: cannot borrow `*arg` as mutable more than once at a time
   --> $DIR/mut-borrow-in-loop.rs:33:25
    |
 LL |             (self.func)(arg) //~ ERROR cannot borrow
-   |                         ^^^ mutable borrow starts here in previous iteration of loop
+   |             ------------^^^-
+   |             |           |
+   |             |           mutable borrow starts here in previous iteration of loop
+   |             borrow later used here
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-eval-overflow-2.rs b/src/test/ui/const-eval-overflow-2.rs
index 885edb55ed8..63f33cafaf8 100644
--- a/src/test/ui/const-eval-overflow-2.rs
+++ b/src/test/ui/const-eval-overflow-2.rs
@@ -11,7 +11,7 @@
 // Evaluation of constants in refutable patterns goes through
 // different compiler control-flow paths.
 
-#![allow(unused_imports, warnings)]
+#![allow(unused_imports, warnings, const_err)]
 
 use std::fmt;
 use std::{i8, i16, i32, i64, isize};
diff --git a/src/test/ui/const-eval-overflow-4.rs b/src/test/ui/const-eval-overflow-4.rs
index 24e178152ee..ed14036b0b4 100644
--- a/src/test/ui/const-eval-overflow-4.rs
+++ b/src/test/ui/const-eval-overflow-4.rs
@@ -22,7 +22,7 @@ use std::{u8, u16, u32, u64, usize};
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1i8) as usize]
     //~^ ERROR E0080
-    //~| WARN attempt to add with overflow
+    //~| ERROR attempt to add with overflow
     = [0; (i8::MAX as usize) + 1];
 
 fn main() {
diff --git a/src/test/ui/const-eval-overflow-4.stderr b/src/test/ui/const-eval-overflow-4.stderr
index db0a6fc8204..fc4762f0554 100644
--- a/src/test/ui/const-eval-overflow-4.stderr
+++ b/src/test/ui/const-eval-overflow-4.stderr
@@ -1,10 +1,10 @@
-warning: attempt to add with overflow
+error: attempt to add with overflow
   --> $DIR/const-eval-overflow-4.rs:23:13
    |
 LL |     : [u32; (i8::MAX as i8 + 1i8) as usize]
    |             ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: #[warn(const_err)] on by default
+   = note: #[deny(const_err)] on by default
 
 error[E0080]: constant evaluation error
   --> $DIR/const-eval-overflow-4.rs:23:13
@@ -12,6 +12,6 @@ error[E0080]: constant evaluation error
 LL |     : [u32; (i8::MAX as i8 + 1i8) as usize]
    |             ^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-eval/conditional_array_execution.rs b/src/test/ui/const-eval/conditional_array_execution.rs
index dbddee862e0..8952a8386d7 100644
--- a/src/test/ui/const-eval/conditional_array_execution.rs
+++ b/src/test/ui/const-eval/conditional_array_execution.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 const X: u32 = 5;
 const Y: u32 = 6;
diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr
index 713b1b36c08..5cf73b9fad6 100644
--- a/src/test/ui/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/const-eval/conditional_array_execution.stderr
@@ -1,19 +1,23 @@
 warning: attempt to subtract with overflow
-  --> $DIR/conditional_array_execution.rs:15:19
+  --> $DIR/conditional_array_execution.rs:16:19
    |
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
    |                   ^^^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/conditional_array_execution.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/conditional_array_execution.rs:15:1
+  --> $DIR/conditional_array_execution.rs:16:1
    |
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: constant evaluation error
-  --> $DIR/conditional_array_execution.rs:20:20
+  --> $DIR/conditional_array_execution.rs:21:20
    |
 LL |     println!("{}", FOO);
    |                    ^^^ referenced constant has errors
diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs
index 097fba4d3c4..7ec100e411b 100644
--- a/src/test/ui/const-eval/issue-43197.rs
+++ b/src/test/ui/const-eval/issue-43197.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 #![feature(const_fn)]
 
diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr
index a22e8016296..d0e13d5657e 100644
--- a/src/test/ui/const-eval/issue-43197.stderr
+++ b/src/test/ui/const-eval/issue-43197.stderr
@@ -1,37 +1,41 @@
 warning: attempt to subtract with overflow
-  --> $DIR/issue-43197.rs:20:20
+  --> $DIR/issue-43197.rs:21:20
    |
 LL |     const X: u32 = 0-1;
    |                    ^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/issue-43197.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/issue-43197.rs:20:5
+  --> $DIR/issue-43197.rs:21:5
    |
 LL |     const X: u32 = 0-1;
    |     ^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to subtract with overflow
-  --> $DIR/issue-43197.rs:23:24
+  --> $DIR/issue-43197.rs:24:24
    |
 LL |     const Y: u32 = foo(0-1);
    |                        ^^^
 
 warning: this constant cannot be used
-  --> $DIR/issue-43197.rs:23:5
+  --> $DIR/issue-43197.rs:24:5
    |
 LL |     const Y: u32 = foo(0-1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: constant evaluation error
-  --> $DIR/issue-43197.rs:26:23
+  --> $DIR/issue-43197.rs:27:23
    |
 LL |     println!("{} {}", X, Y);
    |                       ^ referenced constant has errors
 
 warning: constant evaluation error
-  --> $DIR/issue-43197.rs:26:26
+  --> $DIR/issue-43197.rs:27:26
    |
 LL |     println!("{} {}", X, Y);
    |                          ^ referenced constant has errors
diff --git a/src/test/ui/const-eval/issue-44578.rs b/src/test/ui/const-eval/issue-44578.rs
index 765113cfbb9..4133a8864f6 100644
--- a/src/test/ui/const-eval/issue-44578.rs
+++ b/src/test/ui/const-eval/issue-44578.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 trait Foo {
     const AMT: usize;
diff --git a/src/test/ui/const-eval/issue-44578.stderr b/src/test/ui/const-eval/issue-44578.stderr
index 01c6fa3623f..ce6ff86610a 100644
--- a/src/test/ui/const-eval/issue-44578.stderr
+++ b/src/test/ui/const-eval/issue-44578.stderr
@@ -1,13 +1,17 @@
 warning: constant evaluation error
-  --> $DIR/issue-44578.rs:35:20
+  --> $DIR/issue-44578.rs:36:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/issue-44578.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/issue-44578.rs:35:20
+  --> $DIR/issue-44578.rs:36:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
diff --git a/src/test/ui/const-eval/issue-50706.rs b/src/test/ui/const-eval/issue-50706.rs
new file mode 100644
index 00000000000..2b0082d95b3
--- /dev/null
+++ b/src/test/ui/const-eval/issue-50706.rs
@@ -0,0 +1,47 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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-pass
+
+pub struct Stats;
+
+#[derive(PartialEq, Eq)]
+pub struct StatVariant {
+    pub id: u8,
+    _priv: (),
+}
+
+#[derive(PartialEq, Eq)]
+pub struct Stat {
+    pub variant: StatVariant,
+    pub index: usize,
+    _priv: (),
+}
+
+impl Stats {
+    pub const TEST: StatVariant = StatVariant{id: 0, _priv: (),};
+    #[allow(non_upper_case_globals)]
+    pub const A: Stat = Stat{
+         variant: Self::TEST,
+         index: 0,
+         _priv: (),};
+}
+
+impl Stat {
+    pub fn from_index(variant: StatVariant, index: usize) -> Option<Stat> {
+        let stat = Stat{variant, index, _priv: (),};
+        match stat {
+            Stats::A => Some(Stats::A),
+            _ => None,
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-eval/promoted_errors.rs b/src/test/ui/const-eval/promoted_errors.rs
index dc30c7f9cce..7385860abae 100644
--- a/src/test/ui/const-eval/promoted_errors.rs
+++ b/src/test/ui/const-eval/promoted_errors.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![warn(const_err)]
+
 // compile-pass
 // compile-flags: -O
 fn main() {
diff --git a/src/test/ui/const-eval/promoted_errors.stderr b/src/test/ui/const-eval/promoted_errors.stderr
index 7761f192fdb..8e9a0ea43a4 100644
--- a/src/test/ui/const-eval/promoted_errors.stderr
+++ b/src/test/ui/const-eval/promoted_errors.stderr
@@ -1,49 +1,53 @@
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:14:20
+  --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 0u32 - 1);
    |                    ^^^^^^^^ attempt to subtract with overflow
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:14:20
+  --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 0u32 - 1);
    |                    ^^^^^^^^ attempt to subtract with overflow
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:17:14
+  --> $DIR/promoted_errors.rs:19:14
    |
 LL |     let _x = 0u32 - 1;
    |              ^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:19:20
+  --> $DIR/promoted_errors.rs:21:20
    |
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:19:20
+  --> $DIR/promoted_errors.rs:21:20
    |
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^ attempt to divide by zero
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:22:14
+  --> $DIR/promoted_errors.rs:24:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:22:14
+  --> $DIR/promoted_errors.rs:24:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^ attempt to divide by zero
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:25:20
+  --> $DIR/promoted_errors.rs:27:20
    |
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^ attempt to divide by zero
diff --git a/src/test/ui/const-eval/pub_const_err.rs b/src/test/ui/const-eval/pub_const_err.rs
index c6bf07649af..ef8fdb33d74 100644
--- a/src/test/ui/const-eval/pub_const_err.rs
+++ b/src/test/ui/const-eval/pub_const_err.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 #![crate_type = "lib"]
 
diff --git a/src/test/ui/const-eval/pub_const_err.stderr b/src/test/ui/const-eval/pub_const_err.stderr
index 2981ac20cd9..068825f1cd3 100644
--- a/src/test/ui/const-eval/pub_const_err.stderr
+++ b/src/test/ui/const-eval/pub_const_err.stderr
@@ -1,25 +1,29 @@
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err.rs:15:20
+  --> $DIR/pub_const_err.rs:16:20
    |
 LL | pub const Z: u32 = 0 - 1;
    |                    ^^^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/pub_const_err.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/pub_const_err.rs:15:1
+  --> $DIR/pub_const_err.rs:16:1
    |
 LL | pub const Z: u32 = 0 - 1;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err.rs:19:22
+  --> $DIR/pub_const_err.rs:20:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^
 
 warning: this array length cannot be used
-  --> $DIR/pub_const_err.rs:19:22
+  --> $DIR/pub_const_err.rs:20:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^ attempt to subtract with overflow
diff --git a/src/test/ui/const-eval/pub_const_err_bin.rs b/src/test/ui/const-eval/pub_const_err_bin.rs
index d87cb7ed770..f65da1d8674 100644
--- a/src/test/ui/const-eval/pub_const_err_bin.rs
+++ b/src/test/ui/const-eval/pub_const_err_bin.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 pub const Z: u32 = 0 - 1;
 //~^ WARN attempt to subtract with overflow
diff --git a/src/test/ui/const-eval/pub_const_err_bin.stderr b/src/test/ui/const-eval/pub_const_err_bin.stderr
index 3e8966d854b..dcb8125fc55 100644
--- a/src/test/ui/const-eval/pub_const_err_bin.stderr
+++ b/src/test/ui/const-eval/pub_const_err_bin.stderr
@@ -1,25 +1,29 @@
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err_bin.rs:13:20
+  --> $DIR/pub_const_err_bin.rs:14:20
    |
 LL | pub const Z: u32 = 0 - 1;
    |                    ^^^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/pub_const_err_bin.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/pub_const_err_bin.rs:13:1
+  --> $DIR/pub_const_err_bin.rs:14:1
    |
 LL | pub const Z: u32 = 0 - 1;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err_bin.rs:17:22
+  --> $DIR/pub_const_err_bin.rs:18:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^
 
 warning: this array length cannot be used
-  --> $DIR/pub_const_err_bin.rs:17:22
+  --> $DIR/pub_const_err_bin.rs:18:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^ attempt to subtract with overflow
diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs
index ee07dabab1f..453e332a903 100644
--- a/src/test/ui/const-len-underflow-separate-spans.rs
+++ b/src/test/ui/const-len-underflow-separate-spans.rs
@@ -16,7 +16,7 @@ const ONE: usize = 1;
 const TWO: usize = 2;
 const LEN: usize = ONE - TWO;
 //~^ ERROR E0080
-//~| WARN attempt to subtract with overflow
+//~| ERROR attempt to subtract with overflow
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr
index 8d737dbfc08..48ff7a81c24 100644
--- a/src/test/ui/const-len-underflow-separate-spans.stderr
+++ b/src/test/ui/const-len-underflow-separate-spans.stderr
@@ -1,10 +1,10 @@
-warning: attempt to subtract with overflow
+error: attempt to subtract with overflow
   --> $DIR/const-len-underflow-separate-spans.rs:17:20
    |
 LL | const LEN: usize = ONE - TWO;
    |                    ^^^^^^^^^
    |
-   = note: #[warn(const_err)] on by default
+   = note: #[deny(const_err)] on by default
 
 error[E0080]: constant evaluation error
   --> $DIR/const-len-underflow-separate-spans.rs:17:20
@@ -18,6 +18,6 @@ error[E0080]: constant evaluation error
 LL |     let a: [i8; LEN] = unimplemented!();
    |                 ^^^ referenced constant has errors
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/edition-keywords-2015-2015-expansion.rs b/src/test/ui/edition-keywords-2015-2015-expansion.rs
new file mode 100644
index 00000000000..b8a1994a105
--- /dev/null
+++ b/src/test/ui/edition-keywords-2015-2015-expansion.rs
@@ -0,0 +1,27 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+// aux-build:edition-kw-macro-2015.rs
+// compile-pass
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/ui/edition-keywords-2015-2015-parsing.rs b/src/test/ui/edition-keywords-2015-2015-parsing.rs
new file mode 100644
index 00000000000..1fb91ca006c
--- /dev/null
+++ b/src/test/ui/edition-keywords-2015-2015-parsing.rs
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); // OK
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2015-2015-parsing.stderr b/src/test/ui/edition-keywords-2015-2015-parsing.stderr
new file mode 100644
index 00000000000..5b6fd3e1c9c
--- /dev/null
+++ b/src/test/ui/edition-keywords-2015-2015-parsing.stderr
@@ -0,0 +1,14 @@
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2015-2015-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2015-2015-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/edition-keywords-2015-2018-expansion.rs b/src/test/ui/edition-keywords-2015-2018-expansion.rs
new file mode 100644
index 00000000000..bc14c104c49
--- /dev/null
+++ b/src/test/ui/edition-keywords-2015-2018-expansion.rs
@@ -0,0 +1,24 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+mod one_async {
+    produces_async! {} // ERROR expected identifier, found reserved keyword
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
diff --git a/src/test/ui/edition-keywords-2015-2018-expansion.stderr b/src/test/ui/edition-keywords-2015-2018-expansion.stderr
new file mode 100644
index 00000000000..13c4ee82537
--- /dev/null
+++ b/src/test/ui/edition-keywords-2015-2018-expansion.stderr
@@ -0,0 +1,10 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2015-2018-expansion.rs:20:5
+   |
+LL |     produces_async! {} // ERROR expected identifier, found reserved keyword
+   |     ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/edition-keywords-2015-2018-parsing.rs b/src/test/ui/edition-keywords-2015-2018-parsing.rs
new file mode 100644
index 00000000000..0b680eb16c7
--- /dev/null
+++ b/src/test/ui/edition-keywords-2015-2018-parsing.rs
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2015
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); // OK
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2015-2018-parsing.stderr b/src/test/ui/edition-keywords-2015-2018-parsing.stderr
new file mode 100644
index 00000000000..60cfbce3ff0
--- /dev/null
+++ b/src/test/ui/edition-keywords-2015-2018-parsing.stderr
@@ -0,0 +1,14 @@
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2015-2018-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2015-2018-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/edition-keywords-2018-2015-expansion.rs b/src/test/ui/edition-keywords-2018-2015-expansion.rs
new file mode 100644
index 00000000000..6f85f427eb0
--- /dev/null
+++ b/src/test/ui/edition-keywords-2018-2015-expansion.rs
@@ -0,0 +1,27 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+// aux-build:edition-kw-macro-2015.rs
+// compile-pass
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/ui/edition-keywords-2018-2015-parsing.rs b/src/test/ui/edition-keywords-2018-2015-parsing.rs
new file mode 100644
index 00000000000..29c5ea41f1f
--- /dev/null
+++ b/src/test/ui/edition-keywords-2018-2015-parsing.rs
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2018-2015-parsing.stderr b/src/test/ui/edition-keywords-2018-2015-parsing.stderr
new file mode 100644
index 00000000000..0b3ca57bfab
--- /dev/null
+++ b/src/test/ui/edition-keywords-2018-2015-parsing.stderr
@@ -0,0 +1,32 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:20:13
+   |
+LL |     let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:30:13
+   |
+LL |     module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: expected expression, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:28:22
+   |
+LL |     if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+   |                      ^^^^^ expected expression
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/edition-keywords-2018-2018-expansion.rs b/src/test/ui/edition-keywords-2018-2018-expansion.rs
new file mode 100644
index 00000000000..ef7f63e225c
--- /dev/null
+++ b/src/test/ui/edition-keywords-2018-2018-expansion.rs
@@ -0,0 +1,24 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+mod one_async {
+    produces_async! {} // ERROR expected identifier, found reserved keyword `async`
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
diff --git a/src/test/ui/edition-keywords-2018-2018-expansion.stderr b/src/test/ui/edition-keywords-2018-2018-expansion.stderr
new file mode 100644
index 00000000000..cd51030fd28
--- /dev/null
+++ b/src/test/ui/edition-keywords-2018-2018-expansion.stderr
@@ -0,0 +1,10 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-expansion.rs:20:5
+   |
+LL |     produces_async! {} // ERROR expected identifier, found reserved keyword `async`
+   |     ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/edition-keywords-2018-2018-parsing.rs b/src/test/ui/edition-keywords-2018-2018-parsing.rs
new file mode 100644
index 00000000000..a94808eb224
--- /dev/null
+++ b/src/test/ui/edition-keywords-2018-2018-parsing.rs
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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: --edition=2018
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2018-2018-parsing.stderr b/src/test/ui/edition-keywords-2018-2018-parsing.stderr
new file mode 100644
index 00000000000..1b18d8a39be
--- /dev/null
+++ b/src/test/ui/edition-keywords-2018-2018-parsing.stderr
@@ -0,0 +1,32 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:20:13
+   |
+LL |     let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:30:13
+   |
+LL |     module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: expected expression, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:28:22
+   |
+LL |     if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+   |                      ^^^^^ expected expression
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/error-codes/E0080.stderr b/src/test/ui/error-codes/E0080.stderr
index 5e401bd6c79..25ec5c45831 100644
--- a/src/test/ui/error-codes/E0080.stderr
+++ b/src/test/ui/error-codes/E0080.stderr
@@ -12,15 +12,15 @@ error[E0080]: constant evaluation error
 LL |     X = (1 << 500), //~ ERROR E0080
    |         ^^^^^^^^^^ attempt to shift left with overflow
 
-warning: attempt to divide by zero
+error: attempt to divide by zero
   --> $DIR/E0080.rs:14:9
    |
 LL |     Y = (1 / 0) //~ ERROR E0080
    |         ^^^^^^^
    |
-   = note: #[warn(const_err)] on by default
+   = note: #[deny(const_err)] on by default
 
-warning: constant evaluation error
+error: constant evaluation error
   --> $DIR/E0080.rs:14:9
    |
 LL |     Y = (1 / 0) //~ ERROR E0080
@@ -32,6 +32,6 @@ error[E0080]: constant evaluation error
 LL |     Y = (1 / 0) //~ ERROR E0080
    |         ^^^^^^^ attempt to divide by zero
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/run-pass/align-offset-sign.rs b/src/test/ui/error-codes/E0646.rs
index aaa0419d061..5fc711d9408 100644
--- a/src/test/run-pass/align-offset-sign.rs
+++ b/src/test/ui/error-codes/E0646.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,9 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(align_offset)]
-
-fn main() {
-    let x = 1 as *const u8;
-    assert_eq!(x.align_offset(8), 7);
-}
+fn main() where (): Copy {} //~ ERROR [E0646]
diff --git a/src/test/ui/error-codes/E0646.stderr b/src/test/ui/error-codes/E0646.stderr
new file mode 100644
index 00000000000..96da22a643c
--- /dev/null
+++ b/src/test/ui/error-codes/E0646.stderr
@@ -0,0 +1,9 @@
+error[E0646]: main function is not allowed to have a where clause
+  --> $DIR/E0646.rs:11:1
+   |
+LL | fn main() where (): Copy {} //~ ERROR [E0646]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0646`.
diff --git a/src/test/run-make-fulldeps/issue-36710/foo.cpp b/src/test/ui/error-codes/E0647.rs
index fbd0ead7a50..0a0ffefdf95 100644
--- a/src/test/run-make-fulldeps/issue-36710/foo.cpp
+++ b/src/test/ui/error-codes/E0647.rs
@@ -8,18 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#include <stdint.h>
+#![no_std]
+#![feature(start)]
 
-struct A {
-    A() { v = 1234; }
-    ~A() { v = 1; }
-    uint32_t v;
-};
+extern crate std;
 
-A a;
-
-extern "C" {
-    uint32_t get() {
-        return a.v;
-    }
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize where (): Copy { //~ ERROR [E0647]
+    0
 }
diff --git a/src/test/ui/error-codes/E0647.stderr b/src/test/ui/error-codes/E0647.stderr
new file mode 100644
index 00000000000..f02407dcea6
--- /dev/null
+++ b/src/test/ui/error-codes/E0647.stderr
@@ -0,0 +1,11 @@
+error[E0647]: start function is not allowed to have a where clause
+  --> $DIR/E0647.rs:17:1
+   |
+LL | / fn start(_: isize, _: *const *const u8) -> isize where (): Copy { //~ ERROR [E0647]
+LL | |     0
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0647`.
diff --git a/src/test/ui/fmt/format-string-error.rs b/src/test/ui/fmt/format-string-error.rs
index ec715b3f0ba..5b13686240e 100644
--- a/src/test/ui/fmt/format-string-error.rs
+++ b/src/test/ui/fmt/format-string-error.rs
@@ -12,5 +12,14 @@ fn main() {
     println!("{");
     println!("{{}}");
     println!("}");
+    let _ = format!("{_foo}", _foo = 6usize);
+    //~^ ERROR invalid format string: invalid argument name `_foo`
+    let _ = format!("{_}", _ = 6usize);
+    //~^ ERROR invalid format string: invalid argument name `_`
+    let _ = format!("{");
+    //~^ ERROR invalid format string: expected `'}'` but string was terminated
+    let _ = format!("}");
+    //~^ ERROR invalid format string: unmatched `}` found
+    let _ = format!("{\\}");
+    //~^ ERROR invalid format string: expected `'}'`, found `'\\'`
 }
-
diff --git a/src/test/ui/fmt/format-string-error.stderr b/src/test/ui/fmt/format-string-error.stderr
index a7a66722e52..ff766ddc8fa 100644
--- a/src/test/ui/fmt/format-string-error.stderr
+++ b/src/test/ui/fmt/format-string-error.stderr
@@ -2,7 +2,7 @@ error: invalid format string: expected `'}'` but string was terminated
   --> $DIR/format-string-error.rs:12:5
    |
 LL |     println!("{");
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ expected `'}'` in format string
    |
    = note: if you intended to print `{`, you can escape it using `{{`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
@@ -11,10 +11,48 @@ error: invalid format string: unmatched `}` found
   --> $DIR/format-string-error.rs:14:5
    |
 LL |     println!("}");
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ unmatched `}` in format string
    |
    = note: if you intended to print `}`, you can escape it using `}}`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error: invalid format string: invalid argument name `_foo`
+  --> $DIR/format-string-error.rs:15:23
+   |
+LL |     let _ = format!("{_foo}", _foo = 6usize);
+   |                       ^^^^ invalid argument name in format string
+   |
+   = note: argument names cannot start with an underscore
+
+error: invalid format string: invalid argument name `_`
+  --> $DIR/format-string-error.rs:17:23
+   |
+LL |     let _ = format!("{_}", _ = 6usize);
+   |                       ^ invalid argument name in format string
+   |
+   = note: argument names cannot start with an underscore
+
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/format-string-error.rs:19:23
+   |
+LL |     let _ = format!("{");
+   |                       ^ expected `'}'` in format string
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error: invalid format string: unmatched `}` found
+  --> $DIR/format-string-error.rs:21:22
+   |
+LL |     let _ = format!("}");
+   |                      ^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+
+error: invalid format string: expected `'}'`, found `'/'`
+  --> $DIR/format-string-error.rs:23:23
+   |
+LL |     let _ = format!("{/}");
+   |                       ^ expected `}` in format string
+
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/imports/rfc-1560-warning-cycle.rs b/src/test/ui/imports/rfc-1560-warning-cycle.rs
index f94fc3633e3..5b62c5fcd3f 100644
--- a/src/test/ui/imports/rfc-1560-warning-cycle.rs
+++ b/src/test/ui/imports/rfc-1560-warning-cycle.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(unused)]
-
 pub struct Foo;
 
 mod bar {
@@ -18,9 +16,7 @@ mod bar {
     mod baz {
         use *;
         use bar::*;
-        fn f(_: Foo) {}
-        //~^ ERROR `Foo` is ambiguous
-        //~| WARN hard error in a future release
+        fn f(_: Foo) {} //~ ERROR `Foo` is ambiguous
     }
 }
 
diff --git a/src/test/ui/imports/rfc-1560-warning-cycle.stderr b/src/test/ui/imports/rfc-1560-warning-cycle.stderr
index 452fcc4c1a9..5a01680fc19 100644
--- a/src/test/ui/imports/rfc-1560-warning-cycle.stderr
+++ b/src/test/ui/imports/rfc-1560-warning-cycle.stderr
@@ -1,16 +1,21 @@
-error: `Foo` is ambiguous
-  --> $DIR/rfc-1560-warning-cycle.rs:21:17
+error[E0659]: `Foo` is ambiguous
+  --> $DIR/rfc-1560-warning-cycle.rs:19:17
    |
-LL |         use *;
-   |             - `Foo` could refer to the name imported here
-LL |         use bar::*;
-   |             ------ `Foo` could also refer to the name imported here
-LL |         fn f(_: Foo) {}
+LL |         fn f(_: Foo) {} //~ ERROR `Foo` is ambiguous
    |                 ^^^
    |
-   = note: #[deny(legacy_imports)] on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #38260 <https://github.com/rust-lang/rust/issues/38260>
+note: `Foo` could refer to the name imported here
+  --> $DIR/rfc-1560-warning-cycle.rs:17:13
+   |
+LL |         use *;
+   |             ^
+note: `Foo` could also refer to the name imported here
+  --> $DIR/rfc-1560-warning-cycle.rs:18:13
+   |
+LL |         use bar::*;
+   |             ^^^^^^
+   = note: consider adding an explicit import of `Foo` to disambiguate
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/issue-50714-1.rs b/src/test/ui/issue-50714-1.rs
new file mode 100644
index 00000000000..f0e496a88fb
--- /dev/null
+++ b/src/test/ui/issue-50714-1.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue 50714, make sure that this isn't a linker error.
+
+#![no_std]
+#![feature(start)]
+
+extern crate std;
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { //~ ERROR [E0647]
+    0
+}
+
diff --git a/src/test/ui/issue-50714-1.stderr b/src/test/ui/issue-50714-1.stderr
new file mode 100644
index 00000000000..b93183d2f24
--- /dev/null
+++ b/src/test/ui/issue-50714-1.stderr
@@ -0,0 +1,11 @@
+error[E0647]: start function is not allowed to have a where clause
+  --> $DIR/issue-50714-1.rs:19:1
+   |
+LL | / fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { //~ ERROR [E0647]
+LL | |     0
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0647`.
diff --git a/src/test/ui/issue-50714.rs b/src/test/ui/issue-50714.rs
new file mode 100644
index 00000000000..08d975326df
--- /dev/null
+++ b/src/test/ui/issue-50714.rs
@@ -0,0 +1,14 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue 50714, make sure that this isn't a linker error.
+
+fn main() where fn(&()): Eq {} //~ ERROR [E0646]
+
diff --git a/src/test/ui/issue-50714.stderr b/src/test/ui/issue-50714.stderr
new file mode 100644
index 00000000000..8cdcfe4abe2
--- /dev/null
+++ b/src/test/ui/issue-50714.stderr
@@ -0,0 +1,9 @@
+error[E0646]: main function is not allowed to have a where clause
+  --> $DIR/issue-50714.rs:13:1
+   |
+LL | fn main() where fn(&()): Eq {} //~ ERROR [E0646]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0646`.
diff --git a/src/test/ui/issue-50761.rs b/src/test/ui/issue-50761.rs
new file mode 100644
index 00000000000..b8a7a089c23
--- /dev/null
+++ b/src/test/ui/issue-50761.rs
@@ -0,0 +1,33 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Confirm that we don't accidently divide or mod by zero in llvm_type
+
+// compile-pass
+
+mod a {
+    pub trait A {}
+}
+
+mod b {
+    pub struct Builder {}
+
+    pub fn new() -> Builder {
+        Builder {}
+    }
+
+    impl Builder {
+        pub fn with_a(&mut self, _a: fn() -> ::a::A) {}
+    }
+}
+
+pub use self::b::new;
+
+fn main() {}
diff --git a/src/test/run-make-fulldeps/issue-36710/foo.rs b/src/test/ui/issue-50802.rs
index 6e50566ddfd..6342d0757ee 100644
--- a/src/test/run-make-fulldeps/issue-36710/foo.rs
+++ b/src/test/ui/issue-50802.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Tests that linking to C++ code with global destructors works.
-
-extern { fn get() -> u32; }
+#[allow(unreachable_code)]
 
 fn main() {
-    let i = unsafe { get() };
-    assert_eq!(i, 1234);
+    loop {
+        break while continue { //~ ERROR E0590
+        }
+    }
 }
diff --git a/src/test/ui/issue-50802.stderr b/src/test/ui/issue-50802.stderr
new file mode 100644
index 00000000000..9da2648b376
--- /dev/null
+++ b/src/test/ui/issue-50802.stderr
@@ -0,0 +1,9 @@
+error[E0590]: `break` or `continue` with no label in the condition of a `while` loop
+  --> $DIR/issue-50802.rs:15:21
+   |
+LL |         break while continue { //~ ERROR E0590
+   |                     ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0590`.
diff --git a/src/test/ui/label_break_value_continue.rs b/src/test/ui/label_break_value_continue.rs
index 52e24b759d1..4a505dff3d4 100644
--- a/src/test/ui/label_break_value_continue.rs
+++ b/src/test/ui/label_break_value_continue.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(label_break_value)]
+#![allow(unused_labels)]
 
 // Simple continue pointing to an unlabeled break should yield in an error
 fn continue_simple() {
diff --git a/src/test/ui/label_break_value_continue.stderr b/src/test/ui/label_break_value_continue.stderr
index 24c2d1a22d0..12a21a8a594 100644
--- a/src/test/ui/label_break_value_continue.stderr
+++ b/src/test/ui/label_break_value_continue.stderr
@@ -1,17 +1,17 @@
 error[E0695]: unlabeled `continue` inside of a labeled block
-  --> $DIR/label_break_value_continue.rs:16:9
+  --> $DIR/label_break_value_continue.rs:17:9
    |
 LL |         continue; //~ ERROR unlabeled `continue` inside of a labeled block
    |         ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
 
 error[E0696]: `continue` pointing to a labeled block
-  --> $DIR/label_break_value_continue.rs:23:9
+  --> $DIR/label_break_value_continue.rs:24:9
    |
 LL |         continue 'b; //~ ERROR `continue` pointing to a labeled block
    |         ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
    |
 note: labeled block the continue points to
-  --> $DIR/label_break_value_continue.rs:22:5
+  --> $DIR/label_break_value_continue.rs:23:5
    |
 LL | /     'b: {
 LL | |         continue 'b; //~ ERROR `continue` pointing to a labeled block
@@ -19,7 +19,7 @@ LL | |     }
    | |_____^
 
 error[E0695]: unlabeled `continue` inside of a labeled block
-  --> $DIR/label_break_value_continue.rs:31:13
+  --> $DIR/label_break_value_continue.rs:32:13
    |
 LL |             continue; //~ ERROR unlabeled `continue` inside of a labeled block
    |             ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
diff --git a/src/test/ui/label_break_value_unlabeled_break.rs b/src/test/ui/label_break_value_unlabeled_break.rs
index 38918da291c..454ebd4c6cf 100644
--- a/src/test/ui/label_break_value_unlabeled_break.rs
+++ b/src/test/ui/label_break_value_unlabeled_break.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(label_break_value)]
+#![allow(unused_labels)]
 
 // Simple unlabeled break should yield in an error
 fn unlabeled_break_simple() {
diff --git a/src/test/ui/label_break_value_unlabeled_break.stderr b/src/test/ui/label_break_value_unlabeled_break.stderr
index 8a25975a7bd..62c4a12231b 100644
--- a/src/test/ui/label_break_value_unlabeled_break.stderr
+++ b/src/test/ui/label_break_value_unlabeled_break.stderr
@@ -1,11 +1,11 @@
 error[E0695]: unlabeled `break` inside of a labeled block
-  --> $DIR/label_break_value_unlabeled_break.rs:16:9
+  --> $DIR/label_break_value_unlabeled_break.rs:17:9
    |
 LL |         break; //~ ERROR unlabeled `break` inside of a labeled block
    |         ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label
 
 error[E0695]: unlabeled `break` inside of a labeled block
-  --> $DIR/label_break_value_unlabeled_break.rs:24:13
+  --> $DIR/label_break_value_unlabeled_break.rs:25:13
    |
 LL |             break; //~ ERROR unlabeled `break` inside of a labeled block
    |             ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label
diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs
index 100fb6d3533..bac3f00ffc7 100644
--- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs
+++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs
@@ -20,6 +20,11 @@ struct SoulHistory {
     endless_and_singing: bool
 }
 
+struct LovelyAmbition {
+    lips: usize,
+    fire: usize
+}
+
 #[derive(Clone, Copy)]
 enum Large {
     Suit { case: () }
@@ -45,6 +50,10 @@ fn main() {
         hours_are_suns = false;
     }
 
+    let the_spirit = LovelyAmbition { lips: 1, fire: 2 };
+    let LovelyAmbition { lips, fire } = the_spirit;
+    println!("{}", lips);
+
     let bag = Large::Suit {
         case: ()
     };
diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr
index 992be2c0a28..a8b0e3e4250 100644
--- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr
+++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr
@@ -1,5 +1,5 @@
 warning: unused variable: `i_think_continually`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:31:9
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:36:9
    |
 LL |     let i_think_continually = 2;
    |         ^^^^^^^^^^^^^^^^^^^ help: consider using `_i_think_continually` instead
@@ -12,31 +12,31 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
    = note: #[warn(unused_variables)] implied by #[warn(unused)]
 
 warning: unused variable: `mut_unused_var`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:13
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:43:13
    |
 LL |     let mut mut_unused_var = 1;
    |             ^^^^^^^^^^^^^^ help: consider using `_mut_unused_var` instead
 
 warning: unused variable: `var`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:14
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:45:14
    |
 LL |     let (mut var, unused_var) = (1, 2);
    |              ^^^ help: consider using `_var` instead
 
 warning: unused variable: `unused_var`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:19
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:45:19
    |
 LL |     let (mut var, unused_var) = (1, 2);
    |                   ^^^^^^^^^^ help: consider using `_unused_var` instead
 
 warning: unused variable: `corridors_of_light`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:42:26
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:47:26
    |
 LL |     if let SoulHistory { corridors_of_light,
    |                          ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _`
 
 warning: variable `hours_are_suns` is assigned to, but never used
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:43:30
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:48:30
    |
 LL |                          mut hours_are_suns,
    |                              ^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |                          mut hours_are_suns,
    = note: consider using `_hours_are_suns` instead
 
 warning: value assigned to `hours_are_suns` is never read
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:45:9
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:50:9
    |
 LL |         hours_are_suns = false;
    |         ^^^^^^^^^^^^^^
@@ -56,44 +56,50 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
    |         ^^^^^^
    = note: #[warn(unused_assignments)] implied by #[warn(unused)]
 
+warning: unused variable: `fire`
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:54:32
+   |
+LL |     let LovelyAmbition { lips, fire } = the_spirit;
+   |                                ^^^^ help: try ignoring the field: `fire: _`
+
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:54:23
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:63:23
    |
 LL |         Large::Suit { case } => {}
    |                       ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:59:24
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:68:24
    |
 LL |         &Large::Suit { case } => {}
    |                        ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:64:27
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:73:27
    |
 LL |         box Large::Suit { case } => {}
    |                           ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:69:24
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:78:24
    |
 LL |         (Large::Suit { case },) => {}
    |                        ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:74:24
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:83:24
    |
 LL |         [Large::Suit { case }] => {}
    |                        ^^^^ help: try ignoring the field: `case: _`
 
 warning: unused variable: `case`
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:79:29
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:88:29
    |
 LL |         Tuple(Large::Suit { case }, ()) => {}
    |                             ^^^^ help: try ignoring the field: `case: _`
 
 warning: variable does not need to be mutable
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:9
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:43:9
    |
 LL |     let mut mut_unused_var = 1;
    |         ----^^^^^^^^^^^^^^
@@ -108,7 +114,7 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
    = note: #[warn(unused_mut)] implied by #[warn(unused)]
 
 warning: variable does not need to be mutable
-  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:10
+  --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:45:10
    |
 LL |     let (mut var, unused_var) = (1, 2);
    |          ----^^^
diff --git a/src/test/ui/lint/unused_labels.rs b/src/test/ui/lint/unused_labels.rs
new file mode 100644
index 00000000000..23add604da6
--- /dev/null
+++ b/src/test/ui/lint/unused_labels.rs
@@ -0,0 +1,96 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// The output should warn when a loop label is not used. However, it
+// should also deal with the edge cases where a label is shadowed,
+// within nested loops
+
+// compile-pass
+
+#![feature(label_break_value)]
+#![warn(unused_labels)]
+
+fn main() {
+    'unused_while_label: while 0 == 0 {
+        //~^ WARN unused label
+    }
+
+    let opt = Some(0);
+    'unused_while_let_label: while let Some(_) = opt {
+        //~^ WARN unused label
+    }
+
+    'unused_for_label: for _ in 0..10 {
+        //~^ WARN unused label
+    }
+
+    'used_loop_label: loop {
+        break 'used_loop_label;
+    }
+
+    'used_loop_label_outer_1: for _ in 0..10 {
+        'used_loop_label_inner_1: for _ in 0..10 {
+            break 'used_loop_label_inner_1;
+        }
+        break 'used_loop_label_outer_1;
+    }
+
+    'used_loop_label_outer_2: for _ in 0..10 {
+        'unused_loop_label_inner_2: for _ in 0..10 {
+            //~^ WARN unused label
+            break 'used_loop_label_outer_2;
+        }
+    }
+
+    'unused_loop_label_outer_3: for _ in 0..10 {
+        //~^ WARN unused label
+        'used_loop_label_inner_3: for _ in 0..10 {
+            break 'used_loop_label_inner_3;
+        }
+    }
+
+    // You should be able to break the same label many times
+    'many_used: loop {
+        if true {
+            break 'many_used;
+        } else {
+            break 'many_used;
+        }
+    }
+
+    // Test breaking many times with the same inner label doesn't break the
+    // warning on the outer label
+    'many_used_shadowed: for _ in 0..10 {
+        //~^ WARN unused label
+        'many_used_shadowed: for _ in 0..10 {
+            //~^ WARN label name `'many_used_shadowed` shadows a label name that is already in scope
+            if 1 % 2 == 0 {
+                break 'many_used_shadowed;
+            } else {
+                break 'many_used_shadowed;
+            }
+        }
+    }
+
+    'unused_loop_label: loop {
+        //~^ WARN unused label
+        break;
+    }
+
+    // Make sure unused block labels give warnings...
+    'unused_block_label: {
+        //~^ WARN unused label
+    }
+
+    // ...and that used ones don't:
+    'used_block_label: {
+        break 'used_block_label;
+    }
+}
diff --git a/src/test/ui/lint/unused_labels.stderr b/src/test/ui/lint/unused_labels.stderr
new file mode 100644
index 00000000000..825f5e281f0
--- /dev/null
+++ b/src/test/ui/lint/unused_labels.stderr
@@ -0,0 +1,63 @@
+warning: unused label
+  --> $DIR/unused_labels.rs:21:5
+   |
+LL |     'unused_while_label: while 0 == 0 {
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/unused_labels.rs:18:9
+   |
+LL | #![warn(unused_labels)]
+   |         ^^^^^^^^^^^^^
+
+warning: unused label
+  --> $DIR/unused_labels.rs:26:5
+   |
+LL |     'unused_while_let_label: while let Some(_) = opt {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+  --> $DIR/unused_labels.rs:30:5
+   |
+LL |     'unused_for_label: for _ in 0..10 {
+   |     ^^^^^^^^^^^^^^^^^
+
+warning: unused label
+  --> $DIR/unused_labels.rs:46:9
+   |
+LL |         'unused_loop_label_inner_2: for _ in 0..10 {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+  --> $DIR/unused_labels.rs:52:5
+   |
+LL |     'unused_loop_label_outer_3: for _ in 0..10 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+  --> $DIR/unused_labels.rs:70:5
+   |
+LL |     'many_used_shadowed: for _ in 0..10 {
+   |     ^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+  --> $DIR/unused_labels.rs:82:5
+   |
+LL |     'unused_loop_label: loop {
+   |     ^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+  --> $DIR/unused_labels.rs:88:5
+   |
+LL |     'unused_block_label: {
+   |     ^^^^^^^^^^^^^^^^^^^
+
+warning: label name `'many_used_shadowed` shadows a label name that is already in scope
+  --> $DIR/unused_labels.rs:72:9
+   |
+LL |     'many_used_shadowed: for _ in 0..10 {
+   |     ------------------- first declared here
+LL |         //~^ WARN unused label
+LL |         'many_used_shadowed: for _ in 0..10 {
+   |         ^^^^^^^^^^^^^^^^^^^ lifetime 'many_used_shadowed already in scope
+
diff --git a/src/test/ui/loops-reject-duplicate-labels-2.rs b/src/test/ui/loops-reject-duplicate-labels-2.rs
index 598c7370b89..b273e7a0c7c 100644
--- a/src/test/ui/loops-reject-duplicate-labels-2.rs
+++ b/src/test/ui/loops-reject-duplicate-labels-2.rs
@@ -18,6 +18,7 @@
 // discussed here:
 // https://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833
 
+#[allow(unused_labels)]
 pub fn foo() {
     { 'fl: for _ in 0..10 { break; } }
     { 'fl: loop { break; } }             //~ WARN label name `'fl` shadows a label name that is already in scope
diff --git a/src/test/ui/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops-reject-duplicate-labels-2.stderr
index 830270a99d1..41b4a850f1b 100644
--- a/src/test/ui/loops-reject-duplicate-labels-2.stderr
+++ b/src/test/ui/loops-reject-duplicate-labels-2.stderr
@@ -1,5 +1,5 @@
 warning: label name `'fl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:23:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:24:7
    |
 LL |     { 'fl: for _ in 0..10 { break; } }
    |       --- first declared here
@@ -7,7 +7,7 @@ LL |     { 'fl: loop { break; } }             //~ WARN label name `'fl` shadows
    |       ^^^ lifetime 'fl already in scope
 
 warning: label name `'lf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:25:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:26:7
    |
 LL |     { 'lf: loop { break; } }
    |       --- first declared here
@@ -15,7 +15,7 @@ LL |     { 'lf: for _ in 0..10 { break; } }   //~ WARN label name `'lf` shadows
    |       ^^^ lifetime 'lf already in scope
 
 warning: label name `'wl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:27:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:28:7
    |
 LL |     { 'wl: while 2 > 1 { break; } }
    |       --- first declared here
@@ -23,7 +23,7 @@ LL |     { 'wl: loop { break; } }             //~ WARN label name `'wl` shadows
    |       ^^^ lifetime 'wl already in scope
 
 warning: label name `'lw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:29:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:30:7
    |
 LL |     { 'lw: loop { break; } }
    |       --- first declared here
@@ -31,7 +31,7 @@ LL |     { 'lw: while 2 > 1 { break; } }      //~ WARN label name `'lw` shadows
    |       ^^^ lifetime 'lw already in scope
 
 warning: label name `'fw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:31:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:32:7
    |
 LL |     { 'fw: for _ in 0..10 { break; } }
    |       --- first declared here
@@ -39,7 +39,7 @@ LL |     { 'fw: while 2 > 1 { break; } }      //~ WARN label name `'fw` shadows
    |       ^^^ lifetime 'fw already in scope
 
 warning: label name `'wf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:33:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:34:7
    |
 LL |     { 'wf: while 2 > 1 { break; } }
    |       --- first declared here
@@ -47,7 +47,7 @@ LL |     { 'wf: for _ in 0..10 { break; } }   //~ WARN label name `'wf` shadows
    |       ^^^ lifetime 'wf already in scope
 
 warning: label name `'tl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:35:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:36:7
    |
 LL |     { 'tl: while let Some(_) = None::<i32> { break; } }
    |       --- first declared here
@@ -55,7 +55,7 @@ LL |     { 'tl: loop { break; } }             //~ WARN label name `'tl` shadows
    |       ^^^ lifetime 'tl already in scope
 
 warning: label name `'lt` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels-2.rs:37:7
+  --> $DIR/loops-reject-duplicate-labels-2.rs:38:7
    |
 LL |     { 'lt: loop { break; } }
    |       --- first declared here
@@ -63,7 +63,7 @@ LL |     { 'lt: while let Some(_) = None::<i32> { break; } }
    |       ^^^ lifetime 'lt already in scope
 
 error: compilation successful
-  --> $DIR/loops-reject-duplicate-labels-2.rs:42:1
+  --> $DIR/loops-reject-duplicate-labels-2.rs:43:1
    |
 LL | / pub fn main() { //~ ERROR compilation successful
 LL | |     foo();
diff --git a/src/test/ui/loops-reject-duplicate-labels.rs b/src/test/ui/loops-reject-duplicate-labels.rs
index d768b002ab1..ad24f69871c 100644
--- a/src/test/ui/loops-reject-duplicate-labels.rs
+++ b/src/test/ui/loops-reject-duplicate-labels.rs
@@ -15,6 +15,7 @@
 // Issue #21633: reject duplicate loop labels in function bodies.
 // This is testing the exact cases that are in the issue description.
 
+#[allow(unused_labels)]
 fn foo() {
     'fl: for _ in 0..10 { break; }
     'fl: loop { break; }           //~ WARN label name `'fl` shadows a label name that is already in scope
diff --git a/src/test/ui/loops-reject-duplicate-labels.stderr b/src/test/ui/loops-reject-duplicate-labels.stderr
index a71f98b812a..d0cb81544f8 100644
--- a/src/test/ui/loops-reject-duplicate-labels.stderr
+++ b/src/test/ui/loops-reject-duplicate-labels.stderr
@@ -1,5 +1,5 @@
 warning: label name `'fl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:20:5
+  --> $DIR/loops-reject-duplicate-labels.rs:21:5
    |
 LL |     'fl: for _ in 0..10 { break; }
    |     --- first declared here
@@ -7,7 +7,7 @@ LL |     'fl: loop { break; }           //~ WARN label name `'fl` shadows a labe
    |     ^^^ lifetime 'fl already in scope
 
 warning: label name `'lf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:23:5
+  --> $DIR/loops-reject-duplicate-labels.rs:24:5
    |
 LL |     'lf: loop { break; }
    |     --- first declared here
@@ -15,7 +15,7 @@ LL |     'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a labe
    |     ^^^ lifetime 'lf already in scope
 
 warning: label name `'wl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:25:5
+  --> $DIR/loops-reject-duplicate-labels.rs:26:5
    |
 LL |     'wl: while 2 > 1 { break; }
    |     --- first declared here
@@ -23,7 +23,7 @@ LL |     'wl: loop { break; }           //~ WARN label name `'wl` shadows a labe
    |     ^^^ lifetime 'wl already in scope
 
 warning: label name `'lw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:27:5
+  --> $DIR/loops-reject-duplicate-labels.rs:28:5
    |
 LL |     'lw: loop { break; }
    |     --- first declared here
@@ -31,7 +31,7 @@ LL |     'lw: while 2 > 1 { break; }    //~ WARN label name `'lw` shadows a labe
    |     ^^^ lifetime 'lw already in scope
 
 warning: label name `'fw` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:29:5
+  --> $DIR/loops-reject-duplicate-labels.rs:30:5
    |
 LL |     'fw: for _ in 0..10 { break; }
    |     --- first declared here
@@ -39,7 +39,7 @@ LL |     'fw: while 2 > 1 { break; }    //~ WARN label name `'fw` shadows a labe
    |     ^^^ lifetime 'fw already in scope
 
 warning: label name `'wf` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:31:5
+  --> $DIR/loops-reject-duplicate-labels.rs:32:5
    |
 LL |     'wf: while 2 > 1 { break; }
    |     --- first declared here
@@ -47,7 +47,7 @@ LL |     'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a labe
    |     ^^^ lifetime 'wf already in scope
 
 warning: label name `'tl` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:33:5
+  --> $DIR/loops-reject-duplicate-labels.rs:34:5
    |
 LL |     'tl: while let Some(_) = None::<i32> { break; }
    |     --- first declared here
@@ -55,7 +55,7 @@ LL |     'tl: loop { break; }           //~ WARN label name `'tl` shadows a labe
    |     ^^^ lifetime 'tl already in scope
 
 warning: label name `'lt` shadows a label name that is already in scope
-  --> $DIR/loops-reject-duplicate-labels.rs:35:5
+  --> $DIR/loops-reject-duplicate-labels.rs:36:5
    |
 LL |     'lt: loop { break; }
    |     --- first declared here
@@ -63,7 +63,7 @@ LL |     'lt: while let Some(_) = None::<i32> { break; }
    |     ^^^ lifetime 'lt already in scope
 
 error: compilation successful
-  --> $DIR/loops-reject-duplicate-labels.rs:49:1
+  --> $DIR/loops-reject-duplicate-labels.rs:50:1
    |
 LL | / pub fn main() { //~ ERROR compilation successful
 LL | |     let s = S;
diff --git a/src/test/ui/nll/get_default.nll.stderr b/src/test/ui/nll/get_default.nll.stderr
index c6f021f8c36..b955a51e38d 100644
--- a/src/test/ui/nll/get_default.nll.stderr
+++ b/src/test/ui/nll/get_default.nll.stderr
@@ -4,14 +4,14 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as imm
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, this would not error.
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -23,19 +23,40 @@ LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:50:17
+  --> $DIR/get_default.rs:51:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, just AST would error here
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:33:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, this would not error.
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
+  --> $DIR/get_default.rs:26:1
+   |
+LL | / fn ok(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -46,6 +67,27 @@ LL |                 map.set(String::new()); // Both AST and MIR error here
 LL |                 return v;
    |                        - borrow later used here
 
-error: aborting due to 4 previous errors
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:51:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, just AST would error here
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+  --> $DIR/get_default.rs:41:1
+   |
+LL | / fn err(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/nll/get_default.rs b/src/test/ui/nll/get_default.rs
index 728c84695ea..1a417b1e28c 100644
--- a/src/test/ui/nll/get_default.rs
+++ b/src/test/ui/nll/get_default.rs
@@ -30,8 +30,9 @@ fn ok(map: &mut Map) -> &String {
                 return v;
             }
             None => {
-                map.set(String::new()); // Just AST errors here
+                map.set(String::new()); // Ideally, this would not error.
                 //~^ ERROR borrowed as immutable (Ast)
+                //~| ERROR borrowed as immutable (Mir)
             }
         }
     }
@@ -47,8 +48,9 @@ fn err(map: &mut Map) -> &String {
                 return v;
             }
             None => {
-                map.set(String::new()); // Just AST errors here
+                map.set(String::new()); // Ideally, just AST would error here
                 //~^ ERROR borrowed as immutable (Ast)
+                //~| ERROR borrowed as immutable (Mir)
             }
         }
     }
diff --git a/src/test/ui/nll/get_default.stderr b/src/test/ui/nll/get_default.stderr
index 064fd38b872..dd69e18652c 100644
--- a/src/test/ui/nll/get_default.stderr
+++ b/src/test/ui/nll/get_default.stderr
@@ -4,14 +4,14 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as imm
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, this would not error.
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -23,19 +23,61 @@ LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:50:17
+  --> $DIR/get_default.rs:51:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, just AST would error here
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:33:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, this would not error.
+   |                 ^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
+  --> $DIR/get_default.rs:26:1
+   |
+LL | / fn ok(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:51:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, just AST would error here
+   |                 ^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+  --> $DIR/get_default.rs:41:1
+   |
+LL | / fn err(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -46,6 +88,6 @@ LL |                 map.set(String::new()); // Both AST and MIR error here
 LL |                 return v;
    |                        - borrow later used here
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/suggestions/suggest-labels.rs b/src/test/ui/suggestions/suggest-labels.rs
index 8c97301f40b..9fb519c57ed 100644
--- a/src/test/ui/suggestions/suggest-labels.rs
+++ b/src/test/ui/suggestions/suggest-labels.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[allow(unreachable_code)]
+#[allow(unreachable_code, unused_labels)]
 fn main() {
     'foo: loop {
         break 'fo; //~ ERROR use of undeclared label
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject c658fc8cbcd1f199edd445a49cb43139ebdc5f0
+Subproject ebe0b0eed596243a2839867363cb31d93f0b975
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 812e9c5f39d..b2ce5ce52f7 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -118,6 +118,9 @@ impl CompareMode {
 
 #[derive(Clone)]
 pub struct Config {
+    /// Whether to overwrite stderr/stdout files instead of complaining about changes in output
+    pub bless: bool,
+
     /// The library paths required for running the compiler
     pub compile_lib_path: PathBuf,
 
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 42a2cdfa55b..2bfc1ece095 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -168,6 +168,11 @@ pub fn parse_config(args: Vec<String>) -> Config {
         .optflag("", "verbose", "run tests verbosely, showing all output")
         .optflag(
             "",
+            "bless",
+            "overwrite stderr/stdout files instead of complaining about a mismatch",
+        )
+        .optflag(
+            "",
             "quiet",
             "print one character per test instead of one line",
         )
@@ -290,6 +295,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
     let src_base = opt_path(matches, "src-base");
     let run_ignored = matches.opt_present("ignored");
     Config {
+        bless: matches.opt_present("bless"),
         compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
         run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
         rustc_path: opt_path(matches, "rustc-path"),
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 780c8122734..140c90aaeac 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2502,7 +2502,7 @@ impl<'test> TestCx<'test> {
                 .env("IS_WINDOWS", "1")
                 .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
                 .env("CC", format!("'{}' {}", self.config.cc, cflags))
-                .env("CXX", format!("'{}'", &self.config.cxx));
+                .env("CXX", &self.config.cxx);
         } else {
             cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
                 .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
@@ -2596,15 +2596,13 @@ impl<'test> TestCx<'test> {
         }
 
         if errors > 0 {
-            println!("To update references, run this command from build directory:");
+            println!("To update references, rerun the tests and pass the `--bless` flag");
             let relative_path_to_file = self.testpaths
                 .relative_dir
                 .join(self.testpaths.file.file_name().unwrap());
             println!(
-                "{}/update-references.sh '{}' '{}'",
-                self.config.src_base.display(),
-                self.config.build_base.display(),
-                relative_path_to_file.display()
+                "To only update this specific test, also pass `--test-args {}`",
+                relative_path_to_file.display(),
             );
             self.fatal_proc_rec(
                 &format!("{} errors occurred comparing output.", errors),
@@ -2926,29 +2924,31 @@ impl<'test> TestCx<'test> {
             return 0;
         }
 
-        if expected.is_empty() {
-            println!("normalized {}:\n{}\n", kind, actual);
-        } else {
-            println!("diff of {}:\n", kind);
-            let diff_results = make_diff(expected, actual, 3);
-            for result in diff_results {
-                let mut line_number = result.line_number;
-                for line in result.lines {
-                    match line {
-                        DiffLine::Expected(e) => {
-                            println!("-\t{}", e);
-                            line_number += 1;
-                        }
-                        DiffLine::Context(c) => {
-                            println!("{}\t{}", line_number, c);
-                            line_number += 1;
-                        }
-                        DiffLine::Resulting(r) => {
-                            println!("+\t{}", r);
+        if !self.config.bless {
+            if expected.is_empty() {
+                println!("normalized {}:\n{}\n", kind, actual);
+            } else {
+                println!("diff of {}:\n", kind);
+                let diff_results = make_diff(expected, actual, 3);
+                for result in diff_results {
+                    let mut line_number = result.line_number;
+                    for line in result.lines {
+                        match line {
+                            DiffLine::Expected(e) => {
+                                println!("-\t{}", e);
+                                line_number += 1;
+                            }
+                            DiffLine::Context(c) => {
+                                println!("{}\t{}", line_number, c);
+                                line_number += 1;
+                            }
+                            DiffLine::Resulting(r) => {
+                                println!("+\t{}", r);
+                            }
                         }
                     }
+                    println!("");
                 }
-                println!("");
             }
         }
 
@@ -2958,19 +2958,47 @@ impl<'test> TestCx<'test> {
             .with_extra_extension(mode)
             .with_extra_extension(kind);
 
-        match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
-            Ok(()) => {}
-            Err(e) => self.fatal(&format!(
-                "failed to write {} to `{}`: {}",
+        let mut files = vec![output_file];
+        if self.config.bless {
+            files.push(expected_output_path(
+                self.testpaths,
+                self.revision,
+                &self.config.compare_mode,
                 kind,
-                output_file.display(),
-                e
-            )),
+            ));
+        }
+
+        for output_file in &files {
+            if actual.is_empty() {
+                if let Err(e) = ::std::fs::remove_file(output_file) {
+                    self.fatal(&format!(
+                        "failed to delete `{}`: {}",
+                        output_file.display(),
+                        e,
+                    ));
+                }
+            } else {
+                match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
+                    Ok(()) => {}
+                    Err(e) => self.fatal(&format!(
+                        "failed to write {} to `{}`: {}",
+                        kind,
+                        output_file.display(),
+                        e
+                    )),
+                }
+            }
         }
 
         println!("\nThe actual {0} differed from the expected {0}.", kind);
-        println!("Actual {} saved to {}", kind, output_file.display());
-        1
+        for output_file in files {
+            println!("Actual {} saved to {}", kind, output_file.display());
+        }
+        if self.config.bless {
+            0
+        } else {
+            1
+        }
     }
 
     fn create_stamp(&self) {
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 3e3df0485004bc1343bc8200b68c67ac7c479b2
+Subproject cf0609d0af0b734d4b9ee9dce6df66f946fc763
diff --git a/src/tools/rustdoc/Cargo.toml b/src/tools/rustdoc/Cargo.toml
index 344f617ef95..d3881500441 100644
--- a/src/tools/rustdoc/Cargo.toml
+++ b/src/tools/rustdoc/Cargo.toml
@@ -7,7 +7,7 @@ authors = ["The Rust Project Developers"]
 # the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
 # rustdoc a different name.
 [[bin]]
-name = "rustdoc-tool-binary"
+name = "rustdoc_tool_binary"
 path = "main.rs"
 
 [dependencies]
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
-Subproject db8cb0b8d6942d42a322b1d36b2504977404f36
+Subproject bf2581bf7709b91c4431ba7074de910f72283e1