about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--config.toml.example35
-rw-r--r--src/Cargo.lock55
-rw-r--r--src/bootstrap/config.rs4
-rw-r--r--src/bootstrap/dist.rs6
-rw-r--r--src/bootstrap/lib.rs3
-rw-r--r--src/build_helper/lib.rs12
-rw-r--r--src/doc/unstable-book/src/language-features/cfg-attr-multi.md20
-rw-r--r--src/doc/unstable-book/src/language-features/tool-lints.md35
-rwxr-xr-xsrc/etc/gdb_rust_pretty_printing.py16
-rw-r--r--src/etc/htmldocck.py52
-rw-r--r--src/liballoc/benches/slice.rs23
-rw-r--r--src/liballoc/collections/btree/node.rs43
-rw-r--r--src/liballoc/fmt.rs2
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/rc.rs4
-rw-r--r--src/liballoc/sync.rs4
-rw-r--r--src/liballoc/vec.rs8
-rw-r--r--src/liballoc_system/lib.rs53
-rw-r--r--src/libcore/option.rs4
-rw-r--r--src/libcore/ptr.rs37
-rw-r--r--src/libcore/slice/mod.rs2
-rw-r--r--src/libcore/task/wake.rs65
-rw-r--r--src/libcore/tests/lib.rs1
-rw-r--r--src/librustc/Cargo.toml2
-rw-r--r--src/librustc/diagnostics.rs18
-rw-r--r--src/librustc/hir/check_attr.rs74
-rw-r--r--src/librustc/hir/lowering.rs1
-rw-r--r--src/librustc/hir/mod.rs1
-rw-r--r--src/librustc/ich/impls_hir.rs3
-rw-r--r--src/librustc/ich/impls_ty.rs58
-rw-r--r--src/librustc/lint/levels.rs27
-rw-r--r--src/librustc/macros.rs10
-rw-r--r--src/librustc/middle/expr_use_visitor.rs23
-rw-r--r--src/librustc/middle/lang_items.rs304
-rw-r--r--src/librustc/middle/region.rs3
-rw-r--r--src/librustc/mir/interpret/mod.rs64
-rw-r--r--src/librustc/mir/interpret/value.rs68
-rw-r--r--src/librustc/mir/mod.rs2
-rw-r--r--src/librustc/mir/visit.rs2
-rw-r--r--src/librustc/session/config.rs4
-rw-r--r--src/librustc/session/mod.rs24
-rw-r--r--src/librustc/traits/coherence.rs10
-rw-r--r--src/librustc/traits/mod.rs22
-rw-r--r--src/librustc/traits/select.rs27
-rw-r--r--src/librustc/traits/structural_impls.rs34
-rw-r--r--src/librustc/ty/context.rs36
-rw-r--r--src/librustc/ty/error.rs3
-rw-r--r--src/librustc/ty/fast_reject.rs2
-rw-r--r--src/librustc/ty/flags.rs5
-rw-r--r--src/librustc/ty/item_path.rs2
-rw-r--r--src/librustc/ty/sty.rs16
-rw-r--r--src/librustc/ty/wf.rs2
-rw-r--r--src/librustc/util/ppaux.rs20
-rw-r--r--src/librustc_codegen_llvm/abi.rs23
-rw-r--r--src/librustc_codegen_llvm/allocator.rs2
-rw-r--r--src/librustc_codegen_llvm/attributes.rs30
-rw-r--r--src/librustc_codegen_llvm/base.rs63
-rw-r--r--src/librustc_codegen_llvm/builder.rs18
-rw-r--r--src/librustc_codegen_llvm/common.rs15
-rw-r--r--src/librustc_codegen_llvm/consts.rs21
-rw-r--r--src/librustc_codegen_llvm/context.rs37
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs7
-rw-r--r--src/librustc_codegen_llvm/debuginfo/type_names.rs14
-rw-r--r--src/librustc_codegen_llvm/declare.rs2
-rw-r--r--src/librustc_codegen_llvm/diagnostics.rs11
-rw-r--r--src/librustc_codegen_llvm/glue.rs4
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs166
-rw-r--r--src/librustc_codegen_llvm/lib.rs2
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs1
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs5
-rw-r--r--src/librustc_codegen_llvm/metadata.rs2
-rw-r--r--src/librustc_codegen_llvm/meth.rs24
-rw-r--r--src/librustc_codegen_llvm/mir/analyze.rs6
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs6
-rw-r--r--src/librustc_codegen_llvm/mir/constant.rs4
-rw-r--r--src/librustc_codegen_llvm/mir/statement.rs28
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs4
-rw-r--r--src/librustc_codegen_llvm/type_of.rs15
-rw-r--r--src/librustc_codegen_llvm/value.rs2
-rw-r--r--src/librustc_driver/lib.rs1
-rw-r--r--src/librustc_errors/diagnostic.rs8
-rw-r--r--src/librustc_lint/unused.rs32
-rw-r--r--src/librustc_mir/borrow_check/mod.rs6
-rw-r--r--src/librustc_mir/borrow_check/move_errors.rs15
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs219
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs160
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs14
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs21
-rw-r--r--src/librustc_mir/build/matches/mod.rs37
-rw-r--r--src/librustc_mir/build/matches/simplify.rs4
-rw-r--r--src/librustc_mir/const_eval.rs101
-rw-r--r--src/librustc_mir/hair/cx/block.rs1
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs4
-rw-r--r--src/librustc_mir/interpret/cast.rs31
-rw-r--r--src/librustc_mir/interpret/eval_context.rs123
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs18
-rw-r--r--src/librustc_mir/interpret/machine.rs102
-rw-r--r--src/librustc_mir/interpret/memory.rs501
-rw-r--r--src/librustc_mir/interpret/mod.rs2
-rw-r--r--src/librustc_mir/interpret/operand.rs230
-rw-r--r--src/librustc_mir/interpret/operator.rs36
-rw-r--r--src/librustc_mir/interpret/place.rs414
-rw-r--r--src/librustc_mir/interpret/snapshot.rs29
-rw-r--r--src/librustc_mir/interpret/terminator.rs42
-rw-r--r--src/librustc_mir/interpret/traits.rs17
-rw-r--r--src/librustc_mir/interpret/validity.rs65
-rw-r--r--src/librustc_mir/monomorphize/collector.rs34
-rw-r--r--src/librustc_mir/monomorphize/item.rs13
-rw-r--r--src/librustc_mir/transform/inline.rs23
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs36
-rw-r--r--src/librustc_privacy/lib.rs7
-rw-r--r--src/librustc_target/abi/mod.rs2
-rw-r--r--src/librustc_target/spec/mod.rs6
-rw-r--r--src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs3
-rw-r--r--src/librustc_traits/Cargo.toml2
-rw-r--r--src/librustc_traits/chalk_context.rs41
-rw-r--r--src/librustc_traits/lowering.rs114
-rw-r--r--src/librustc_typeck/astconv.rs13
-rw-r--r--src/librustc_typeck/check/cast.rs4
-rw-r--r--src/librustc_typeck/check/closure.rs4
-rw-r--r--src/librustc_typeck/check/method/confirm.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs7
-rw-r--r--src/librustc_typeck/check/method/suggest.rs3
-rw-r--r--src/librustc_typeck/coherence/inherent_impls.rs4
-rw-r--r--src/librustc_typeck/coherence/mod.rs5
-rw-r--r--src/librustc_typeck/outlives/implicit_infer.rs43
-rw-r--r--src/librustc_typeck/variance/constraints.rs10
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/mod.rs73
-rw-r--r--src/librustdoc/html/highlight.rs25
-rw-r--r--src/librustdoc/html/render.rs5
-rw-r--r--src/librustdoc/html/static/rustdoc.css37
-rw-r--r--src/libstd/Cargo.toml9
-rw-r--r--src/libstd/fs.rs2
-rw-r--r--src/libstd/panic.rs2
-rw-r--r--src/libstd/primitive_docs.rs25
-rw-r--r--src/libstd/sync/once.rs2
-rw-r--r--src/libstd/sys/wasm/mutex_atomics.rs23
-rw-r--r--src/libstd/sys/wasm/thread.rs46
-rw-r--r--src/libstd/sys/wasm/thread_local_atomics.rs53
-rw-r--r--src/libstd/thread/local.rs14
-rw-r--r--src/libstd/thread/mod.rs2
-rw-r--r--src/libsyntax/config.rs95
-rw-r--r--src/libsyntax/feature_gate.rs18
-rw-r--r--src/libsyntax/parse/lexer/mod.rs13
-rw-r--r--src/libsyntax/parse/parser.rs35
-rw-r--r--src/rustllvm/RustWrapper.cpp2
-rw-r--r--src/rustllvm/rustllvm.h1
-rw-r--r--src/stage0.txt2
-rw-r--r--src/test/codegen/naked-functions.rs10
-rw-r--r--src/test/codegen/no-plt.rs27
-rw-r--r--src/test/mir-opt/basic_assignment.rs2
-rw-r--r--src/test/mir-opt/inline-trait-method.rs31
-rw-r--r--src/test/run-pass/macros/macro-as-fn-body.rs42
-rw-r--r--src/test/run-pass/resolve-pseudo-shadowing.rs2
-rw-r--r--src/test/run-pass/tool_lints.rs2
-rw-r--r--src/test/run-pass/tool_lints_2018_preview.rs2
-rw-r--r--src/test/rustdoc-ui/invalid-syntax.rs17
-rw-r--r--src/test/rustdoc-ui/invalid-syntax.stderr10
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-1.rs4
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-2.rs2
-rw-r--r--src/test/ui-fulldeps/lint_tool_test.rs2
-rw-r--r--src/test/ui/asm/asm-out-assign-imm.nll.stderr4
-rw-r--r--src/test/ui/asm/asm-out-assign-imm.stderr4
-rw-r--r--src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr12
-rw-r--r--src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr24
-rw-r--r--src/test/ui/associated-types/associated-types-subtyping-1.rs20
-rw-r--r--src/test/ui/borrowck/borrowck-asm.ast.nll.stderr16
-rw-r--r--src/test/ui/borrowck/borrowck-asm.ast.stderr16
-rw-r--r--src/test/ui/borrowck/borrowck-asm.mir.stderr16
-rw-r--r--src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr14
-rw-r--r--src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr14
-rw-r--r--src/test/ui/borrowck/borrowck-describe-lvalue.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr4
-rw-r--r--src/test/ui/cfg-attr-trailing-comma.rs13
-rw-r--r--src/test/ui/cfg-attr-trailing-comma.stderr14
-rw-r--r--src/test/ui/chalkify/lower_trait.rs9
-rw-r--r--src/test/ui/chalkify/lower_trait.stderr23
-rw-r--r--src/test/ui/closure-expected-type/README.md1
-rw-r--r--src/test/ui/closure-expected-type/issue-24421.rs20
-rw-r--r--src/test/ui/conditional-compilation/auxiliary/namespaced_enums.rs (renamed from src/test/ui/auxiliary/namespaced_enums.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs (renamed from src/test/ui/cfg-arg-invalid-1.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-2.rs (renamed from src/test/ui/cfg-arg-invalid-2.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-3.rs (renamed from src/test/ui/cfg-arg-invalid-3.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-4.rs (renamed from src/test/ui/cfg-arg-invalid-4.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-5.rs (renamed from src/test/ui/cfg-arg-invalid-5.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-cfg-2.rs (renamed from src/test/ui/cfg-attr-cfg-2.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr (renamed from src/test/ui/cfg-attr-cfg-2.stderr)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-crate-2.rs (renamed from src/test/ui/cfg-attr-crate-2.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr (renamed from src/test/ui/cfg-attr-crate-2.stderr)2
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.rs (renamed from src/test/ui/cfg-attr-invalid-predicate.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr (renamed from src/test/ui/cfg-attr-invalid-predicate.stderr)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-multi-false.rs20
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs16
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr11
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs16
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr11
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-multi-true.rs22
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr38
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-parse.rs45
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-parse.stderr32
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs (renamed from src/test/ui/cfg-attr-syntax-validation.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr (renamed from src/test/ui/cfg-attr-syntax-validation.stderr)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs (renamed from src/test/ui/cfg-attr-unknown-attribute-macro-expansion.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr (renamed from src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-empty-codemap.rs (renamed from src/test/ui/cfg-empty-codemap.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-in-crate-1.rs (renamed from src/test/ui/cfg-in-crate-1.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-in-crate-1.stderr (renamed from src/test/ui/cfg-in-crate-1.stderr)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-non-opt-expr.rs (renamed from src/test/ui/cfg-non-opt-expr.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg-non-opt-expr.stderr (renamed from src/test/ui/cfg-non-opt-expr.stderr)0
-rw-r--r--src/test/ui/conditional-compilation/cfg_attr_path.rs (renamed from src/test/ui/cfg_attr_path.rs)0
-rw-r--r--src/test/ui/conditional-compilation/cfg_attr_path.stderr (renamed from src/test/ui/cfg_attr_path.stderr)0
-rw-r--r--src/test/ui/consts/const-eval/ub-ref.rs3
-rw-r--r--src/test/ui/consts/const-eval/ub-ref.stderr10
-rw-r--r--src/test/ui/consts/const-eval/ub-upvars.rs21
-rw-r--r--src/test/ui/consts/const-eval/ub-upvars.stderr15
-rw-r--r--src/test/ui/consts/issue-54224.rs14
-rw-r--r--src/test/ui/consts/issue-54224.stderr23
-rw-r--r--src/test/ui/did_you_mean/bad-assoc-ty.stderr28
-rw-r--r--src/test/ui/error-codes/E0152.rs2
-rw-r--r--src/test/ui/error-codes/E0152.stderr4
-rw-r--r--src/test/ui/error-codes/E0223.stderr4
-rw-r--r--src/test/ui/error-codes/E0718.rs17
-rw-r--r--src/test/ui/error-codes/E0718.stderr9
-rw-r--r--src/test/ui/feature-gate-underscore_const_names.rs24
-rw-r--r--src/test/ui/feature-gate-underscore_const_names.stderr16
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs5
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr11
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs3
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr11
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs7
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs9
-rw-r--r--src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr11
-rw-r--r--src/test/ui/feature-gates/feature-gate-tool_lints.stderr11
-rw-r--r--src/test/ui/fn_must_use.rs8
-rw-r--r--src/test/ui/fn_must_use.stderr20
-rw-r--r--src/test/ui/impl-trait/impl_trait_projections.stderr4
-rw-r--r--src/test/ui/inline-asm-bad-operand.rs57
-rw-r--r--src/test/ui/inline-asm-bad-operand.stderr33
-rw-r--r--src/test/ui/issues/issue-20801.nll.stderr8
-rw-r--r--src/test/ui/issues/issue-23073.stderr4
-rw-r--r--src/test/ui/issues/issue-34209.stderr4
-rw-r--r--src/test/ui/issues/issue-40510-1.nll.stderr12
-rw-r--r--src/test/ui/issues/issue-40510-3.nll.stderr12
-rw-r--r--src/test/ui/issues/issue-49824.nll.stderr12
-rw-r--r--src/test/ui/issues/issue-52240.nll.stderr9
-rw-r--r--src/test/ui/issues/issue-52240.rs16
-rw-r--r--src/test/ui/issues/issue-52240.stderr9
-rw-r--r--src/test/ui/issues/issue-54966.rs6
-rw-r--r--src/test/ui/issues/issue-54966.stderr9
-rw-r--r--src/test/ui/lint/must_use-unit.rs17
-rw-r--r--src/test/ui/lint/must_use-unit.stderr20
-rw-r--r--src/test/ui/macros/issue-54441.stderr3
-rw-r--r--src/test/ui/nll/issue-52663-trait-object.rs27
-rw-r--r--src/test/ui/nll/issue-52663-trait-object.stderr13
-rw-r--r--src/test/ui/nll/issue-53040.rs16
-rw-r--r--src/test/ui/nll/issue-53040.stderr13
-rw-r--r--src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/patterns.stderr4
-rw-r--r--src/test/ui/panic-handler/panic-handler-wrong-location.rs (renamed from src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs)10
-rw-r--r--src/test/ui/panic-handler/panic-handler-wrong-location.stderr11
-rw-r--r--src/test/ui/qualified/qualified-path-params-2.stderr4
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-addr-of-self.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs7
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr14
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr33
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.rs2
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.stderr6
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr20
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr11
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs2
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr4
-rw-r--r--src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.rs6
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.stderr14
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container.nll.stderr46
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container.rs12
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container.stderr48
-rw-r--r--src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr4
-rw-r--r--src/test/ui/resolve/issue-54379.rs (renamed from src/test/ui/feature-gates/feature-gate-tool_lints.rs)12
-rw-r--r--src/test/ui/resolve/issue-54379.stderr24
-rw-r--r--src/test/ui/self/self-impl.stderr8
-rw-r--r--src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr2
-rw-r--r--src/test/ui/structs/struct-path-associated-type.stderr12
-rw-r--r--src/test/ui/tool_lints-fail.rs2
-rw-r--r--src/test/ui/tool_lints.rs2
-rw-r--r--src/test/ui/traits/trait-item-privacy.stderr12
-rw-r--r--src/test/ui/try-block/try-block-bad-lifetime.stderr2
-rw-r--r--src/test/ui/ufcs/ufcs-partially-resolved.stderr4
-rw-r--r--src/test/ui/underscore_const_names.rs43
-rw-r--r--src/test/ui/unknown-lint-tool-name.rs2
-rw-r--r--src/test/ui/variance/variance-cell-is-invariant.nll.stderr4
-rw-r--r--src/test/ui/wf/wf-static-method.nll.stderr33
m---------src/tools/cargo0
m---------src/tools/clippy24
m---------src/tools/miri10
m---------src/tools/rls0
309 files changed, 4545 insertions, 2151 deletions
diff --git a/config.toml.example b/config.toml.example
index 312270532af..1c851999130 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -243,19 +243,36 @@
 # =============================================================================
 [rust]
 
-# Indicates that the build should be optimized for debugging Rust. Note that
-# this is typically not what you want as it takes an incredibly large amount of
-# time to have a debug-mode rustc compile any code (notably libstd). If this
-# value is set to `true` it will affect a number of configuration options below
-# as well, if unconfigured.
-#debug = false
-
-# Whether or not to optimize the compiler and standard library
+# Whether or not to optimize the compiler and standard library.
+#
 # Note: the slowness of the non optimized compiler compiling itself usually
 #       outweighs the time gains in not doing optimizations, therefore a
-#       full bootstrap takes much more time with optimize set to false.
+#       full bootstrap takes much more time with `optimize` set to false.
 #optimize = true
 
+# Indicates that the build should be configured for debugging Rust. A
+# `debug`-enabled compiler and standard library will be somewhat
+# slower (due to e.g. checking of debug assertions) but should remain
+# usable.
+#
+# Note: If this value is set to `true`, it will affect a number of
+#       configuration options below as well, if they have been left
+#       unconfigured in this file.
+#
+# Note: changes to the `debug` setting do *not* affect `optimize`
+#       above. In theory, a "maximally debuggable" environment would
+#       set `optimize` to `false` above to assist the introspection
+#       facilities of debuggers like lldb and gdb. To recreate such an
+#       environment, explicitly set `optimize` to `false` and `debug`
+#       to `true`. In practice, everyone leaves `optimize` set to
+#       `true`, because an unoptimized rustc with debugging
+#       enabled becomes *unusably slow* (e.g. rust-lang/rust#24840
+#       reported a 25x slowdown) and bootstrapping the supposed
+#       "maximally debuggable" environment (notably libstd) takes
+#       hours to build.
+#
+#debug = false
+
 # Number of codegen units to use for each compiler invocation. A value of 0
 # means "the number of cores on this machine", and 1+ is passed through to the
 # compiler.
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 6a9488226b1..52314b0ac89 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -204,7 +204,7 @@ dependencies = [
  "env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "chalk-engine"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -737,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "flate2"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -826,16 +826,6 @@ version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "getset"
-version = "0.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
 name = "git2"
 version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -969,7 +959,7 @@ version = "0.0.0"
 dependencies = [
  "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1269,7 +1259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "minifier"
-version = "0.0.19"
+version = "0.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1303,7 +1293,7 @@ dependencies = [
  "compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "vergen 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vergen 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1659,7 +1649,7 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.6"
+version = "2.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1807,7 +1797,7 @@ dependencies = [
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "racer 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "racer 2.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1824,6 +1814,7 @@ dependencies = [
  "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1898,8 +1889,8 @@ dependencies = [
  "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fmt_macros 0.0.0",
  "graphviz 0.0.0",
  "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2143,7 +2134,7 @@ dependencies = [
 name = "rustc_codegen_utils"
 version = "0.0.0"
 dependencies = [
- "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_data_structures 0.0.0",
@@ -2286,7 +2277,7 @@ dependencies = [
 name = "rustc_metadata"
 version = "0.0.0"
 dependencies = [
- "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "proc_macro 0.0.0",
  "rustc 0.0.0",
@@ -2434,7 +2425,7 @@ name = "rustc_traits"
 version = "0.0.0"
 dependencies = [
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
@@ -2484,7 +2475,7 @@ dependencies = [
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
- "minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3072,13 +3063,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "vergen"
-version = "2.0.0"
+version = "3.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "getset 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -3195,7 +3185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1"
 "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
 "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
-"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0"
+"checksum chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6749eb72e7d4355d944a99f15fbaea701b978c18c5e184a025fcde942b0c9779"
 "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
 "checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37"
 "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
@@ -3233,7 +3223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
 "checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f"
 "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
-"checksum flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37847f133aae7acf82bb9577ccd8bda241df836787642654286e79679826a54b"
+"checksum flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4af030962d89d62aa52cd9492083b1cd9b2d1a77764878102a6c0f86b4d5444d"
 "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
 "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
 "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
@@ -3245,7 +3235,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
 "checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3"
 "checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
-"checksum getset 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54c7f36a235738bb25904d6a2b3dbb28f6f5736cd3918c4bf80d6bb236200782"
 "checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71"
 "checksum git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b502f6b1b467957403d168f0039e0c46fa6a1220efa2adaef25d5b267b5fe024"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
@@ -3289,7 +3278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
 "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
-"checksum minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9908ed7c62f990c21ab41fdca53a864a3ada0da69d8729c4de727b397e27bc11"
+"checksum minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "96c269bb45c39b333392b2b18ad71760b34ac65666591386b0e959ed58b3f474"
 "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
 "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
 "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
@@ -3331,7 +3320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
 "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
-"checksum racer 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "99e820b7f7701c834c3f6f8226f388c19c0ea948a3ef79ddc96aa7398b5ba87a"
+"checksum racer 2.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0beefbfaed799c3554021a48856113ad53862311395f6d75376192884ba5fbe6"
 "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
 "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
 "checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
@@ -3419,7 +3408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
 "checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
 "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
-"checksum vergen 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a16834fc61e1492c07dae49b6c14b55f8b1d43a5f5f9e9a2ecc063f47b9f93c"
+"checksum vergen 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9696d96ec5d68984d060af80d7ba0ed4eb533978a0efb05ed4b8465f20d04f"
 "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum wait-timeout 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f3bf741a801531993db6478b95682117471f76916f5e690dd8d45395b09349"
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index c3fbc8eeca6..a5ed096a735 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -628,6 +628,9 @@ impl Config {
         let default = false;
         config.llvm_assertions = llvm_assertions.unwrap_or(default);
 
+        let default = true;
+        config.rust_optimize = optimize.unwrap_or(default);
+
         let default = match &config.channel[..] {
             "stable" | "beta" | "nightly" => true,
             _ => false,
@@ -640,7 +643,6 @@ impl Config {
         config.debug_jemalloc = debug_jemalloc.unwrap_or(default);
         config.rust_debuginfo = debuginfo.unwrap_or(default);
         config.rust_debug_assertions = debug_assertions.unwrap_or(default);
-        config.rust_optimize = optimize.unwrap_or(!default);
 
         let default = config.channel == "dev";
         config.ignore_git = ignore_git.unwrap_or(default);
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index c25f94357f2..cf79d4f777a 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1263,14 +1263,16 @@ impl Step for Clippy {
         builder.install(&cargoclippy, &image.join("bin"), 0o755);
         let doc = image.join("share/doc/clippy");
         builder.install(&src.join("README.md"), &doc, 0o644);
-        builder.install(&src.join("LICENSE"), &doc, 0o644);
+        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
+        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
 
         // Prepare the overlay
         let overlay = tmp.join("clippy-overlay");
         drop(fs::remove_dir_all(&overlay));
         t!(fs::create_dir_all(&overlay));
         builder.install(&src.join("README.md"), &overlay, 0o644);
-        builder.install(&src.join("LICENSE"), &doc, 0o644);
+        builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
+        builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
         builder.create(&overlay.join("version"), &version);
 
         // Generate the installer tarball
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 247727762d1..c09de02ab51 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1288,6 +1288,9 @@ impl Build {
         t!(fs::create_dir_all(dstdir));
         drop(fs::remove_file(&dst));
         {
+            if !src.exists() {
+                panic!("Error: File \"{}\" not found!", src.display());
+            }
             let mut s = t!(fs::File::open(&src));
             let mut d = t!(fs::File::create(&dst));
             io::copy(&mut s, &mut d).expect("failed to copy");
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index ec94f57861d..5d174719ab2 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -91,13 +91,13 @@ pub fn try_run_suppressed(cmd: &mut Command) -> bool {
     output.status.success()
 }
 
-pub fn gnu_target(target: &str) -> String {
+pub fn gnu_target(target: &str) -> &str {
     match target {
-        "i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
-        "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
-        "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
-        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
-        s => s.to_string(),
+        "i686-pc-windows-msvc" => "i686-pc-win32",
+        "x86_64-pc-windows-msvc" => "x86_64-pc-win32",
+        "i686-pc-windows-gnu" => "i686-w64-mingw32",
+        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
+        s => s,
     }
 }
 
diff --git a/src/doc/unstable-book/src/language-features/cfg-attr-multi.md b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md
new file mode 100644
index 00000000000..6365d3e71c6
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md
@@ -0,0 +1,20 @@
+# `cfg_attr_multi`
+
+The tracking issue for this feature is: [#54881]
+The RFC for this feature is: [#2539]
+
+[#54881]: https://github.com/rust-lang/rust/issues/54881
+[#2539]: https://github.com/rust-lang/rfcs/pull/2539
+
+------------------------
+
+This feature flag lets you put multiple attributes into a `cfg_attr` attribute.
+
+Example:
+
+```rust,ignore
+#[cfg_attr(all(), must_use, optimize)]
+```
+
+Because `cfg_attr` resolves before procedural macros, this does not affect
+macro resolution at all.
\ No newline at end of file
diff --git a/src/doc/unstable-book/src/language-features/tool-lints.md b/src/doc/unstable-book/src/language-features/tool-lints.md
deleted file mode 100644
index 5c0d33b5ab0..00000000000
--- a/src/doc/unstable-book/src/language-features/tool-lints.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# `tool_lints`
-
-The tracking issue for this feature is: [#44690]
-
-[#44690]: https://github.com/rust-lang/rust/issues/44690
-
-------------------------
-
-Tool lints let you use scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of
-certain tools.
-
-Currently `clippy` is the only available lint tool.
-
-It is recommended for lint tools to implement the scoped lints like this:
-
-- `#[_(TOOL_NAME::lintname)]`: for lint names
-- `#[_(TOOL_NAME::lintgroup)]`: for groups of lints
-- `#[_(TOOL_NAME::all)]`: for (almost[^1]) all lints
-
-## An example
-
-```rust
-#![feature(tool_lints)]
-
-#![warn(clippy::pedantic)]
-
-#[allow(clippy::filter_map)]
-fn main() {
-    let v = vec![0; 10];
-    let _ = v.into_iter().filter(|&x| x < 1).map(|x| x + 1).collect::<Vec<_>>();
-    println!("No filter_map()!");
-}
-```
-
-[^1]: Some defined lint groups can be excluded here.
diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py
index 216915dba5f..b1252f386df 100755
--- a/src/etc/gdb_rust_pretty_printing.py
+++ b/src/etc/gdb_rust_pretty_printing.py
@@ -322,8 +322,11 @@ class RustStdBTreeSetPrinter(object):
     def children(self):
         (length, data_ptr) = \
             rustpp.extract_length_and_ptr_from_std_btreeset(self.__val)
-        val = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
-        gdb_ptr = val.get_wrapped_value()
+        leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
+        maybe_uninit_keys = leaf_node.get_child_at_index(3)
+        manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
+        keys = manually_drop_keys.get_child_at_index(0)
+        gdb_ptr = keys.get_wrapped_value()
         for index in xrange(length):
             yield (str(index), gdb_ptr[index])
 
@@ -345,9 +348,14 @@ class RustStdBTreeMapPrinter(object):
     def children(self):
         (length, data_ptr) = \
             rustpp.extract_length_and_ptr_from_std_btreemap(self.__val)
-        keys = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
+        leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
+        maybe_uninit_keys = leaf_node.get_child_at_index(3)
+        manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
+        keys = manually_drop_keys.get_child_at_index(0)
         keys_ptr = keys.get_wrapped_value()
-        vals = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(4)
+        maybe_uninit_vals = leaf_node.get_child_at_index(4)
+        manually_drop_vals = maybe_uninit_vals.get_child_at_index(1)
+        vals = manually_drop_vals.get_child_at_index(0)
         vals_ptr = vals.get_wrapped_value()
         for index in xrange(length):
             yield (str(index), keys_ptr[index])
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 569788fe9c0..91010262981 100644
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -15,65 +15,66 @@ htmldocck.py is a custom checker script for Rustdoc HTML outputs.
 
 The principle is simple: This script receives a path to generated HTML
 documentation and a "template" script, which has a series of check
-commands like `@has` or `@matches`. Each command can be used to check if
+commands like `@has` or `@matches`. Each command is used to check if
 some pattern is present or not present in the particular file or in
-the particular node of HTML tree. In many cases, the template script
-happens to be a source code given to rustdoc.
+a particular node of the HTML tree. In many cases, the template script
+happens to be the source code given to rustdoc.
 
 While it indeed is possible to test in smaller portions, it has been
 hard to construct tests in this fashion and major rendering errors were
-discovered much later. This script is designed for making the black-box
-and regression testing of Rustdoc easy. This does not preclude the needs
-for unit testing, but can be used to complement related tests by quickly
+discovered much later. This script is designed to make black-box and
+regression testing of Rustdoc easy. This does not preclude the needs for
+unit testing, but can be used to complement related tests by quickly
 showing the expected renderings.
 
 In order to avoid one-off dependencies for this task, this script uses
 a reasonably working HTML parser and the existing XPath implementation
-from Python's standard library. Hopefully we won't render
+from Python's standard library. Hopefully, we won't render
 non-well-formed HTML.
 
 # Commands
 
 Commands start with an `@` followed by a command name (letters and
 hyphens), and zero or more arguments separated by one or more whitespace
-and optionally delimited with single or double quotes. The `@` mark
-cannot be preceded by a non-whitespace character. Other lines (including
-every text up to the first `@`) are ignored, but it is recommended to
-avoid the use of `@` in the template file.
+characters and optionally delimited with single or double quotes. The `@`
+mark cannot be preceded by a non-whitespace character. Other lines
+(including every text up to the first `@`) are ignored, but it is
+recommended to avoid the use of `@` in the template file.
 
 There are a number of supported commands:
 
-* `@has PATH` checks for the existence of given file.
+* `@has PATH` checks for the existence of the given file.
 
   `PATH` is relative to the output directory. It can be given as `-`
   which repeats the most recently used `PATH`.
 
 * `@has PATH PATTERN` and `@matches PATH PATTERN` checks for
-  the occurrence of given `PATTERN` in the given file. Only one
-  occurrence of given pattern is enough.
+  the occurrence of the given pattern `PATTERN` in the specified file.
+  Only one occurrence of the pattern is enough.
 
   For `@has`, `PATTERN` is a whitespace-normalized (every consecutive
   whitespace being replaced by one single space character) string.
   The entire file is also whitespace-normalized including newlines.
 
   For `@matches`, `PATTERN` is a Python-supported regular expression.
-  The file remains intact but the regexp is matched with no `MULTILINE`
-  and `IGNORECASE` option. You can still use a prefix `(?m)` or `(?i)`
+  The file remains intact but the regexp is matched without the `MULTILINE`
+  and `IGNORECASE` options. You can still use a prefix `(?m)` or `(?i)`
   to override them, and `\A` and `\Z` for definitely matching
   the beginning and end of the file.
 
   (The same distinction goes to other variants of these commands.)
 
 * `@has PATH XPATH PATTERN` and `@matches PATH XPATH PATTERN` checks for
-  the presence of given `XPATH` in the given HTML file, and also
-  the occurrence of given `PATTERN` in the matching node or attribute.
-  Only one occurrence of given pattern in the match is enough.
+  the presence of the given XPath `XPATH` in the specified HTML file,
+  and also the occurrence of the given pattern `PATTERN` in the matching
+  node or attribute. Only one occurrence of the pattern in the match
+  is enough.
 
   `PATH` should be a valid and well-formed HTML file. It does *not*
   accept arbitrary HTML5; it should have matching open and close tags
   and correct entity references at least.
 
-  `XPATH` is an XPath expression to match. This is fairly limited:
+  `XPATH` is an XPath expression to match. The XPath is fairly limited:
   `tag`, `*`, `.`, `//`, `..`, `[@attr]`, `[@attr='value']`, `[tag]`,
   `[POS]` (element located in given `POS`), `[last()-POS]`, `text()`
   and `@attr` (both as the last segment) are supported. Some examples:
@@ -85,7 +86,7 @@ There are a number of supported commands:
   - `//h1[@class="fqn"]/span[1]/a[last()]/@class` matches a value of
     `class` attribute in the last `a` element (can be followed by more
     elements that are not `a`) inside the first `span` in the `h1` with
-    a class of `fqn`. Note that there cannot be no additional elements
+    a class of `fqn`. Note that there cannot be any additional elements
     between them due to the use of `/` instead of `//`.
 
   Do not try to use non-absolute paths, it won't work due to the flawed
@@ -93,11 +94,12 @@ There are a number of supported commands:
 
   For the text matches (i.e. paths not ending with `@attr`), any
   subelements are flattened into one string; this is handy for ignoring
-  highlights for example. If you want to simply check the presence of
-  given node or attribute, use an empty string (`""`) as a `PATTERN`.
+  highlights for example. If you want to simply check for the presence of
+  a given node or attribute, use an empty string (`""`) as a `PATTERN`.
 
-* `@count PATH XPATH COUNT' checks for the occurrence of given XPath
-  in the given file. The number of occurrences must match the given count.
+* `@count PATH XPATH COUNT' checks for the occurrence of the given XPath
+  in the specified file. The number of occurrences must match the given
+  count.
 
 * `@has-dir PATH` checks for the existence of the given directory.
 
diff --git a/src/liballoc/benches/slice.rs b/src/liballoc/benches/slice.rs
index a699ff9c0a7..490320f57cb 100644
--- a/src/liballoc/benches/slice.rs
+++ b/src/liballoc/benches/slice.rs
@@ -13,6 +13,7 @@ use std::mem;
 use std::ptr;
 
 use rand::{Rng, SeedableRng, XorShiftRng};
+use rand::distributions::{Standard, Alphanumeric};
 use test::{Bencher, black_box};
 
 #[bench]
@@ -192,18 +193,20 @@ fn gen_descending(len: usize) -> Vec<u64> {
     (0..len as u64).rev().collect()
 }
 
+const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+
 fn gen_random(len: usize) -> Vec<u64> {
-    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
-    rng.gen_iter::<u64>().take(len).collect()
+    let mut rng = XorShiftRng::from_seed(SEED);
+    rng.sample_iter(&Standard).take(len).collect()
 }
 
 fn gen_random_bytes(len: usize) -> Vec<u8> {
-    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
-    rng.gen_iter::<u8>().take(len).collect()
+    let mut rng = XorShiftRng::from_seed(SEED);
+    rng.sample_iter(&Standard).take(len).collect()
 }
 
 fn gen_mostly_ascending(len: usize) -> Vec<u64> {
-    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
+    let mut rng = XorShiftRng::from_seed(SEED);
     let mut v = gen_ascending(len);
     for _ in (0usize..).take_while(|x| x * x <= len) {
         let x = rng.gen::<usize>() % len;
@@ -214,7 +217,7 @@ fn gen_mostly_ascending(len: usize) -> Vec<u64> {
 }
 
 fn gen_mostly_descending(len: usize) -> Vec<u64> {
-    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
+    let mut rng = XorShiftRng::from_seed(SEED);
     let mut v = gen_descending(len);
     for _ in (0usize..).take_while(|x| x * x <= len) {
         let x = rng.gen::<usize>() % len;
@@ -225,18 +228,18 @@ fn gen_mostly_descending(len: usize) -> Vec<u64> {
 }
 
 fn gen_strings(len: usize) -> Vec<String> {
-    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
+    let mut rng = XorShiftRng::from_seed(SEED);
     let mut v = vec![];
     for _ in 0..len {
         let n = rng.gen::<usize>() % 20 + 1;
-        v.push(rng.gen_ascii_chars().take(n).collect());
+        v.push(rng.sample_iter(&Alphanumeric).take(n).collect());
     }
     v
 }
 
 fn gen_big_random(len: usize) -> Vec<[u64; 16]> {
-    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
-    rng.gen_iter().map(|x| [x; 16]).take(len).collect()
+    let mut rng = XorShiftRng::from_seed(SEED);
+    rng.sample_iter(&Standard).map(|x| [x; 16]).take(len).collect()
 }
 
 macro_rules! sort {
diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs
index 0315545262b..deca9591fbd 100644
--- a/src/liballoc/collections/btree/node.rs
+++ b/src/liballoc/collections/btree/node.rs
@@ -42,7 +42,7 @@
 //   This implies that even an empty internal node has at least one edge.
 
 use core::marker::PhantomData;
-use core::mem;
+use core::mem::{self, MaybeUninit};
 use core::ptr::{self, Unique, NonNull};
 use core::slice;
 
@@ -58,9 +58,6 @@ pub const CAPACITY: usize = 2 * B - 1;
 /// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned
 /// case.
 ///
-/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
-/// avoiding accidentally dropping unused and uninitialized keys and values.
-///
 /// We put the metadata first so that its position is the same for every `K` and `V`, in order
 /// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
 /// prevent them from being reordered.
@@ -73,7 +70,7 @@ struct LeafNode<K, V> {
     /// This node's index into the parent node's `edges` array.
     /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`.
     /// This is only guaranteed to be initialized when `parent` is nonnull.
-    parent_idx: u16,
+    parent_idx: MaybeUninit<u16>,
 
     /// The number of keys and values this node stores.
     ///
@@ -83,8 +80,8 @@ struct LeafNode<K, V> {
 
     /// The arrays storing the actual data of the node. Only the first `len` elements of each
     /// array are initialized and valid.
-    keys: [K; CAPACITY],
-    vals: [V; CAPACITY],
+    keys: MaybeUninit<[K; CAPACITY]>,
+    vals: MaybeUninit<[V; CAPACITY]>,
 }
 
 impl<K, V> LeafNode<K, V> {
@@ -94,10 +91,10 @@ impl<K, V> LeafNode<K, V> {
         LeafNode {
             // As a general policy, we leave fields uninitialized if they can be, as this should
             // be both slightly faster and easier to track in Valgrind.
-            keys: mem::uninitialized(),
-            vals: mem::uninitialized(),
+            keys: MaybeUninit::uninitialized(),
+            vals: MaybeUninit::uninitialized(),
             parent: ptr::null(),
-            parent_idx: mem::uninitialized(),
+            parent_idx: MaybeUninit::uninitialized(),
             len: 0
         }
     }
@@ -115,10 +112,10 @@ unsafe impl Sync for LeafNode<(), ()> {}
 // ever take a pointer past the first key.
 static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
     parent: ptr::null(),
-    parent_idx: 0,
+    parent_idx: MaybeUninit::uninitialized(),
     len: 0,
-    keys: [(); CAPACITY],
-    vals: [(); CAPACITY],
+    keys: MaybeUninit::uninitialized(),
+    vals: MaybeUninit::uninitialized(),
 };
 
 /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
@@ -430,7 +427,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
                     root: self.root,
                     _marker: PhantomData
                 },
-                idx: self.as_leaf().parent_idx as usize,
+                idx: unsafe { usize::from(*self.as_leaf().parent_idx.get_ref()) },
                 _marker: PhantomData
             })
         } else {
@@ -567,7 +564,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
             // the node, which is allowed by LLVM.
             unsafe {
                 slice::from_raw_parts(
-                    self.as_leaf().keys.as_ptr(),
+                    self.as_leaf().keys.as_ptr() as *const K,
                     self.len()
                 )
             }
@@ -578,7 +575,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
         debug_assert!(!self.is_shared_root());
         unsafe {
             slice::from_raw_parts(
-                self.as_leaf().vals.as_ptr(),
+                self.as_leaf().vals.as_ptr() as *const V,
                 self.len()
             )
         }
@@ -605,7 +602,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
         } else {
             unsafe {
                 slice::from_raw_parts_mut(
-                    &mut self.as_leaf_mut().keys as *mut [K] as *mut K,
+                    self.as_leaf_mut().keys.get_mut() as *mut [K] as *mut K,
                     self.len()
                 )
             }
@@ -616,7 +613,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
         debug_assert!(!self.is_shared_root());
         unsafe {
             slice::from_raw_parts_mut(
-                &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
+                self.as_leaf_mut().vals.get_mut() as *mut [V] as *mut V,
                 self.len()
             )
         }
@@ -1013,7 +1010,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
         let ptr = self.node.as_internal_mut() as *mut _;
         let mut child = self.descend();
         child.as_leaf_mut().parent = ptr;
-        child.as_leaf_mut().parent_idx = idx;
+        child.as_leaf_mut().parent_idx.set(idx);
     }
 
     /// Unsafely asserts to the compiler some static information about whether the underlying
@@ -1152,12 +1149,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
 
             ptr::copy_nonoverlapping(
                 self.node.keys().as_ptr().add(self.idx + 1),
-                new_node.keys.as_mut_ptr(),
+                new_node.keys.as_mut_ptr() as *mut K,
                 new_len
             );
             ptr::copy_nonoverlapping(
                 self.node.vals().as_ptr().add(self.idx + 1),
-                new_node.vals.as_mut_ptr(),
+                new_node.vals.as_mut_ptr() as *mut V,
                 new_len
             );
 
@@ -1210,12 +1207,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
 
             ptr::copy_nonoverlapping(
                 self.node.keys().as_ptr().add(self.idx + 1),
-                new_node.data.keys.as_mut_ptr(),
+                new_node.data.keys.as_mut_ptr() as *mut K,
                 new_len
             );
             ptr::copy_nonoverlapping(
                 self.node.vals().as_ptr().add(self.idx + 1),
-                new_node.data.vals.as_mut_ptr(),
+                new_node.data.vals.as_mut_ptr() as *mut V,
                 new_len
             );
             ptr::copy_nonoverlapping(
diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs
index b49ec0ae252..a2e68a223f1 100644
--- a/src/liballoc/fmt.rs
+++ b/src/liballoc/fmt.rs
@@ -152,7 +152,7 @@
 //! Additionally, the return value of this function is [`fmt::Result`] which is a
 //! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
 //! should ensure that they propagate errors from the [`Formatter`][`Formatter`] (e.g., when
-//! calling [`write!`]) however, they should never return errors spuriously. That
+//! calling [`write!`]). However, they should never return errors spuriously. That
 //! is, a formatting implementation must and may only return an error if the
 //! passed-in [`Formatter`] returns an error. This is because, contrary to what
 //! the function signature might suggest, string formatting is an infallible
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 78d1958b8fb..987572e6b74 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -119,6 +119,7 @@
 #![feature(rustc_const_unstable)]
 #![feature(const_vec_new)]
 #![feature(slice_partition_dedup)]
+#![feature(maybe_uninit)]
 
 // Allow testing this library
 
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 915b8e7787e..40bb2faa362 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -867,7 +867,7 @@ impl<T: ?Sized> Clone for Rc<T> {
     ///
     /// let five = Rc::new(5);
     ///
-    /// Rc::clone(&five);
+    /// let _ = Rc::clone(&five);
     /// ```
     #[inline]
     fn clone(&self) -> Rc<T> {
@@ -1304,7 +1304,7 @@ impl<T: ?Sized> Clone for Weak<T> {
     ///
     /// let weak_five = Rc::downgrade(&Rc::new(5));
     ///
-    /// Weak::clone(&weak_five);
+    /// let _ = Weak::clone(&weak_five);
     /// ```
     #[inline]
     fn clone(&self) -> Weak<T> {
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 9e245fbd7bb..35935861fb1 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -713,7 +713,7 @@ impl<T: ?Sized> Clone for Arc<T> {
     ///
     /// let five = Arc::new(5);
     ///
-    /// Arc::clone(&five);
+    /// let _ = Arc::clone(&five);
     /// ```
     #[inline]
     fn clone(&self) -> Arc<T> {
@@ -1135,7 +1135,7 @@ impl<T: ?Sized> Clone for Weak<T> {
     ///
     /// let weak_five = Arc::downgrade(&Arc::new(5));
     ///
-    /// Weak::clone(&weak_five);
+    /// let _ = Weak::clone(&weak_five);
     /// ```
     #[inline]
     fn clone(&self) -> Weak<T> {
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 2bc037e3fee..f7a0bbdceaf 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -120,11 +120,17 @@ use raw_vec::RawVec;
 /// assert_eq!(vec, [1, 2, 3, 4]);
 /// ```
 ///
-/// It can also initialize each element of a `Vec<T>` with a given value:
+/// It can also initialize each element of a `Vec<T>` with a given value.
+/// This may be more efficient than performing allocation and initialization
+/// in separate steps, especially when initializing a vector of zeros:
 ///
 /// ```
 /// let vec = vec![0; 5];
 /// assert_eq!(vec, [0, 0, 0, 0, 0]);
+///
+/// // The following is equivalent, but potentially slower:
+/// let mut vec1 = Vec::with_capacity(5);
+/// vec1.resize(5, 0);
 /// ```
 ///
 /// Use a `Vec<T>` as an efficient stack:
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 3ef03ec6d58..15283036bb4 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -20,6 +20,10 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
+#![cfg_attr(
+    all(target_arch = "wasm32", not(target_os = "emscripten")),
+    feature(integer_atomics, stdsimd)
+)]
 #![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
 #![rustc_alloc_kind = "lib"]
 
@@ -331,29 +335,76 @@ mod platform {
     use core::alloc::{GlobalAlloc, Layout};
     use System;
 
-    // No need for synchronization here as wasm is currently single-threaded
     static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
 
     #[stable(feature = "alloc_system_type", since = "1.28.0")]
     unsafe impl GlobalAlloc for System {
         #[inline]
         unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            let _lock = lock::lock();
             DLMALLOC.malloc(layout.size(), layout.align())
         }
 
         #[inline]
         unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            let _lock = lock::lock();
             DLMALLOC.calloc(layout.size(), layout.align())
         }
 
         #[inline]
         unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+            let _lock = lock::lock();
             DLMALLOC.free(ptr, layout.size(), layout.align())
         }
 
         #[inline]
         unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+            let _lock = lock::lock();
             DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
         }
     }
+
+    #[cfg(target_feature = "atomics")]
+    mod lock {
+        use core::arch::wasm32;
+        use core::sync::atomic::{AtomicI32, Ordering::SeqCst};
+
+        static LOCKED: AtomicI32 = AtomicI32::new(0);
+
+        pub struct DropLock;
+
+        pub fn lock() -> DropLock {
+            loop {
+                if LOCKED.swap(1, SeqCst) == 0 {
+                    return DropLock
+                }
+                unsafe {
+                    let r = wasm32::atomic::wait_i32(
+                        &LOCKED as *const AtomicI32 as *mut i32,
+                        1,  // expected value
+                        -1, // timeout
+                    );
+                    debug_assert!(r == 0 || r == 1);
+                }
+            }
+        }
+
+        impl Drop for DropLock {
+            fn drop(&mut self) {
+                let r = LOCKED.swap(0, SeqCst);
+                debug_assert_eq!(r, 1);
+                unsafe {
+                    wasm32::atomic::wake(
+                        &LOCKED as *const AtomicI32 as *mut i32,
+                        1, // only one thread
+                    );
+                }
+            }
+        }
+    }
+
+    #[cfg(not(target_feature = "atomics"))]
+    mod lock {
+        pub fn lock() {} // no atomics, no threads, that's easy!
+    }
 }
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 0255f7a0885..cf1c77041b9 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -867,8 +867,6 @@ impl<T> Option<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(option_replace)]
-    ///
     /// let mut x = Some(2);
     /// let old = x.replace(5);
     /// assert_eq!(x, Some(5));
@@ -880,7 +878,7 @@ impl<T> Option<T> {
     /// assert_eq!(old, None);
     /// ```
     #[inline]
-    #[unstable(feature = "option_replace", issue = "51998")]
+    #[stable(feature = "option_replace", since = "1.31.0")]
     pub fn replace(&mut self, value: T) -> Option<T> {
         mem::replace(self, Some(value))
     }
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index bd58dcf4ae0..b8d7fcffbcc 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -2370,13 +2370,13 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
         ///
         /// 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];
+        const INV_TABLE_MOD_16: [u8; 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];
+        let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1] as usize;
         if m <= INV_TABLE_MOD {
             table_inverse & (m - 1)
         } else {
@@ -2429,36 +2429,23 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
     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
+    if p as usize & (gcd - 1) == 0 {
+        // This branch solves for the following linear congruence equation:
         //
-        // * a, s are co-prime
+        // $$ p + so ≡ 0 mod a $$
         //
-        // This gives us the formula below:
+        // $p$ here is the pointer value, $s$ – stride of `T`, $o$ offset in `T`s, and $a$ – the
+        // requested alignment.
         //
-        // o = (a - (p mod a)) * (s⁻¹ mod a) * s
+        // g = gcd(a, s)
+        // o = (a - (p mod a))/g * ((s/g)⁻¹ mod a)
         //
         // 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.
+        // incrementing p by s bytes change the relative alignment of p”. Division by `g` is
+        // necessary to make this equation well formed if $a$ and $s$ are not co-prime.
         //
         // 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.
+        // to take the result $o mod lcm(s, a)$. We can replace $lcm(s, a)$ with just a $a / g$.
         let j = a.wrapping_sub(pmoda) >> gcdpow;
         let k = smoda >> gcdpow;
         return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow);
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 76dcca02578..c9013f589ed 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -1932,7 +1932,7 @@ impl<T> [T] {
         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
+            // because relying on llvm to consteval all this is… well, it makes me uncomfortable.
             let (ctz_a, mut ctz_b) = unsafe {
                 if a == 0 { return b; }
                 if b == 0 { return a; }
diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs
index 651db6356ba..ab4ae50c443 100644
--- a/src/libcore/task/wake.rs
+++ b/src/libcore/task/wake.rs
@@ -12,7 +12,7 @@
             reason = "futures in libcore are unstable",
             issue = "50547")]
 
-use {fmt, mem};
+use fmt;
 use marker::Unpin;
 use ptr::NonNull;
 
@@ -63,6 +63,20 @@ impl Waker {
     pub fn will_wake(&self, other: &Waker) -> bool {
         self.inner == other.inner
     }
+
+    /// Returns whether or not this `Waker` and `other` `LocalWaker` awaken
+    /// the same task.
+    ///
+    /// This function works on a best-effort basis, and may return false even
+    /// when the `Waker`s would awaken the same task. However, if this function
+    /// returns true, it is guaranteed that the `Waker`s will awaken the same
+    /// task.
+    ///
+    /// This function is primarily used for optimization purposes.
+    #[inline]
+    pub fn will_wake_local(&self, other: &LocalWaker) -> bool {
+        self.will_wake(&other.0)
+    }
 }
 
 impl Clone for Waker {
@@ -97,9 +111,8 @@ impl Drop for Waker {
 /// Task executors can use this type to implement more optimized singlethreaded wakeup
 /// behavior.
 #[repr(transparent)]
-pub struct LocalWaker {
-    inner: NonNull<dyn UnsafeWake>,
-}
+#[derive(Clone)]
+pub struct LocalWaker(Waker);
 
 impl Unpin for LocalWaker {}
 impl !Send for LocalWaker {}
@@ -120,7 +133,16 @@ impl LocalWaker {
     /// on the current thread.
     #[inline]
     pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
-        LocalWaker { inner }
+        LocalWaker(Waker::new(inner))
+    }
+
+    /// Borrows this `LocalWaker` as a `Waker`.
+    ///
+    /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
+    /// (implements `Send` and `Sync`).
+    #[inline]
+    pub fn as_waker(&self) -> &Waker {
+        &self.0
     }
 
     /// Converts this `LocalWaker` into a `Waker`.
@@ -129,13 +151,13 @@ impl LocalWaker {
     /// (implements `Send` and `Sync`).
     #[inline]
     pub fn into_waker(self) -> Waker {
-        self.into()
+        self.0
     }
 
     /// Wake up the task associated with this `LocalWaker`.
     #[inline]
     pub fn wake(&self) {
-        unsafe { self.inner.as_ref().wake_local() }
+        unsafe { self.0.inner.as_ref().wake_local() }
     }
 
     /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
@@ -148,7 +170,7 @@ impl LocalWaker {
     /// This function is primarily used for optimization purposes.
     #[inline]
     pub fn will_wake(&self, other: &LocalWaker) -> bool {
-        self.inner == other.inner
+        self.0.will_wake(&other.0)
     }
 
     /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
@@ -161,45 +183,24 @@ impl LocalWaker {
     /// This function is primarily used for optimization purposes.
     #[inline]
     pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
-        self.inner == other.inner
+        self.0.will_wake(other)
     }
 }
 
 impl From<LocalWaker> for Waker {
     #[inline]
     fn from(local_waker: LocalWaker) -> Self {
-        let inner = local_waker.inner;
-        mem::forget(local_waker);
-        Waker { inner }
-    }
-}
-
-impl Clone for LocalWaker {
-    #[inline]
-    fn clone(&self) -> Self {
-        let waker = unsafe { self.inner.as_ref().clone_raw() };
-        let inner = waker.inner;
-        mem::forget(waker);
-        LocalWaker { inner }
+        local_waker.0
     }
 }
 
 impl fmt::Debug for LocalWaker {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("Waker")
+        f.debug_struct("LocalWaker")
             .finish()
     }
 }
 
-impl Drop for LocalWaker {
-    #[inline]
-    fn drop(&mut self) {
-        unsafe {
-            self.inner.as_ref().drop_raw()
-        }
-    }
-}
-
 /// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
 ///
 /// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index ada61d8dfd8..0beb60a1270 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -39,7 +39,6 @@
 #![feature(reverse_bits)]
 #![feature(inner_deref)]
 #![feature(slice_internals)]
-#![feature(option_replace)]
 #![feature(slice_partition_dedup)]
 #![feature(copy_within)]
 
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 6c3b52196a3..d0ec8640ce9 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -31,7 +31,7 @@ syntax_pos = { path = "../libsyntax_pos" }
 backtrace = "0.3.3"
 parking_lot = "0.6"
 byteorder = { version = "1.1", features = ["i128"]}
-chalk-engine = { version = "0.7.0", default-features=false }
+chalk-engine = { version = "0.8.0", default-features=false }
 rustc_fs_util = { path = "../librustc_fs_util" }
 smallvec = { version = "0.6.5", features = ["union"] }
 
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 84afdd53cf4..1d21a5cf79d 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -637,8 +637,8 @@ Erroneous code example:
 ```compile_fail,E0152
 #![feature(lang_items)]
 
-#[lang = "panic_impl"]
-struct Foo; // error: duplicate lang item found: `panic_impl`
+#[lang = "arc"]
+struct Foo; // error: duplicate lang item found: `arc`
 ```
 
 Lang items are already implemented in the standard library. Unless you are
@@ -2116,6 +2116,20 @@ struct Foo;
 ```
 "##,
 
+E0718: r##"
+This error indicates that a `#[lang = ".."]` attribute was placed
+on the wrong type of item.
+
+Examples of erroneous code:
+
+```compile_fail,E0718
+#![feature(lang_items)]
+
+#[lang = "arc"]
+static X: u32 = 42;
+```
+"##,
+
 }
 
 
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index b23a50ef1a4..020012d756a 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -14,40 +14,80 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use syntax_pos::Span;
-use ty::TyCtxt;
-
 use hir;
 use hir::intravisit::{self, Visitor, NestedVisitorMap};
+use ty::TyCtxt;
+use std::fmt::{self, Display};
+use syntax_pos::Span;
 
 #[derive(Copy, Clone, PartialEq)]
-enum Target {
+pub(crate) enum Target {
+    ExternCrate,
+    Use,
+    Static,
+    Const,
     Fn,
+    Closure,
+    Mod,
+    ForeignMod,
+    GlobalAsm,
+    Ty,
+    Existential,
+    Enum,
     Struct,
     Union,
-    Enum,
-    Const,
-    ForeignMod,
+    Trait,
+    TraitAlias,
+    Impl,
     Expression,
     Statement,
-    Closure,
-    Static,
-    Trait,
-    Other,
+}
+
+impl Display for Target {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", match *self {
+            Target::ExternCrate => "extern crate",
+            Target::Use => "use",
+            Target::Static => "static item",
+            Target::Const => "constant item",
+            Target::Fn => "function",
+            Target::Closure => "closure",
+            Target::Mod => "module",
+            Target::ForeignMod => "foreign module",
+            Target::GlobalAsm => "global asm",
+            Target::Ty => "type alias",
+            Target::Existential => "existential type",
+            Target::Enum => "enum",
+            Target::Struct => "struct",
+            Target::Union => "union",
+            Target::Trait => "trait",
+            Target::TraitAlias => "trait alias",
+            Target::Impl => "item",
+            Target::Expression => "expression",
+            Target::Statement => "statement",
+        })
+    }
 }
 
 impl Target {
-    fn from_item(item: &hir::Item) -> Target {
+    pub(crate) fn from_item(item: &hir::Item) -> Target {
         match item.node {
+            hir::ItemKind::ExternCrate(..) => Target::ExternCrate,
+            hir::ItemKind::Use(..) => Target::Use,
+            hir::ItemKind::Static(..) => Target::Static,
+            hir::ItemKind::Const(..) => Target::Const,
             hir::ItemKind::Fn(..) => Target::Fn,
+            hir::ItemKind::Mod(..) => Target::Mod,
+            hir::ItemKind::ForeignMod(..) => Target::ForeignMod,
+            hir::ItemKind::GlobalAsm(..) => Target::GlobalAsm,
+            hir::ItemKind::Ty(..) => Target::Ty,
+            hir::ItemKind::Existential(..) => Target::Existential,
+            hir::ItemKind::Enum(..) => Target::Enum,
             hir::ItemKind::Struct(..) => Target::Struct,
             hir::ItemKind::Union(..) => Target::Union,
-            hir::ItemKind::Enum(..) => Target::Enum,
-            hir::ItemKind::Const(..) => Target::Const,
-            hir::ItemKind::ForeignMod(..) => Target::ForeignMod,
-            hir::ItemKind::Static(..) => Target::Static,
             hir::ItemKind::Trait(..) => Target::Trait,
-            _ => Target::Other,
+            hir::ItemKind::TraitAlias(..) => Target::TraitAlias,
+            hir::ItemKind::Impl(..) => Target::Impl,
         }
     }
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 73093580910..4d51126621d 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -3953,6 +3953,7 @@ impl<'a> LoweringContext<'a> {
                             constraint: out.constraint.clone(),
                             is_rw: out.is_rw,
                             is_indirect: out.is_indirect,
+                            span: out.expr.span,
                         })
                         .collect(),
                     asm: asm.asm.clone(),
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index c57c26434e3..1a97c678ef1 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1812,6 +1812,7 @@ pub struct InlineAsmOutput {
     pub constraint: Symbol,
     pub is_rw: bool,
     pub is_indirect: bool,
+    pub span: Span,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index da9604702df..9f4ac77fa1f 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -983,7 +983,8 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::BodyId {
 impl_stable_hash_for!(struct hir::InlineAsmOutput {
     constraint,
     is_rw,
-    is_indirect
+    is_indirect,
+    span
 });
 
 impl_stable_hash_for!(struct hir::GlobalAsm {
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index e83b514c691..f51a3e71d07 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -391,10 +391,39 @@ for ::mir::interpret::ConstValue<'gcx> {
     }
 }
 
-impl_stable_hash_for!(struct mir::interpret::Pointer {
-    alloc_id,
-    offset
-});
+impl<'a, Tag> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::Pointer<Tag>
+where Tag: HashStable<StableHashingContext<'a>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        let ::mir::interpret::Pointer { alloc_id, offset, tag } = self;
+        alloc_id.hash_stable(hcx, hasher);
+        offset.hash_stable(hcx, hasher);
+        tag.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, Tag> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::Scalar<Tag>
+where Tag: HashStable<StableHashingContext<'a>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        use mir::interpret::Scalar::*;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            Bits { bits, size } => {
+                bits.hash_stable(hcx, hasher);
+                size.hash_stable(hcx, hasher);
+            },
+            Ptr(ptr) => ptr.hash_stable(hcx, hasher),
+        }
+    }
+}
 
 impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
     fn hash_stable<W: StableHasherResult>(
@@ -449,25 +478,6 @@ impl_stable_hash_for!(enum ::syntax::ast::Mutability {
     Mutable
 });
 
-
-impl<'a> HashStable<StableHashingContext<'a>>
-for ::mir::interpret::Scalar {
-    fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'a>,
-                                          hasher: &mut StableHasher<W>) {
-        use mir::interpret::Scalar::*;
-
-        mem::discriminant(self).hash_stable(hcx, hasher);
-        match *self {
-            Bits { bits, size } => {
-                bits.hash_stable(hcx, hasher);
-                size.hash_stable(hcx, hasher);
-            },
-            Ptr(ptr) => ptr.hash_stable(hcx, hasher),
-        }
-    }
-}
-
 impl_stable_hash_for!(struct ty::Const<'tcx> {
     ty,
     val
@@ -1360,7 +1370,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
-        use traits::Goal::*;
+        use traits::GoalKind::*;
 
         mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 87d33e473e7..950754a07ab 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -18,11 +18,10 @@ use lint::context::CheckLintNameResult;
 use lint::{self, Lint, LintId, Level, LintSource};
 use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
                                            StableHasher, StableHasherResult};
-use session::{config::nightly_options, Session};
+use session::Session;
 use syntax::ast;
 use syntax::attr;
 use syntax::source_map::MultiSpan;
-use syntax::feature_gate;
 use syntax::symbol::Symbol;
 use util::nodemap::FxHashMap;
 
@@ -228,18 +227,7 @@ impl<'a> LintLevelsBuilder<'a> {
                     }
                 };
                 let tool_name = if let Some(lint_tool) = word.is_scoped() {
-                    let gate_feature = !self.sess.features_untracked().tool_lints;
-                    let known_tool = attr::is_known_lint_tool(lint_tool);
-                    if gate_feature {
-                        feature_gate::emit_feature_err(
-                            &sess.parse_sess,
-                            "tool_lints",
-                            word.span,
-                            feature_gate::GateIssue::Language,
-                            &format!("scoped lint `{}` is experimental", word.ident),
-                        );
-                    }
-                    if !known_tool {
+                    if !attr::is_known_lint_tool(lint_tool) {
                         span_err!(
                             sess,
                             lint_tool.span,
@@ -247,9 +235,6 @@ impl<'a> LintLevelsBuilder<'a> {
                             "an unknown tool name found in scoped lint: `{}`",
                             word.ident
                         );
-                    }
-
-                    if gate_feature || !known_tool {
                         continue;
                     }
 
@@ -299,13 +284,7 @@ impl<'a> LintLevelsBuilder<'a> {
                                     "change it to",
                                     new_lint_name.to_string(),
                                     Applicability::MachineApplicable,
-                                );
-
-                                if nightly_options::is_nightly_build() {
-                                    err.emit();
-                                } else {
-                                    err.cancel();
-                                }
+                                ).emit();
 
                                 let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span);
                                 for id in ids {
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 759ac1a7952..897e9cc2a38 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -63,6 +63,16 @@ macro_rules! span_bug {
 }
 
 #[macro_export]
+macro_rules! static_assert {
+    ($name:ident: $test:expr) => {
+        // Use the bool to access an array such that if the bool is false, the access
+        // is out-of-bounds.
+        #[allow(dead_code)]
+        static $name: () = [()][!$test as usize];
+    }
+}
+
+#[macro_export]
 macro_rules! __impl_stable_hash_field {
     ($field:ident, $ctx:expr, $hasher:expr) => ($field.hash_stable($ctx, $hasher));
     ($field:ident, $ctx:expr, $hasher:expr, _) => ({ let _ = $field; });
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index d6b43ffe6da..7e9b26bbf72 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -364,11 +364,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn mutate_expr(&mut self,
+                   span: Span,
                    assignment_expr: &hir::Expr,
                    expr: &hir::Expr,
                    mode: MutateMode) {
         let cmt = return_if_err!(self.mc.cat_expr(expr));
-        self.delegate.mutate(assignment_expr.id, assignment_expr.span, &cmt, mode);
+        self.delegate.mutate(assignment_expr.id, span, &cmt, mode);
         self.walk_expr(expr);
     }
 
@@ -472,12 +473,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                     if o.is_indirect {
                         self.consume_expr(output);
                     } else {
-                        self.mutate_expr(expr, output,
-                                         if o.is_rw {
-                                             MutateMode::WriteAndRead
-                                         } else {
-                                             MutateMode::JustWrite
-                                         });
+                        self.mutate_expr(
+                            output.span,
+                            expr,
+                            output,
+                            if o.is_rw {
+                                MutateMode::WriteAndRead
+                            } else {
+                                MutateMode::JustWrite
+                            },
+                        );
                     }
                 }
                 self.consume_exprs(inputs);
@@ -515,7 +520,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             }
 
             hir::ExprKind::Assign(ref lhs, ref rhs) => {
-                self.mutate_expr(expr, &lhs, MutateMode::JustWrite);
+                self.mutate_expr(expr.span, expr, &lhs, MutateMode::JustWrite);
                 self.consume_expr(&rhs);
             }
 
@@ -527,7 +532,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 if self.mc.tables.is_method_call(expr) {
                     self.consume_expr(lhs);
                 } else {
-                    self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead);
+                    self.mutate_expr(expr.span, expr, &lhs, MutateMode::WriteAndRead);
                 }
                 self.consume_expr(&rhs);
             }
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 0bd816b3e55..c5d028c1735 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -22,6 +22,7 @@
 pub use self::LangItem::*;
 
 use hir::def_id::DefId;
+use hir::check_attr::Target;
 use ty::{self, TyCtxt};
 use middle::weak_lang_items;
 use util::nodemap::FxHashMap;
@@ -36,7 +37,7 @@ use hir;
 // So you probably just want to nip down to the end.
 macro_rules! language_item_table {
     (
-        $( $variant:ident, $name:expr, $method:ident; )*
+        $( $variant:ident, $name:expr, $method:ident, $target:path; )*
     ) => {
 
 enum_from_u32! {
@@ -96,26 +97,49 @@ impl LanguageItems {
 
 struct LanguageItemCollector<'a, 'tcx: 'a> {
     items: LanguageItems,
-
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
-    item_refs: FxHashMap<&'static str, usize>,
+    item_refs: FxHashMap<&'static str, (usize, Target)>,
 }
 
 impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if let Some((value, span)) = extract(&item.attrs) {
-            let item_index = self.item_refs.get(&*value.as_str()).cloned();
-
-            if let Some(item_index) = item_index {
-                let def_id = self.tcx.hir.local_def_id(item.id);
-                self.collect_item(item_index, def_id);
-            } else {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0522,
-                                               "definition of an unknown language item: `{}`",
-                                               value);
-                err.span_label(span, format!("definition of unknown language item `{}`", value));
-                err.emit();
+            let actual_target = Target::from_item(item);
+            match self.item_refs.get(&*value.as_str()).cloned() {
+                // Known lang item with attribute on correct target.
+                Some((item_index, expected_target)) if actual_target == expected_target => {
+                    let def_id = self.tcx.hir.local_def_id(item.id);
+                    self.collect_item(item_index, def_id);
+                },
+                // Known lang item with attribute on incorrect target.
+                Some((_, expected_target)) => {
+                    let mut err = struct_span_err!(
+                        self.tcx.sess, span, E0718,
+                        "`{}` language item must be applied to a {}",
+                        value, expected_target,
+                    );
+                    err.span_label(
+                        span,
+                        format!(
+                            "attribute should be applied to a {}, not a {}",
+                            expected_target, actual_target,
+                        ),
+                    );
+                    err.emit();
+                },
+                // Unknown lang item.
+                _ => {
+                    let mut err = struct_span_err!(
+                        self.tcx.sess, span, E0522,
+                        "definition of an unknown language item: `{}`",
+                        value
+                    );
+                    err.span_label(
+                        span,
+                        format!("definition of unknown language item `{}`", value)
+                    );
+                    err.emit();
+                },
             }
         }
     }
@@ -133,7 +157,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItemCollector<'a, 'tcx> {
         let mut item_refs = FxHashMap();
 
-        $( item_refs.insert($name, $variant as usize); )*
+        $( item_refs.insert($name, ($variant as usize, $target)); )*
 
         LanguageItemCollector {
             tcx,
@@ -210,84 +234,84 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
 }
 
 language_item_table! {
-//  Variant name,                    Name,                      Method name;
-    CharImplItem,                    "char",                    char_impl;
-    StrImplItem,                     "str",                     str_impl;
-    SliceImplItem,                   "slice",                   slice_impl;
-    SliceU8ImplItem,                 "slice_u8",                slice_u8_impl;
-    StrAllocImplItem,                "str_alloc",               str_alloc_impl;
-    SliceAllocImplItem,              "slice_alloc",             slice_alloc_impl;
-    SliceU8AllocImplItem,            "slice_u8_alloc",          slice_u8_alloc_impl;
-    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
-    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
-    I8ImplItem,                      "i8",                      i8_impl;
-    I16ImplItem,                     "i16",                     i16_impl;
-    I32ImplItem,                     "i32",                     i32_impl;
-    I64ImplItem,                     "i64",                     i64_impl;
-    I128ImplItem,                     "i128",                   i128_impl;
-    IsizeImplItem,                   "isize",                   isize_impl;
-    U8ImplItem,                      "u8",                      u8_impl;
-    U16ImplItem,                     "u16",                     u16_impl;
-    U32ImplItem,                     "u32",                     u32_impl;
-    U64ImplItem,                     "u64",                     u64_impl;
-    U128ImplItem,                    "u128",                    u128_impl;
-    UsizeImplItem,                   "usize",                   usize_impl;
-    F32ImplItem,                     "f32",                     f32_impl;
-    F64ImplItem,                     "f64",                     f64_impl;
-    F32RuntimeImplItem,              "f32_runtime",             f32_runtime_impl;
-    F64RuntimeImplItem,              "f64_runtime",             f64_runtime_impl;
-
-    SizedTraitLangItem,              "sized",                   sized_trait;
-    UnsizeTraitLangItem,             "unsize",                  unsize_trait;
-    CopyTraitLangItem,               "copy",                    copy_trait;
-    CloneTraitLangItem,              "clone",                   clone_trait;
-    SyncTraitLangItem,               "sync",                    sync_trait;
-    FreezeTraitLangItem,             "freeze",                  freeze_trait;
-
-    DropTraitLangItem,               "drop",                    drop_trait;
-
-    CoerceUnsizedTraitLangItem,      "coerce_unsized",          coerce_unsized_trait;
-
-    AddTraitLangItem,                "add",                     add_trait;
-    SubTraitLangItem,                "sub",                     sub_trait;
-    MulTraitLangItem,                "mul",                     mul_trait;
-    DivTraitLangItem,                "div",                     div_trait;
-    RemTraitLangItem,                "rem",                     rem_trait;
-    NegTraitLangItem,                "neg",                     neg_trait;
-    NotTraitLangItem,                "not",                     not_trait;
-    BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
-    BitAndTraitLangItem,             "bitand",                  bitand_trait;
-    BitOrTraitLangItem,              "bitor",                   bitor_trait;
-    ShlTraitLangItem,                "shl",                     shl_trait;
-    ShrTraitLangItem,                "shr",                     shr_trait;
-    AddAssignTraitLangItem,          "add_assign",              add_assign_trait;
-    SubAssignTraitLangItem,          "sub_assign",              sub_assign_trait;
-    MulAssignTraitLangItem,          "mul_assign",              mul_assign_trait;
-    DivAssignTraitLangItem,          "div_assign",              div_assign_trait;
-    RemAssignTraitLangItem,          "rem_assign",              rem_assign_trait;
-    BitXorAssignTraitLangItem,       "bitxor_assign",           bitxor_assign_trait;
-    BitAndAssignTraitLangItem,       "bitand_assign",           bitand_assign_trait;
-    BitOrAssignTraitLangItem,        "bitor_assign",            bitor_assign_trait;
-    ShlAssignTraitLangItem,          "shl_assign",              shl_assign_trait;
-    ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
-    IndexTraitLangItem,              "index",                   index_trait;
-    IndexMutTraitLangItem,           "index_mut",               index_mut_trait;
-
-    UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;
-
-    DerefTraitLangItem,              "deref",                   deref_trait;
-    DerefMutTraitLangItem,           "deref_mut",               deref_mut_trait;
-
-    FnTraitLangItem,                 "fn",                      fn_trait;
-    FnMutTraitLangItem,              "fn_mut",                  fn_mut_trait;
-    FnOnceTraitLangItem,             "fn_once",                 fn_once_trait;
-
-    GeneratorStateLangItem,          "generator_state",         gen_state;
-    GeneratorTraitLangItem,          "generator",               gen_trait;
-
-    EqTraitLangItem,                 "eq",                      eq_trait;
-    PartialOrdTraitLangItem,         "partial_ord",             partial_ord_trait;
-    OrdTraitLangItem,                "ord",                     ord_trait;
+//  Variant name,                Name,                 Method name,             Target;
+    CharImplItem,                "char",               char_impl,               Target::Impl;
+    StrImplItem,                 "str",                str_impl,                Target::Impl;
+    SliceImplItem,               "slice",              slice_impl,              Target::Impl;
+    SliceU8ImplItem,             "slice_u8",           slice_u8_impl,           Target::Impl;
+    StrAllocImplItem,            "str_alloc",          str_alloc_impl,          Target::Impl;
+    SliceAllocImplItem,          "slice_alloc",        slice_alloc_impl,        Target::Impl;
+    SliceU8AllocImplItem,        "slice_u8_alloc",     slice_u8_alloc_impl,     Target::Impl;
+    ConstPtrImplItem,            "const_ptr",          const_ptr_impl,          Target::Impl;
+    MutPtrImplItem,              "mut_ptr",            mut_ptr_impl,            Target::Impl;
+    I8ImplItem,                  "i8",                 i8_impl,                 Target::Impl;
+    I16ImplItem,                 "i16",                i16_impl,                Target::Impl;
+    I32ImplItem,                 "i32",                i32_impl,                Target::Impl;
+    I64ImplItem,                 "i64",                i64_impl,                Target::Impl;
+    I128ImplItem,                "i128",               i128_impl,               Target::Impl;
+    IsizeImplItem,               "isize",              isize_impl,              Target::Impl;
+    U8ImplItem,                  "u8",                 u8_impl,                 Target::Impl;
+    U16ImplItem,                 "u16",                u16_impl,                Target::Impl;
+    U32ImplItem,                 "u32",                u32_impl,                Target::Impl;
+    U64ImplItem,                 "u64",                u64_impl,                Target::Impl;
+    U128ImplItem,                "u128",               u128_impl,               Target::Impl;
+    UsizeImplItem,               "usize",              usize_impl,              Target::Impl;
+    F32ImplItem,                 "f32",                f32_impl,                Target::Impl;
+    F64ImplItem,                 "f64",                f64_impl,                Target::Impl;
+    F32RuntimeImplItem,          "f32_runtime",        f32_runtime_impl,        Target::Impl;
+    F64RuntimeImplItem,          "f64_runtime",        f64_runtime_impl,        Target::Impl;
+
+    SizedTraitLangItem,          "sized",              sized_trait,             Target::Trait;
+    UnsizeTraitLangItem,         "unsize",             unsize_trait,            Target::Trait;
+    CopyTraitLangItem,           "copy",               copy_trait,              Target::Trait;
+    CloneTraitLangItem,          "clone",              clone_trait,             Target::Trait;
+    SyncTraitLangItem,           "sync",               sync_trait,              Target::Trait;
+    FreezeTraitLangItem,         "freeze",             freeze_trait,            Target::Trait;
+
+    DropTraitLangItem,           "drop",               drop_trait,              Target::Trait;
+
+    CoerceUnsizedTraitLangItem,  "coerce_unsized",     coerce_unsized_trait,    Target::Trait;
+
+    AddTraitLangItem,            "add",                add_trait,               Target::Trait;
+    SubTraitLangItem,            "sub",                sub_trait,               Target::Trait;
+    MulTraitLangItem,            "mul",                mul_trait,               Target::Trait;
+    DivTraitLangItem,            "div",                div_trait,               Target::Trait;
+    RemTraitLangItem,            "rem",                rem_trait,               Target::Trait;
+    NegTraitLangItem,            "neg",                neg_trait,               Target::Trait;
+    NotTraitLangItem,            "not",                not_trait,               Target::Trait;
+    BitXorTraitLangItem,         "bitxor",             bitxor_trait,            Target::Trait;
+    BitAndTraitLangItem,         "bitand",             bitand_trait,            Target::Trait;
+    BitOrTraitLangItem,          "bitor",              bitor_trait,             Target::Trait;
+    ShlTraitLangItem,            "shl",                shl_trait,               Target::Trait;
+    ShrTraitLangItem,            "shr",                shr_trait,               Target::Trait;
+    AddAssignTraitLangItem,      "add_assign",         add_assign_trait,        Target::Trait;
+    SubAssignTraitLangItem,      "sub_assign",         sub_assign_trait,        Target::Trait;
+    MulAssignTraitLangItem,      "mul_assign",         mul_assign_trait,        Target::Trait;
+    DivAssignTraitLangItem,      "div_assign",         div_assign_trait,        Target::Trait;
+    RemAssignTraitLangItem,      "rem_assign",         rem_assign_trait,        Target::Trait;
+    BitXorAssignTraitLangItem,   "bitxor_assign",      bitxor_assign_trait,     Target::Trait;
+    BitAndAssignTraitLangItem,   "bitand_assign",      bitand_assign_trait,     Target::Trait;
+    BitOrAssignTraitLangItem,    "bitor_assign",       bitor_assign_trait,      Target::Trait;
+    ShlAssignTraitLangItem,      "shl_assign",         shl_assign_trait,        Target::Trait;
+    ShrAssignTraitLangItem,      "shr_assign",         shr_assign_trait,        Target::Trait;
+    IndexTraitLangItem,          "index",              index_trait,             Target::Trait;
+    IndexMutTraitLangItem,       "index_mut",          index_mut_trait,         Target::Trait;
+
+    UnsafeCellTypeLangItem,      "unsafe_cell",        unsafe_cell_type,        Target::Struct;
+
+    DerefTraitLangItem,          "deref",              deref_trait,             Target::Trait;
+    DerefMutTraitLangItem,       "deref_mut",          deref_mut_trait,         Target::Trait;
+
+    FnTraitLangItem,             "fn",                 fn_trait,                Target::Trait;
+    FnMutTraitLangItem,          "fn_mut",             fn_mut_trait,            Target::Trait;
+    FnOnceTraitLangItem,         "fn_once",            fn_once_trait,           Target::Trait;
+
+    GeneratorStateLangItem,      "generator_state",    gen_state,               Target::Enum;
+    GeneratorTraitLangItem,      "generator",          gen_trait,               Target::Trait;
+
+    EqTraitLangItem,             "eq",                 eq_trait,                Target::Trait;
+    PartialOrdTraitLangItem,     "partial_ord",        partial_ord_trait,       Target::Trait;
+    OrdTraitLangItem,            "ord",                ord_trait,               Target::Trait;
 
     // A number of panic-related lang items. The `panic` item corresponds to
     // divide-by-zero and various panic cases with `match`. The
@@ -298,68 +322,68 @@ language_item_table! {
     // defined to use it, but a final product is required to define it
     // somewhere. Additionally, there are restrictions on crates that use a weak
     // lang item, but do not have it defined.
-    PanicFnLangItem,                 "panic",                   panic_fn;
-    PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
-    PanicInfoLangItem,               "panic_info",              panic_info;
-    PanicImplLangItem,               "panic_impl",              panic_impl;
+    PanicFnLangItem,             "panic",              panic_fn,                Target::Fn;
+    PanicBoundsCheckFnLangItem,  "panic_bounds_check", panic_bounds_check_fn,   Target::Fn;
+    PanicInfoLangItem,           "panic_info",         panic_info,              Target::Struct;
+    PanicImplLangItem,           "panic_impl",         panic_impl,              Target::Fn;
     // Libstd panic entry point. Necessary for const eval to be able to catch it
-    BeginPanicFnLangItem,            "begin_panic",             begin_panic_fn;
+    BeginPanicFnLangItem,        "begin_panic",        begin_panic_fn,          Target::Fn;
 
-    ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
-    BoxFreeFnLangItem,               "box_free",                box_free_fn;
-    DropInPlaceFnLangItem,           "drop_in_place",           drop_in_place_fn;
-    OomLangItem,                     "oom",                     oom;
-    AllocLayoutLangItem,             "alloc_layout",            alloc_layout;
+    ExchangeMallocFnLangItem,    "exchange_malloc",    exchange_malloc_fn,      Target::Fn;
+    BoxFreeFnLangItem,           "box_free",           box_free_fn,             Target::Fn;
+    DropInPlaceFnLangItem,       "drop_in_place",      drop_in_place_fn,        Target::Fn;
+    OomLangItem,                 "oom",                oom,                     Target::Fn;
+    AllocLayoutLangItem,         "alloc_layout",       alloc_layout,            Target::Struct;
 
-    StartFnLangItem,                 "start",                   start_fn;
+    StartFnLangItem,             "start",              start_fn,                Target::Fn;
 
-    EhPersonalityLangItem,           "eh_personality",          eh_personality;
-    EhUnwindResumeLangItem,          "eh_unwind_resume",        eh_unwind_resume;
-    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;
+    EhPersonalityLangItem,       "eh_personality",     eh_personality,          Target::Fn;
+    EhUnwindResumeLangItem,      "eh_unwind_resume",   eh_unwind_resume,        Target::Fn;
+    MSVCTryFilterLangItem,       "msvc_try_filter",    msvc_try_filter,         Target::Static;
 
-    OwnedBoxLangItem,                "owned_box",               owned_box;
+    OwnedBoxLangItem,            "owned_box",          owned_box,               Target::Struct;
 
-    PhantomDataItem,                 "phantom_data",            phantom_data;
+    PhantomDataItem,             "phantom_data",       phantom_data,            Target::Struct;
 
-    ManuallyDropItem,                "manually_drop",           manually_drop;
+    ManuallyDropItem,            "manually_drop",      manually_drop,           Target::Struct;
 
-    DebugTraitLangItem,              "debug_trait",             debug_trait;
+    DebugTraitLangItem,          "debug_trait",        debug_trait,             Target::Trait;
 
     // A lang item for each of the 128-bit operators we can optionally lower.
-    I128AddFnLangItem,               "i128_add",                i128_add_fn;
-    U128AddFnLangItem,               "u128_add",                u128_add_fn;
-    I128SubFnLangItem,               "i128_sub",                i128_sub_fn;
-    U128SubFnLangItem,               "u128_sub",                u128_sub_fn;
-    I128MulFnLangItem,               "i128_mul",                i128_mul_fn;
-    U128MulFnLangItem,               "u128_mul",                u128_mul_fn;
-    I128DivFnLangItem,               "i128_div",                i128_div_fn;
-    U128DivFnLangItem,               "u128_div",                u128_div_fn;
-    I128RemFnLangItem,               "i128_rem",                i128_rem_fn;
-    U128RemFnLangItem,               "u128_rem",                u128_rem_fn;
-    I128ShlFnLangItem,               "i128_shl",                i128_shl_fn;
-    U128ShlFnLangItem,               "u128_shl",                u128_shl_fn;
-    I128ShrFnLangItem,               "i128_shr",                i128_shr_fn;
-    U128ShrFnLangItem,               "u128_shr",                u128_shr_fn;
+    I128AddFnLangItem,           "i128_add",           i128_add_fn,             Target::Fn;
+    U128AddFnLangItem,           "u128_add",           u128_add_fn,             Target::Fn;
+    I128SubFnLangItem,           "i128_sub",           i128_sub_fn,             Target::Fn;
+    U128SubFnLangItem,           "u128_sub",           u128_sub_fn,             Target::Fn;
+    I128MulFnLangItem,           "i128_mul",           i128_mul_fn,             Target::Fn;
+    U128MulFnLangItem,           "u128_mul",           u128_mul_fn,             Target::Fn;
+    I128DivFnLangItem,           "i128_div",           i128_div_fn,             Target::Fn;
+    U128DivFnLangItem,           "u128_div",           u128_div_fn,             Target::Fn;
+    I128RemFnLangItem,           "i128_rem",           i128_rem_fn,             Target::Fn;
+    U128RemFnLangItem,           "u128_rem",           u128_rem_fn,             Target::Fn;
+    I128ShlFnLangItem,           "i128_shl",           i128_shl_fn,             Target::Fn;
+    U128ShlFnLangItem,           "u128_shl",           u128_shl_fn,             Target::Fn;
+    I128ShrFnLangItem,           "i128_shr",           i128_shr_fn,             Target::Fn;
+    U128ShrFnLangItem,           "u128_shr",           u128_shr_fn,             Target::Fn;
     // And overflow versions for the operators that are checkable.
     // While MIR calls these Checked*, they return (T,bool), not Option<T>.
-    I128AddoFnLangItem,              "i128_addo",               i128_addo_fn;
-    U128AddoFnLangItem,              "u128_addo",               u128_addo_fn;
-    I128SuboFnLangItem,              "i128_subo",               i128_subo_fn;
-    U128SuboFnLangItem,              "u128_subo",               u128_subo_fn;
-    I128MuloFnLangItem,              "i128_mulo",               i128_mulo_fn;
-    U128MuloFnLangItem,              "u128_mulo",               u128_mulo_fn;
-    I128ShloFnLangItem,              "i128_shlo",               i128_shlo_fn;
-    U128ShloFnLangItem,              "u128_shlo",               u128_shlo_fn;
-    I128ShroFnLangItem,              "i128_shro",               i128_shro_fn;
-    U128ShroFnLangItem,              "u128_shro",               u128_shro_fn;
+    I128AddoFnLangItem,          "i128_addo",          i128_addo_fn,            Target::Fn;
+    U128AddoFnLangItem,          "u128_addo",          u128_addo_fn,            Target::Fn;
+    I128SuboFnLangItem,          "i128_subo",          i128_subo_fn,            Target::Fn;
+    U128SuboFnLangItem,          "u128_subo",          u128_subo_fn,            Target::Fn;
+    I128MuloFnLangItem,          "i128_mulo",          i128_mulo_fn,            Target::Fn;
+    U128MuloFnLangItem,          "u128_mulo",          u128_mulo_fn,            Target::Fn;
+    I128ShloFnLangItem,          "i128_shlo",          i128_shlo_fn,            Target::Fn;
+    U128ShloFnLangItem,          "u128_shlo",          u128_shlo_fn,            Target::Fn;
+    I128ShroFnLangItem,          "i128_shro",          i128_shro_fn,            Target::Fn;
+    U128ShroFnLangItem,          "u128_shro",          u128_shro_fn,            Target::Fn;
 
     // Align offset for stride != 1, must not panic.
-    AlignOffsetLangItem,             "align_offset",            align_offset_fn;
+    AlignOffsetLangItem,         "align_offset",       align_offset_fn,         Target::Fn;
 
-    TerminationTraitLangItem,        "termination",             termination;
+    TerminationTraitLangItem,    "termination",        termination,             Target::Trait;
 
-    Arc,                             "arc",                     arc;
-    Rc,                              "rc",                      rc;
+    Arc,                         "arc",                arc,                     Target::Struct;
+    Rc,                          "rc",                 rc,                      Target::Struct;
 }
 
 impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index edb571da7db..a90f03f536a 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -167,8 +167,7 @@ newtype_index! {
 impl_stable_hash_for!(struct ::middle::region::FirstStatementIndex { private });
 
 // compilation error if size of `ScopeData` is not the same as a `u32`
-#[allow(dead_code)]
-static ASSERT: () = [()][!(mem::size_of::<ScopeData>() == 4) as usize];
+static_assert!(ASSERT_SCOPE_DATA: mem::size_of::<ScopeData>() == 4);
 
 impl Scope {
     /// Returns a item-local id associated with this scope.
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index e9d0b041339..5eee0fba5fb 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -138,54 +138,82 @@ impl<T: layout::HasDataLayout> PointerArithmetic for T {}
 /// each context.
 ///
 /// Defaults to the index based and loosely coupled AllocId.
+///
+/// Pointer is also generic over the `Tag` associated with each pointer,
+/// which is used to do provenance tracking during execution.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub struct Pointer<Id=AllocId> {
+pub struct Pointer<Tag=(),Id=AllocId> {
     pub alloc_id: Id,
     pub offset: Size,
+    pub tag: Tag,
 }
 
 /// Produces a `Pointer` which points to the beginning of the Allocation
 impl From<AllocId> for Pointer {
+    #[inline(always)]
     fn from(alloc_id: AllocId) -> Self {
         Pointer::new(alloc_id, Size::ZERO)
     }
 }
 
-impl<'tcx> Pointer {
+impl<'tcx> Pointer<()> {
+    #[inline(always)]
     pub fn new(alloc_id: AllocId, offset: Size) -> Self {
-        Pointer { alloc_id, offset }
+        Pointer { alloc_id, offset, tag: () }
+    }
+
+    #[inline(always)]
+    pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
+        where Tag: Default
+    {
+        Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
+    }
+}
+
+impl<'tcx, Tag> Pointer<Tag> {
+    #[inline(always)]
+    pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
+        Pointer { alloc_id, offset, tag }
     }
 
     pub fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
-        Pointer::new(
+        Pointer::new_with_tag(
             self.alloc_id,
             Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
+            self.tag,
         )
     }
 
     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.bytes(), i);
-        (Pointer::new(self.alloc_id, Size::from_bytes(res)), over)
+        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
     }
 
     pub fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
-        Ok(Pointer::new(
+        Ok(Pointer::new_with_tag(
             self.alloc_id,
             Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
+            self.tag,
         ))
     }
 
     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());
-        (Pointer::new(self.alloc_id, Size::from_bytes(res)), over)
+        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
     }
 
     pub fn offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
-        Ok(Pointer::new(
+        Ok(Pointer::new_with_tag(
             self.alloc_id,
             Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
+            self.tag
         ))
     }
+
+    #[inline]
+    pub fn erase_tag(self) -> Pointer {
+        Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
+    }
 }
 
 
@@ -496,15 +524,15 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> {
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub struct Allocation {
+pub struct Allocation<Tag=()> {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer
     pub bytes: Vec<u8>,
-    /// Maps from byte addresses to allocations.
+    /// Maps from byte addresses to extra data for each pointer.
     /// Only the first byte of a pointer is inserted into the map; i.e.,
     /// every entry in this map applies to `pointer_size` consecutive bytes starting
     /// at the given offset.
-    pub relocations: Relocations,
+    pub relocations: Relocations<Tag>,
     /// Denotes undefined memory. Reading from undefined memory is forbidden in miri
     pub undef_mask: UndefMask,
     /// The alignment of the allocation to detect unaligned reads.
@@ -515,7 +543,7 @@ pub struct Allocation {
     pub mutability: Mutability,
 }
 
-impl Allocation {
+impl<Tag> Allocation<Tag> {
     /// Creates a read-only allocation initialized by the given bytes
     pub fn from_bytes(slice: &[u8], align: Align) -> Self {
         let mut undef_mask = UndefMask::new(Size::ZERO);
@@ -548,29 +576,29 @@ impl Allocation {
 impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct Relocations<Id=AllocId>(SortedMap<Size, Id>);
+pub struct Relocations<Tag=(), Id=AllocId>(SortedMap<Size, (Tag, Id)>);
 
-impl<Id> Relocations<Id> {
+impl<Tag, Id> Relocations<Tag, Id> {
     pub fn new() -> Self {
         Relocations(SortedMap::new())
     }
 
     // The caller must guarantee that the given relocations are already sorted
     // by address and contain no duplicates.
-    pub fn from_presorted(r: Vec<(Size, Id)>) -> Self {
+    pub fn from_presorted(r: Vec<(Size, (Tag, Id))>) -> Self {
         Relocations(SortedMap::from_presorted_elements(r))
     }
 }
 
-impl Deref for Relocations {
-    type Target = SortedMap<Size, AllocId>;
+impl<Tag> Deref for Relocations<Tag> {
+    type Target = SortedMap<Size, (Tag, AllocId)>;
 
     fn deref(&self) -> &Self::Target {
         &self.0
     }
 }
 
-impl DerefMut for Relocations {
+impl<Tag> DerefMut for Relocations<Tag> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.0
     }
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index c81d55e69b6..9e54b146fd0 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -79,7 +79,47 @@ impl<'tcx> ConstValue<'tcx> {
     }
 }
 
-impl<'tcx> Scalar {
+/// A `Scalar` represents an immediate, primitive value existing outside of a
+/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
+/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
+/// of a simple value or a pointer into another `Allocation`
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+pub enum Scalar<Tag=(), Id=AllocId> {
+    /// The raw bytes of a simple value.
+    Bits {
+        /// The first `size` bytes are the value.
+        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
+        size: u8,
+        bits: u128,
+    },
+
+    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
+    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
+    /// relocation and its associated offset together as a `Pointer` here.
+    Ptr(Pointer<Tag, Id>),
+}
+
+impl<'tcx> Scalar<()> {
+    #[inline]
+    pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
+        where Tag: Default
+    {
+        match self {
+            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
+            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
+        }
+    }
+}
+
+impl<'tcx, Tag> Scalar<Tag> {
+    #[inline]
+    pub fn erase_tag(self) -> Scalar {
+        match self {
+            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
+            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
+        }
+    }
+
     #[inline]
     pub fn ptr_null(cx: impl HasDataLayout) -> Self {
         Scalar::Bits {
@@ -208,7 +248,7 @@ impl<'tcx> Scalar {
     }
 
     #[inline]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
         match self {
             Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
             Scalar::Bits { .. } => err!(ReadBytesAsPointer),
@@ -317,29 +357,9 @@ impl<'tcx> Scalar {
     }
 }
 
-impl From<Pointer> for Scalar {
+impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
     #[inline(always)]
-    fn from(ptr: Pointer) -> Self {
+    fn from(ptr: Pointer<Tag>) -> Self {
         Scalar::Ptr(ptr)
     }
 }
-
-/// A `Scalar` represents an immediate, primitive value existing outside of a
-/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
-/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
-/// of a simple value or a pointer into another `Allocation`
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum Scalar<Id=AllocId> {
-    /// The raw bytes of a simple value.
-    Bits {
-        /// The first `size` bytes are the value.
-        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
-        size: u8,
-        bits: u128,
-    },
-
-    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
-    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
-    /// relocation and its associated offset together as a `Pointer` here.
-    Ptr(Pointer<Id>),
-}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index ea4eb761964..2587e19b1cb 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> {
     /// e.g. via `let x: T`, then we carry that type here. The MIR
     /// borrow checker needs this information since it can affect
     /// region inference.
-    pub user_ty: Option<CanonicalTy<'tcx>>,
+    pub user_ty: Option<(CanonicalTy<'tcx>, Span)>,
 
     /// Name of the local, used in debuginfo and pretty-printing.
     ///
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index d2b0a6a37a7..920dc88d6a8 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -735,7 +735,7 @@ macro_rules! make_mir_visitor {
                     local,
                     source_info: *source_info,
                 });
-                if let Some(user_ty) = user_ty {
+                if let Some((user_ty, _)) = user_ty {
                     self.visit_user_ty(user_ty);
                 }
                 self.visit_source_info(source_info);
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index c532b5ee56f..d8c36f81da3 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1387,6 +1387,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "output a json file with profiler results"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
           "emits a section containing stack size metadata"),
+    plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
+          "whether to use the PLT when calling into shared libraries;
+          only has effect for PIC code on systems with ELF binaries
+          (default: PLT is disabled if full relro is enabled)"),
 }
 
 pub fn default_lib_output() -> CrateType {
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 3c209a43246..10a506da4ea 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -40,8 +40,7 @@ use syntax::parse::{self, ParseSess};
 use syntax_pos::{MultiSpan, Span};
 use util::profiling::SelfProfiler;
 
-use rustc_target::spec::PanicStrategy;
-use rustc_target::spec::{Target, TargetTriple};
+use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple};
 use rustc_data_structures::flock;
 use jobserver::Client;
 
@@ -984,6 +983,27 @@ impl Session {
     pub fn edition(&self) -> Edition {
         self.opts.edition
     }
+
+    /// True if we cannot skip the PLT for shared library calls.
+    pub fn needs_plt(&self) -> bool {
+        // Check if the current target usually needs PLT to be enabled.
+        // The user can use the command line flag to override it.
+        let needs_plt = self.target.target.options.needs_plt;
+
+        let dbg_opts = &self.opts.debugging_opts;
+
+        let relro_level = dbg_opts.relro_level
+            .unwrap_or(self.target.target.options.relro_level);
+
+        // Only enable this optimization by default if full relro is also enabled.
+        // In this case, lazy binding was already unavailable, so nothing is lost.
+        // This also ensures `-Wl,-z,now` is supported by the linker.
+        let full_relro = RelroLevel::Full == relro_level;
+
+        // If user didn't explicitly forced us to use / skip the PLT,
+        // then try to skip it where possible.
+        dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
+    }
 }
 
 pub fn build_session(
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 7add8ef05ee..817e9ffcbb5 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -418,9 +418,7 @@ fn fundamental_ty(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'_>) -> bool {
     match ty.sty {
         ty::Ref(..) => true,
         ty::Adt(def, _) => def.is_fundamental(),
-        ty::Dynamic(ref data, ..) => {
-            data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental"))
-        }
+        ty::Dynamic(ref data, ..) => tcx.has_attr(data.principal().def_id(), "fundamental"),
         _ => false
     }
 }
@@ -467,11 +465,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
         ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
         ty::Foreign(did) => def_id_is_local(did, in_crate),
 
-        ty::Dynamic(ref tt, ..) => {
-            tt.principal().map_or(false, |p|
-                def_id_is_local(p.def_id(), in_crate)
-            )
-        }
+        ty::Dynamic(ref tt, ..) => def_id_is_local(tt.principal().def_id(), in_crate),
 
         ty::Error => true,
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 286e35c5d4e..6e4abee32c0 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -318,31 +318,33 @@ pub enum QuantifierKind {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum Goal<'tcx> {
-    Implies(Clauses<'tcx>, &'tcx Goal<'tcx>),
-    And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>),
-    Not(&'tcx Goal<'tcx>),
+pub enum GoalKind<'tcx> {
+    Implies(Clauses<'tcx>, Goal<'tcx>),
+    And(Goal<'tcx>, Goal<'tcx>),
+    Not(Goal<'tcx>),
     DomainGoal(DomainGoal<'tcx>),
-    Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>),
+    Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
     CannotProve,
 }
 
+pub type Goal<'tcx> = &'tcx GoalKind<'tcx>;
+
 pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>;
 
 impl<'tcx> DomainGoal<'tcx> {
-    pub fn into_goal(self) -> Goal<'tcx> {
-        Goal::DomainGoal(self)
+    pub fn into_goal(self) -> GoalKind<'tcx> {
+        GoalKind::DomainGoal(self)
     }
 }
 
-impl<'tcx> Goal<'tcx> {
+impl<'tcx> GoalKind<'tcx> {
     pub fn from_poly_domain_goal<'a>(
         domain_goal: PolyDomainGoal<'tcx>,
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    ) -> Goal<'tcx> {
+    ) -> GoalKind<'tcx> {
         match domain_goal.no_late_bound_regions() {
             Some(p) => p.into_goal(),
-            None => Goal::Quantified(
+            None => GoalKind::Quantified(
                 QuantifierKind::Universal,
                 domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal()))
             ),
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 82d881e10b1..8e8024e51da 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -2088,10 +2088,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         return;
                     }
 
-                    match data.principal() {
-                        Some(p) => p.with_self_ty(this.tcx(), self_ty),
-                        None => return,
-                    }
+                    data.principal().with_self_ty(this.tcx(), self_ty)
                 }
                 ty::Infer(ty::TyVar(_)) => {
                     debug!("assemble_candidates_from_object_ty: ambiguous");
@@ -2183,15 +2180,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 //
                 // We always upcast when we can because of reason
                 // #2 (region bounds).
-                match (data_a.principal(), data_b.principal()) {
-                    (Some(a), Some(b)) => {
-                        a.def_id() == b.def_id()
-                            && data_b.auto_traits()
-                            // All of a's auto traits need to be in b's auto traits.
-                            .all(|b| data_a.auto_traits().any(|a| a == b))
-                    }
-                    _ => false,
-                }
+                data_a.principal().def_id() == data_b.principal().def_id()
+                    && data_b.auto_traits()
+                    // All of a's auto traits need to be in b's auto traits.
+                    .all(|b| data_a.auto_traits().any(|a| a == b))
             }
 
             // T -> Trait.
@@ -2981,7 +2973,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             .shallow_resolve(*obligation.self_ty().skip_binder());
         let poly_trait_ref = match self_ty.sty {
             ty::Dynamic(ref data, ..) => {
-                data.principal().unwrap().with_self_ty(self.tcx(), self_ty)
+                data.principal().with_self_ty(self.tcx(), self_ty)
             }
             _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
         };
@@ -3244,10 +3236,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
                 // See assemble_candidates_for_unsizing for more info.
                 let existential_predicates = data_a.map_bound(|data_a| {
-                    let principal = data_a.principal();
-                    let iter = principal
-                        .into_iter()
-                        .map(ty::ExistentialPredicate::Trait)
+                    let iter = iter::once(ty::ExistentialPredicate::Trait(data_a.principal()))
                         .chain(
                             data_a
                                 .projection_bounds()
@@ -3285,7 +3274,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             // T -> Trait.
             (_, &ty::Dynamic(ref data, r)) => {
                 let mut object_dids = data.auto_traits()
-                    .chain(data.principal().map(|p| p.def_id()));
+                    .chain(iter::once(data.principal().def_id()));
                 if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
                     return Err(TraitNotObjectSafe(did));
                 }
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 22e79fc2638..1524f89af29 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -469,7 +469,7 @@ impl fmt::Display for traits::QuantifierKind {
 
 impl<'tcx> fmt::Display for traits::Goal<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use traits::Goal::*;
+        use traits::GoalKind::*;
 
         match self {
             Implies(hypotheses, goal) => {
@@ -598,25 +598,25 @@ CloneTypeFoldableAndLiftImpls! {
 }
 
 EnumTypeFoldableImpl! {
-    impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
-        (traits::Goal::Implies)(hypotheses, goal),
-        (traits::Goal::And)(goal1, goal2),
-        (traits::Goal::Not)(goal),
-        (traits::Goal::DomainGoal)(domain_goal),
-        (traits::Goal::Quantified)(qkind, goal),
-        (traits::Goal::CannotProve),
+    impl<'tcx> TypeFoldable<'tcx> for traits::GoalKind<'tcx> {
+        (traits::GoalKind::Implies)(hypotheses, goal),
+        (traits::GoalKind::And)(goal1, goal2),
+        (traits::GoalKind::Not)(goal),
+        (traits::GoalKind::DomainGoal)(domain_goal),
+        (traits::GoalKind::Quantified)(qkind, goal),
+        (traits::GoalKind::CannotProve),
     }
 }
 
 EnumLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for traits::Goal<'a> {
-        type Lifted = traits::Goal<'tcx>;
-        (traits::Goal::Implies)(hypotheses, goal),
-        (traits::Goal::And)(goal1, goal2),
-        (traits::Goal::Not)(goal),
-        (traits::Goal::DomainGoal)(domain_goal),
-        (traits::Goal::Quantified)(kind, goal),
-        (traits::Goal::CannotProve),
+    impl<'a, 'tcx> Lift<'tcx> for traits::GoalKind<'a> {
+        type Lifted = traits::GoalKind<'tcx>;
+        (traits::GoalKind::Implies)(hypotheses, goal),
+        (traits::GoalKind::And)(goal1, goal2),
+        (traits::GoalKind::Not)(goal),
+        (traits::GoalKind::DomainGoal)(domain_goal),
+        (traits::GoalKind::Quantified)(kind, goal),
+        (traits::GoalKind::CannotProve),
     }
 }
 
@@ -633,7 +633,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx traits::Goal<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         let v = (**self).fold_with(folder);
         folder.tcx().mk_goal(v)
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 46ba5f5ef36..ab1df2d4c3b 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -36,7 +36,7 @@ use mir::interpret::Allocation;
 use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
 use ty::ReprOptions;
 use traits;
-use traits::{Clause, Clauses, Goal, Goals};
+use traits::{Clause, Clauses, GoalKind, Goal, Goals};
 use ty::{self, Ty, TypeAndMut};
 use ty::{TyS, TyKind, List};
 use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const};
@@ -143,7 +143,8 @@ pub struct CtxtInterners<'tcx> {
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     const_: InternedSet<'tcx, Const<'tcx>>,
     clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
-    goals: InternedSet<'tcx, List<Goal<'tcx>>>,
+    goal: InternedSet<'tcx, GoalKind<'tcx>>,
+    goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
 }
 
 impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
@@ -159,7 +160,8 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
             predicates: Default::default(),
             const_: Default::default(),
             clauses: Default::default(),
-            goals: Default::default(),
+            goal: Default::default(),
+            goal_list: Default::default(),
         }
     }
 
@@ -827,12 +829,9 @@ impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
         // Ensure our type representation does not grow
         #[cfg(target_pointer_width = "64")]
-        #[allow(dead_code)]
-        static ASSERT_TY_KIND: () =
-            [()][!(::std::mem::size_of::<ty::TyKind<'_>>() <= 24) as usize];
+        static_assert!(ASSERT_TY_KIND: ::std::mem::size_of::<ty::TyKind<'_>>() <= 24);
         #[cfg(target_pointer_width = "64")]
-        #[allow(dead_code)]
-        static ASSERT_TYS: () = [()][!(::std::mem::size_of::<ty::TyS<'_>>() <= 32) as usize];
+        static_assert!(ASSERT_TYS: ::std::mem::size_of::<ty::TyS<'_>>() <= 32);
 
         let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
         let mk_region = |r| {
@@ -1731,9 +1730,9 @@ impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for &'a Goal<'a> {
-    type Lifted = &'tcx Goal<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Goal<'tcx>> {
+impl<'a, 'tcx> Lift<'tcx> for Goal<'a> {
+    type Lifted = Goal<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Goal<'tcx>> {
         if tcx.interners.arena.in_arena(*self as *const _) {
             return Some(unsafe { mem::transmute(*self) });
         }
@@ -2304,6 +2303,12 @@ impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
     }
 }
 
+impl<'tcx: 'lcx, 'lcx> Borrow<GoalKind<'lcx>> for Interned<'tcx, GoalKind<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a GoalKind<'lcx> {
+        &self.0
+    }
+}
+
 impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]>
     for Interned<'tcx, List<ExistentialPredicate<'tcx>>> {
     fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] {
@@ -2419,7 +2424,8 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
 
 direct_interners!('tcx,
     region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind,
-    const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>
+    const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>,
+    goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx>
 );
 
 macro_rules! slice_interners {
@@ -2438,7 +2444,7 @@ slice_interners!(
     type_list: _intern_type_list(Ty),
     substs: _intern_substs(Kind),
     clauses: _intern_clauses(Clause),
-    goals: _intern_goals(Goal)
+    goal_list: _intern_goals(Goal)
 );
 
 // This isn't a perfect fit: CanonicalVarInfo slices are always
@@ -2818,10 +2824,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         iter.intern_with(|xs| self.intern_goals(xs))
     }
 
-    pub fn mk_goal(self, goal: Goal<'tcx>) -> &'tcx Goal<'_> {
-        &self.intern_goals(&[goal])[0]
-    }
-
     pub fn lint_hir<S: Into<MultiSpan>>(self,
                                         lint: &'static Lint,
                                         hir_id: HirId,
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 3123f0fbe31..d886d5ed204 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -208,8 +208,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
             ty::FnDef(..) => "fn item".into(),
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(ref inner, ..) => {
-                inner.principal().map_or_else(|| "trait".into(),
-                    |p| format!("trait {}", tcx.item_path_str(p.def_id())).into())
+                format!("trait {}", tcx.item_path_str(inner.principal().def_id())).into()
             }
             ty::Closure(..) => "closure".into(),
             ty::Generator(..) => "generator".into(),
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 0f68e7aba4d..e6aaf8b1bb2 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -78,7 +78,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType),
         ty::RawPtr(_) => Some(PtrSimplifiedType),
         ty::Dynamic(ref trait_info, ..) => {
-            trait_info.principal().map(|p| TraitSimplifiedType(p.def_id()))
+            Some(TraitSimplifiedType(trait_info.principal().def_id()))
         }
         ty::Ref(_, ty, _) => {
             // since we introduce auto-refs during method lookup, we
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index c3d41873009..10a90dfc8a8 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -148,7 +148,10 @@ impl FlagComputation {
                 self.add_projection_ty(data);
             }
 
-            &ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+            &ty::UnnormalizedProjection(ref data) => {
+                self.add_flags(TypeFlags::HAS_PROJECTION);
+                self.add_projection_ty(data);
+            },
 
             &ty::Opaque(_, substs) => {
                 self.add_flags(TypeFlags::HAS_PROJECTION);
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index ab081324036..c4a25971da3 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -436,7 +436,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
     match ty.sty {
         ty::Adt(adt_def, _) => Some(adt_def.did),
 
-        ty::Dynamic(data, ..) => data.principal().map(|p| p.def_id()),
+        ty::Dynamic(data, ..) => Some(data.principal().def_id()),
 
         ty::Array(subty, _) |
         ty::Slice(subty) => characteristic_def_id_of_type(subty),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 145c122e75d..cc6e6b2861e 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -559,10 +559,10 @@ impl<'a, 'gcx, 'tcx> Binder<ExistentialPredicate<'tcx>> {
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List<ExistentialPredicate<'tcx>> {}
 
 impl<'tcx> List<ExistentialPredicate<'tcx>> {
-    pub fn principal(&self) -> Option<ExistentialTraitRef<'tcx>> {
-        match self.get(0) {
-            Some(&ExistentialPredicate::Trait(tr)) => Some(tr),
-            _ => None,
+    pub fn principal(&self) -> ExistentialTraitRef<'tcx> {
+        match self[0] {
+            ExistentialPredicate::Trait(tr) => tr,
+            other => bug!("first predicate is {:?}", other),
         }
     }
 
@@ -589,8 +589,8 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
 }
 
 impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
-    pub fn principal(&self) -> Option<PolyExistentialTraitRef<'tcx>> {
-        self.skip_binder().principal().map(Binder::bind)
+    pub fn principal(&self) -> PolyExistentialTraitRef<'tcx> {
+        Binder::bind(self.skip_binder().principal())
     }
 
     #[inline]
@@ -1825,9 +1825,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             }
             Dynamic(ref obj, region) => {
                 let mut v = vec![region];
-                if let Some(p) = obj.principal() {
-                    v.extend(p.skip_binder().substs.regions());
-                }
+                v.extend(obj.principal().skip_binder().substs.regions());
                 v
             }
             Adt(_, substs) | Opaque(_, substs) => {
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 7af838845cd..27747970f76 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -387,7 +387,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 
                     let cause = self.cause(traits::MiscObligation);
                     let component_traits =
-                        data.auto_traits().chain(data.principal().map(|p| p.def_id()));
+                        data.auto_traits().chain(once(data.principal().def_id()));
                     self.out.extend(
                         component_traits.map(|did| traits::Obligation::new(
                             cause.clone(),
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 33534ab27f1..f3b5503b8d0 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -621,16 +621,16 @@ define_print! {
                 // Use a type that can't appear in defaults of type parameters.
                 let dummy_self = tcx.mk_infer(ty::FreshTy(0));
 
-                if let Some(p) = self.principal() {
-                    let principal = tcx.lift(&p).expect("could not lift TraitRef for printing")
-                        .with_self_ty(tcx, dummy_self);
-                    let projections = self.projection_bounds().map(|p| {
-                        tcx.lift(&p)
-                            .expect("could not lift projection for printing")
-                            .with_self_ty(tcx, dummy_self)
-                    }).collect::<Vec<_>>();
-                    cx.parameterized(f, principal.substs, principal.def_id, &projections)?;
-                }
+                let principal = tcx
+                    .lift(&self.principal())
+                    .expect("could not lift TraitRef for printing")
+                    .with_self_ty(tcx, dummy_self);
+                let projections = self.projection_bounds().map(|p| {
+                    tcx.lift(&p)
+                        .expect("could not lift projection for printing")
+                        .with_self_ty(tcx, dummy_self)
+                }).collect::<Vec<_>>();
+                cx.parameterized(f, principal.substs, principal.def_id, &projections)?;
 
                 // Builtin bounds.
                 for did in self.auto_traits() {
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 684f2b35885..c8e8d0dc84e 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -150,7 +150,7 @@ impl LlvmType for CastTarget {
         // Create list of fields in the main structure
         let mut args: Vec<_> =
             self.prefix.iter().flat_map(|option_kind| option_kind.map(
-                    |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
+                |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
             .chain((0..rest_count).map(|_| rest_ll_unit))
             .collect();
 
@@ -259,8 +259,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
 }
 
 pub trait FnTypeExt<'tcx> {
-    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>)
-                   -> Self;
+    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self;
     fn new(cx: &CodegenCx<'ll, 'tcx>,
            sig: ty::FnSig<'tcx>,
            extra_args: &[Ty<'tcx>]) -> Self;
@@ -283,8 +282,7 @@ pub trait FnTypeExt<'tcx> {
 }
 
 impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
-    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>)
-                       -> Self {
+    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
         let fn_ty = instance.ty(cx.tcx);
         let sig = ty_fn_sig(cx, fn_ty);
         let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
@@ -292,16 +290,16 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
     }
 
     fn new(cx: &CodegenCx<'ll, 'tcx>,
-               sig: ty::FnSig<'tcx>,
-               extra_args: &[Ty<'tcx>]) -> Self {
+           sig: ty::FnSig<'tcx>,
+           extra_args: &[Ty<'tcx>]) -> Self {
         FnType::new_internal(cx, sig, extra_args, |ty, _| {
             ArgType::new(cx.layout_of(ty))
         })
     }
 
     fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
-                      sig: ty::FnSig<'tcx>,
-                      extra_args: &[Ty<'tcx>]) -> Self {
+                  sig: ty::FnSig<'tcx>,
+                  extra_args: &[Ty<'tcx>]) -> Self {
         FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
             let mut layout = cx.layout_of(ty);
             // Don't pass the vtable, it's not an argument of the virtual fn.
@@ -338,7 +336,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
             RustIntrinsic | PlatformIntrinsic |
             Rust | RustCall => Conv::C,
 
-            // It's the ABI's job to select this, not us.
+            // It's the ABI's job to select this, not ours.
             System => bug!("system abi should be selected elsewhere"),
 
             Stdcall => Conv::X86Stdcall,
@@ -697,14 +695,13 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
             // If the value is a boolean, the range is 0..2 and that ultimately
             // become 0..0 when the type becomes i1, which would be rejected
             // by the LLVM verifier.
-            match scalar.value {
-                layout::Int(..) if !scalar.is_bool() => {
+            if let layout::Int(..) = scalar.value {
+                if !scalar.is_bool() {
                     let range = scalar.valid_range_exclusive(bx.cx);
                     if range.start != range.end {
                         bx.range_metadata(callsite, range);
                     }
                 }
-                _ => {}
             }
         }
         for arg in &self.args {
diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs
index 0beb8a8844c..7c237407c8f 100644
--- a/src/librustc_codegen_llvm/allocator.rs
+++ b/src/librustc_codegen_llvm/allocator.rs
@@ -33,7 +33,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind
     let void = llvm::LLVMVoidTypeInContext(llcx);
 
     for method in ALLOCATOR_METHODS {
-        let mut args = Vec::new();
+        let mut args = Vec::with_capacity(method.inputs.len());
         for ty in method.inputs.iter() {
             match *ty {
                 AllocatorTy::Layout => {
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 51380db5b23..90ba103ca4c 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -94,9 +94,8 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     // Currently stack probes seem somewhat incompatible with the address
     // sanitizer. With asan we're already protected from stack overflow anyway
     // so we don't really need stack probes regardless.
-    match cx.sess().opts.debugging_opts.sanitizer {
-        Some(Sanitizer::Address) => return,
-        _ => {}
+    if let Some(Sanitizer::Address) = cx.sess().opts.debugging_opts.sanitizer {
+        return
     }
 
     // probestack doesn't play nice either with pgo-gen.
@@ -138,6 +137,15 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
             target_cpu.as_c_str());
 }
 
+/// Sets the `NonLazyBind` LLVM attribute on a given function,
+/// assuming the codegen options allow skipping the PLT.
+pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
+    // Don't generate calls through PLT if it's not necessary
+    if !sess.needs_plt() {
+        Attribute::NonLazyBind.apply_llfn(Function, llfn);
+    }
+}
+
 /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
 /// attributes.
 pub fn from_fn_attrs(
@@ -280,12 +288,14 @@ pub fn provide_extern(providers: &mut Providers) {
         // `NativeLibrary` internally contains information about
         // `#[link(wasm_import_module = "...")]` for example.
         let native_libs = tcx.native_libraries(cnum);
-        let mut def_id_to_native_lib = FxHashMap();
-        for lib in native_libs.iter() {
+
+        let def_id_to_native_lib = native_libs.iter().filter_map(|lib|
             if let Some(id) = lib.foreign_module {
-                def_id_to_native_lib.insert(id, lib);
+                Some((id, lib))
+            } else {
+                None
             }
-        }
+        ).collect::<FxHashMap<_, _>>();
 
         let mut ret = FxHashMap();
         for lib in tcx.foreign_modules(cnum).iter() {
@@ -296,10 +306,10 @@ pub fn provide_extern(providers: &mut Providers) {
                 Some(s) => s,
                 None => continue,
             };
-            for id in lib.foreign_items.iter() {
+            ret.extend(lib.foreign_items.iter().map(|id| {
                 assert_eq!(id.krate, cnum);
-                ret.insert(*id, module.to_string());
-            }
+                (*id, module.to_string())
+            }));
         }
 
         Lrc::new(ret)
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 55dc43ec1fb..c814ab4ab67 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -213,8 +213,8 @@ pub fn unsized_info(
                             vtable_ptr.llvm_type(cx))
         }
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
-                                     source,
-                                     target),
+                  source,
+                  target),
     }
 }
 
@@ -340,11 +340,11 @@ pub fn cast_shift_expr_rhs(
 }
 
 fn cast_shift_rhs<'ll, F, G>(op: hir::BinOpKind,
-                        lhs: &'ll Value,
-                        rhs: &'ll Value,
-                        trunc: F,
-                        zext: G)
-                        -> &'ll Value
+                             lhs: &'ll Value,
+                             rhs: &'ll Value,
+                             trunc: F,
+                             zext: G)
+                             -> &'ll Value
     where F: FnOnce(&'ll Value, &'ll Type) -> &'ll Value,
           G: FnOnce(&'ll Value, &'ll Type) -> &'ll Value
 {
@@ -363,8 +363,8 @@ fn cast_shift_rhs<'ll, F, G>(op: hir::BinOpKind,
         if lhs_sz < rhs_sz {
             trunc(rhs, lhs_llty)
         } else if lhs_sz > rhs_sz {
-            // FIXME (#1877: If shifting by negative
-            // values becomes not undefined then this is wrong.
+            // FIXME (#1877: If in the future shifting by negative
+            // values is no longer undefined then this is wrong.
             zext(rhs, lhs_llty)
         } else {
             rhs
@@ -495,10 +495,8 @@ pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'
     let sig = common::ty_fn_sig(cx, fn_ty);
     let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
 
-    let lldecl = match cx.instances.borrow().get(&instance) {
-        Some(&val) => val,
-        None => bug!("Instance `{:?}` not already declared", instance)
-    };
+    let lldecl = cx.instances.borrow().get(&instance).cloned().unwrap_or_else(||
+        bug!("Instance `{:?}` not already declared", instance));
 
     cx.stats.borrow_mut().n_closures += 1;
 
@@ -566,8 +564,8 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) {
         if declare::get_defined_value(cx, "main").is_some() {
             // FIXME: We should be smart and show a better diagnostic here.
             cx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times")
-                      .help("did you use #[no_mangle] on `fn main`? Use #[start] instead")
-                      .emit();
+                     .help("did you use #[no_mangle] on `fn main`? Use #[start] instead")
+                     .emit();
             cx.sess().abort_if_errors();
             bug!();
         }
@@ -736,9 +734,9 @@ fn determine_cgu_reuse<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             rx: mpsc::Receiver<Box<dyn Any + Send>>)
-                             -> OngoingCodegen {
-
+                               rx: mpsc::Receiver<Box<dyn Any + Send>>)
+                               -> OngoingCodegen
+{
     check_for_rustc_errors_attr(tcx);
 
     if let Some(true) = tcx.sess.opts.debugging_opts.thinlto {
@@ -803,8 +801,7 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Run the monomorphization collector and partition the collected items into
     // codegen units.
-    let codegen_units =
-        tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
+    let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
     let codegen_units = (*codegen_units).clone();
 
     // Force all codegen_unit queries so they are already either red or green
@@ -837,12 +834,7 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         .iter()
         .any(|(_, list)| {
             use rustc::middle::dependency_format::Linkage;
-            list.iter().any(|linkage| {
-                match linkage {
-                    Linkage::Dynamic => true,
-                    _ => false,
-                }
-            })
+            list.iter().any(|&linkage| linkage == Linkage::Dynamic)
         });
     let allocator_module = if any_dynamic_crate {
         None
@@ -988,7 +980,7 @@ fn collect_and_partition_mono_items<'a, 'tcx>(
                 if mode_string != "lazy" {
                     let message = format!("Unknown codegen-item collection mode '{}'. \
                                            Falling back to 'lazy' mode.",
-                                           mode_string);
+                                          mode_string);
                     tcx.sess.warn(&message);
                 }
 
@@ -1123,7 +1115,15 @@ impl CrateInfo {
             info.load_wasm_imports(tcx, LOCAL_CRATE);
         }
 
-        for &cnum in tcx.crates().iter() {
+        let crates = tcx.crates();
+
+        let n_crates = crates.len();
+        info.native_libraries.reserve(n_crates);
+        info.crate_name.reserve(n_crates);
+        info.used_crate_source.reserve(n_crates);
+        info.missing_lang_items.reserve(n_crates);
+
+        for &cnum in crates.iter() {
             info.native_libraries.insert(cnum, tcx.native_libraries(cnum));
             info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
             info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
@@ -1165,11 +1165,12 @@ impl CrateInfo {
     }
 
     fn load_wasm_imports(&mut self, tcx: TyCtxt, cnum: CrateNum) {
-        for (&id, module) in tcx.wasm_import_module_map(cnum).iter() {
+        self.wasm_imports.extend(tcx.wasm_import_module_map(cnum).iter().map(|(&id, module)| {
             let instance = Instance::mono(tcx, id);
             let import_name = tcx.symbol_name(instance);
-            self.wasm_imports.insert(import_name.to_string(), module.clone());
-        }
+
+            (import_name.to_string(), module.clone())
+        }));
     }
 }
 
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 77de88997e4..df9c4e874bd 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -110,10 +110,10 @@ impl Builder<'a, 'll, 'tcx> {
         }
         if self.cx.sess().count_llvm_insns() {
             *self.cx.stats
-                .borrow_mut()
-                .llvm_insns
-                .entry(category.to_string())
-                .or_insert(0) += 1;
+                    .borrow_mut()
+                    .llvm_insns
+                    .entry(category.to_string())
+                    .or_insert(0) += 1;
         }
     }
 
@@ -735,9 +735,9 @@ impl Builder<'a, 'll, 'tcx> {
     }
 
     pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
-                         inputs: &[&'ll Value], output: &'ll Type,
-                         volatile: bool, alignstack: bool,
-                         dia: AsmDialect) -> Option<&'ll Value> {
+                           inputs: &[&'ll Value], output: &'ll Type,
+                           volatile: bool, alignstack: bool,
+                           dia: AsmDialect) -> Option<&'ll Value> {
         self.count_insn("inlineasm");
 
         let volatile = if volatile { llvm::True }
@@ -1093,7 +1093,7 @@ impl Builder<'a, 'll, 'tcx> {
     ) -> &'ll Value {
         unsafe {
             llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src,
-                                         order, failure_order, weak)
+                                             order, failure_order, weak)
         }
     }
     pub fn atomic_rmw(
@@ -1194,7 +1194,7 @@ impl Builder<'a, 'll, 'tcx> {
             })
             .collect();
 
-        return Cow::Owned(casted_args);
+        Cow::Owned(casted_args)
     }
 
     pub fn lifetime_start(&self, ptr: &'ll Value, size: Size) {
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 53bb02ddd99..c08937fa9b9 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -336,16 +336,13 @@ pub fn langcall(tcx: TyCtxt,
                 msg: &str,
                 li: LangItem)
                 -> DefId {
-    match tcx.lang_items().require(li) {
-        Ok(id) => id,
-        Err(s) => {
-            let msg = format!("{} {}", msg, s);
-            match span {
-                Some(span) => tcx.sess.span_fatal(span, &msg[..]),
-                None => tcx.sess.fatal(&msg[..]),
-            }
+    tcx.lang_items().require(li).unwrap_or_else(|s| {
+        let msg = format!("{} {}", msg, s);
+        match span {
+            Some(span) => tcx.sess.span_fatal(span, &msg[..]),
+            None => tcx.sess.fatal(&msg[..]),
         }
-    }
+    })
 }
 
 // To avoid UB from LLVM, these two functions mask RHS with an
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 522de2f15e0..9228870bf3a 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -124,7 +124,7 @@ pub fn get_static(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll Value {
     assert!(!defined_in_current_codegen_unit,
             "consts::get_static() should always hit the cache for \
              statics defined in the same CGU, but did not for `{:?}`",
-             def_id);
+            def_id);
 
     let ty = instance.ty(cx.tcx);
     let sym = cx.tcx.symbol_name(instance).as_str();
@@ -249,14 +249,13 @@ fn check_and_apply_linkage(
         // extern "C" fn() from being non-null, so we can't just declare a
         // static and call it a day. Some linkages (like weak) will make it such
         // that the static actually has a null value.
-        let llty2 = match ty.sty {
-            ty::RawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx),
-            _ => {
-                if span.is_some() {
-                    cx.sess().span_fatal(span.unwrap(), "must have type `*const T` or `*mut T`")
-                } else {
-                    bug!("must have type `*const T` or `*mut T`")
-                }
+        let llty2 = if let ty::RawPtr(ref mt) = ty.sty {
+            cx.layout_of(mt.ty).llvm_type(cx)
+        } else {
+            if let Some(span) = span {
+                cx.sess().span_fatal(span, "must have type `*const T` or `*mut T`")
+            } else {
+                bug!("must have type `*const T` or `*mut T`")
             }
         };
         unsafe {
@@ -273,9 +272,9 @@ fn check_and_apply_linkage(
             let mut real_name = "_rust_extern_with_linkage_".to_string();
             real_name.push_str(&sym);
             let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{
-                if span.is_some() {
+                if let Some(span) = span {
                     cx.sess().span_fatal(
-                        span.unwrap(),
+                        span,
                         &format!("symbol `{}` is already defined", &sym)
                     )
                 } else {
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 9547f4a190e..e6197423738 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -59,8 +59,8 @@ pub struct CodegenCx<'a, 'tcx: 'a> {
     /// Cache instances of monomorphic and polymorphic items
     pub instances: RefCell<FxHashMap<Instance<'tcx>, &'a Value>>,
     /// Cache generated vtables
-    pub vtables: RefCell<FxHashMap<(Ty<'tcx>,
-                                Option<ty::PolyExistentialTraitRef<'tcx>>), &'a Value>>,
+    pub vtables: RefCell<FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>),
+                                   &'a Value>>,
     /// Cache of constant strings,
     pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, &'a Value>>,
 
@@ -208,14 +208,21 @@ pub unsafe fn create_module(
         llvm::LLVMRustSetModulePIELevel(llmod);
     }
 
+    // If skipping the PLT is enabled, we need to add some module metadata
+    // to ensure intrinsic calls don't use it.
+    if !sess.needs_plt() {
+        let avoid_plt = "RtLibUseGOT\0".as_ptr() as *const _;
+        llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
+    }
+
     llmod
 }
 
 impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
     crate fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               codegen_unit: Arc<CodegenUnit<'tcx>>,
-               llvm_module: &'a ::ModuleLlvm)
-               -> CodegenCx<'a, 'tcx> {
+                 codegen_unit: Arc<CodegenUnit<'tcx>>,
+                 llvm_module: &'a ::ModuleLlvm)
+                 -> CodegenCx<'a, 'tcx> {
         // An interesting part of Windows which MSVC forces our hand on (and
         // apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
         // attributes in LLVM IR as well as native dependencies (in C these
@@ -270,8 +277,8 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
         let dbg_cx = if tcx.sess.opts.debuginfo != DebugInfo::None {
             let dctx = debuginfo::CrateDebugContext::new(llmod);
             debuginfo::metadata::compile_unit_metadata(tcx,
-                                                        &codegen_unit.name().as_str(),
-                                                        &dctx);
+                                                       &codegen_unit.name().as_str(),
+                                                       &dctx);
             Some(dctx)
         } else {
             None
@@ -318,10 +325,8 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
         if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
             return v;
         }
-        match declare_intrinsic(self, key) {
-            Some(v) => return v,
-            None => bug!("unknown intrinsic '{}'", key)
-        }
+
+        declare_intrinsic(self, key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key))
     }
 
     /// Generate a new symbol name with the given prefix. This symbol name must
@@ -465,9 +470,10 @@ impl LayoutOf for &'a CodegenCx<'ll, 'tcx> {
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty))
-            .unwrap_or_else(|e| match e {
-                LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
-                _ => bug!("failed to get layout for `{}`: {}", ty, e)
+            .unwrap_or_else(|e| if let LayoutError::SizeOverflow(_) = e {
+                self.sess().fatal(&e.to_string())
+            } else {
+                bug!("failed to get layout for `{}`: {}", ty, e)
             })
     }
 }
@@ -772,5 +778,6 @@ fn declare_intrinsic(cx: &CodegenCx<'ll, '_>, key: &str) -> Option<&'ll Value> {
         ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void);
         ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void);
     }
-    return None;
+
+    None
 }
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 706568b5446..6eff086a2ba 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -435,12 +435,7 @@ fn trait_pointer_metadata(
     // But it does not describe the trait's methods.
 
     let containing_scope = match trait_type.sty {
-        ty::Dynamic(ref data, ..) => if let Some(principal) = data.principal() {
-            let def_id = principal.def_id();
-            Some(get_namespace_for_item(cx, def_id))
-        } else {
-            NO_SCOPE_METADATA
-        },
+        ty::Dynamic(ref data, ..) => Some(get_namespace_for_item(cx, data.principal().def_id())),
         _ => {
             bug!("debuginfo: Unexpected trait-object type in \
                   trait_pointer_metadata(): {:?}",
diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs
index 2f110fd552a..06b9318a5e8 100644
--- a/src/librustc_codegen_llvm/debuginfo/type_names.rs
+++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs
@@ -116,14 +116,12 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             }
         },
         ty::Dynamic(ref trait_data, ..) => {
-            if let Some(principal) = trait_data.principal() {
-                let principal = cx.tcx.normalize_erasing_late_bound_regions(
-                    ty::ParamEnv::reveal_all(),
-                    &principal,
-                );
-                push_item_name(cx, principal.def_id, false, output);
-                push_type_params(cx, principal.substs, output);
-            }
+            let principal = cx.tcx.normalize_erasing_late_bound_regions(
+                ty::ParamEnv::reveal_all(),
+                &trait_data.principal(),
+            );
+            push_item_name(cx, principal.def_id, false, output);
+            push_type_params(cx, principal.substs, output);
         },
         ty::FnDef(..) | ty::FnPtr(_) => {
             let sig = t.fn_sig(cx.tcx);
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 7141c9ece89..26969e24f08 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -104,6 +104,8 @@ fn declare_raw_fn(
         attributes::unwind(llfn, false);
     }
 
+    attributes::non_lazy_bind(cx.sess(), llfn);
+
     llfn
 }
 
diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/diagnostics.rs
index 242b7a1a119..5721938c9c0 100644
--- a/src/librustc_codegen_llvm/diagnostics.rs
+++ b/src/librustc_codegen_llvm/diagnostics.rs
@@ -69,4 +69,15 @@ fn main() {
 ```
 "##,
 
+E0669: r##"
+Cannot convert inline assembly operand to a single LLVM value.
+
+This error usually happens when trying to pass in a value to an input inline
+assembly operand that is actually a pair of values. In particular, this can
+happen when trying to pass in a slice, for instance a `&str`. In Rust, these
+values are represented internally as a pair of values, the pointer and its
+length. When passed as an input operand, this pair of values can not be
+coerced into a register and thus we must fail with an error.
+"##,
+
 }
diff --git a/src/librustc_codegen_llvm/glue.rs b/src/librustc_codegen_llvm/glue.rs
index ff33cec0437..842bdf3cb49 100644
--- a/src/librustc_codegen_llvm/glue.rs
+++ b/src/librustc_codegen_llvm/glue.rs
@@ -97,8 +97,8 @@ pub fn size_and_align_of_dst(bx: &Builder<'_, 'll, 'tcx>, t: Ty<'tcx>, info: Opt
                     C_usize(cx, std::cmp::max(sized_align, unsized_align) as u64)
                 }
                 _ => bx.select(bx.icmp(llvm::IntUGT, sized_align, unsized_align),
-                                sized_align,
-                                unsized_align)
+                               sized_align,
+                               unsized_align)
             };
 
             // Issue #27023: must add any necessary padding to `size`
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 5ec934ebd06..272196afa6f 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -115,8 +115,8 @@ pub fn codegen_intrinsic_call(
     let llval = match name {
         _ if simple.is_some() => {
             bx.call(simple.unwrap(),
-                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
-                     None)
+                    &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
+                    None)
         }
         "unreachable" => {
             return;
@@ -373,7 +373,6 @@ pub fn codegen_intrinsic_call(
                     return;
                 }
             }
-
         },
         "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
             let sty = &arg_tys[0].sty;
@@ -540,10 +539,9 @@ pub fn codegen_intrinsic_call(
         }
 
         _ => {
-            let intr = match Intrinsic::find(&name) {
-                Some(intr) => intr,
-                None => bug!("unknown intrinsic '{}'", name),
-            };
+            let intr = Intrinsic::find(&name).unwrap_or_else(||
+                bug!("unknown intrinsic '{}'", name));
+
             fn one<T>(x: Vec<T>) -> T {
                 assert_eq!(x.len(), 1);
                 x.into_iter().next().unwrap()
@@ -822,8 +820,7 @@ fn codegen_msvc_try(
         let i64p = Type::i64(cx).ptr_to();
         let ptr_align = bx.tcx().data_layout.pointer_align;
         let slot = bx.alloca(i64p, "slot", ptr_align);
-        bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(),
-            None);
+        bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
 
         normal.ret(C_i32(cx, 0));
 
@@ -911,8 +908,7 @@ fn codegen_gnu_try(
         // being thrown.  The second value is a "selector" indicating which of
         // the landing pad clauses the exception's type had been matched to.
         // rust_try ignores the selector.
-        let lpad_ty = Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)],
-                                    false);
+        let lpad_ty = Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)], false);
         let vals = catch.landing_pad(lpad_ty, bx.cx.eh_personality(), 1);
         catch.add_clause(vals, C_null(Type::i8p(cx)));
         let ptr = catch.extract_value(vals, 0);
@@ -976,7 +972,7 @@ fn get_rust_try_fn<'ll, 'tcx>(
     let output = tcx.types.i32;
     let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, codegen);
     cx.rust_try_fn.set(Some(rust_try));
-    return rust_try
+    rust_try
 }
 
 fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
@@ -1000,11 +996,11 @@ fn generic_simd_intrinsic(
         ($msg: tt, $($fmt: tt)*) => {
             span_invalid_monomorphization_error(
                 bx.sess(), span,
-                &format!(concat!("invalid monomorphization of `{}` intrinsic: ",
-                                 $msg),
+                &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
                          name, $($fmt)*));
         }
     }
+
     macro_rules! return_error {
         ($($fmt: tt)*) => {
             {
@@ -1021,14 +1017,13 @@ fn generic_simd_intrinsic(
             }
         };
     }
+
     macro_rules! require_simd {
         ($ty: expr, $position: expr) => {
             require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
         }
     }
 
-
-
     let tcx = bx.tcx();
     let sig = tcx.normalize_erasing_late_bound_regions(
         ty::ParamEnv::reveal_all(),
@@ -1075,11 +1070,8 @@ fn generic_simd_intrinsic(
     }
 
     if name.starts_with("simd_shuffle") {
-        let n: usize = match name["simd_shuffle".len()..].parse() {
-            Ok(n) => n,
-            Err(_) => span_bug!(span,
-                                "bad `simd_shuffle` instruction only caught in codegen?")
-        };
+        let n: usize = name["simd_shuffle".len()..].parse().unwrap_or_else(|_|
+            span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?"));
 
         require_simd!(ret_ty, "return");
 
@@ -1121,8 +1113,8 @@ fn generic_simd_intrinsic(
         };
 
         return Ok(bx.shuffle_vector(args[0].immediate(),
-                                     args[1].immediate(),
-                                     C_vector(&indices)))
+                                    args[1].immediate(),
+                                    C_vector(&indices)))
     }
 
     if name == "simd_insert" {
@@ -1130,8 +1122,8 @@ fn generic_simd_intrinsic(
                  "expected inserted type `{}` (element of input `{}`), found `{}`",
                  in_elem, in_ty, arg_tys[2]);
         return Ok(bx.insert_element(args[0].immediate(),
-                                     args[2].immediate(),
-                                     args[1].immediate()))
+                                    args[2].immediate(),
+                                    args[1].immediate()))
     }
     if name == "simd_extract" {
         require!(ret_ty == in_elem,
@@ -1150,9 +1142,7 @@ fn generic_simd_intrinsic(
         );
         match m_elem_ty.sty {
             ty::Int(_) => {},
-            _ => {
-                return_error!("mask element type is `{}`, expected `i_`", m_elem_ty);
-            }
+            _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty)
         }
         // truncate the mask to a vector of i1s
         let i1 = Type::i1(bx.cx);
@@ -1177,8 +1167,7 @@ fn generic_simd_intrinsic(
             ($msg: tt, $($fmt: tt)*) => {
                 span_invalid_monomorphization_error(
                     bx.sess(), span,
-                    &format!(concat!("invalid monomorphization of `{}` intrinsic: ",
-                                     $msg),
+                    &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
                              name, $($fmt)*));
             }
         }
@@ -1223,63 +1212,53 @@ fn generic_simd_intrinsic(
                         &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                         None);
         unsafe { llvm::LLVMRustSetHasUnsafeAlgebra(c) };
-        return Ok(c);
-    }
-
-    if name == "simd_fsqrt" {
-        return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_fsin" {
-        return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_fcos" {
-        return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_fabs" {
-        return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_floor" {
-        return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_ceil" {
-        return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_fexp" {
-        return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_fexp2" {
-        return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_flog10" {
-        return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_flog2" {
-        return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_flog" {
-        return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args);
+        Ok(c)
     }
 
-    if name == "simd_fpowi" {
-        return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_fpow"  {
-        return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args);
-    }
-
-    if name == "simd_fma" {
-        return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args);
+    match name {
+        "simd_fsqrt" => {
+            return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fsin" => {
+            return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fcos" => {
+            return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fabs" => {
+            return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_floor" => {
+            return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_ceil" => {
+            return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fexp" => {
+            return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fexp2" => {
+            return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_flog10" => {
+            return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_flog2" => {
+            return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_flog" => {
+            return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fpowi" => {
+            return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fpow" => {
+            return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args);
+        }
+        "simd_fma" => {
+            return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args);
+        }
+        _ => { /* fallthrough */ }
     }
 
     // FIXME: use:
@@ -1312,7 +1291,7 @@ fn generic_simd_intrinsic(
     }
 
 
-    if name == "simd_gather"  {
+    if name == "simd_gather" {
         // simd_gather(values: <N x T>, pointers: <N x *_ T>,
         //             mask: <N x i{M}>) -> <N x T>
         // * N: number of elements in the input vectors
@@ -1360,7 +1339,7 @@ fn generic_simd_intrinsic(
         // to the element type of the first argument
         let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty {
             ty::RawPtr(p) if p.ty == in_elem => (ptr_count(arg_tys[1].simd_type(tcx)),
-                                                   non_ptr(arg_tys[1].simd_type(tcx))),
+                                                 non_ptr(arg_tys[1].simd_type(tcx))),
             _ => {
                 require!(false, "expected element type `{}` of second argument `{}` \
                                  to be a pointer to the element type `{}` of the first \
@@ -1371,7 +1350,7 @@ fn generic_simd_intrinsic(
             }
         };
         assert!(pointer_count > 0);
-        assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx)));
+        assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
         assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
 
         // The element type of the third argument must be a signed integer type of any width:
@@ -1414,7 +1393,7 @@ fn generic_simd_intrinsic(
         return Ok(v);
     }
 
-    if name == "simd_scatter"  {
+    if name == "simd_scatter" {
         // simd_scatter(values: <N x T>, pointers: <N x *mut T>,
         //             mask: <N x i{M}>) -> ()
         // * N: number of elements in the input vectors
@@ -1468,7 +1447,7 @@ fn generic_simd_intrinsic(
             }
         };
         assert!(pointer_count > 0);
-        assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx)));
+        assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
         assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
 
         // The element type of the third argument must be a signed integer type of any width:
@@ -1570,7 +1549,6 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
                                     )
                                 }
                             }
-
                         };
                         Ok(bx.$float_reduce(acc, args[0].immediate()))
                     }
@@ -1750,9 +1728,9 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
                     _ => {},
                 }
                 require!(false,
-                            "unsupported operation on `{}` with element `{}`",
-                            in_ty,
-                            in_elem)
+                         "unsupported operation on `{}` with element `{}`",
+                         in_ty,
+                         in_elem)
             })*
         }
     }
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 71d739222b6..63a8ab077e5 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -306,7 +306,7 @@ impl ModuleCodegen {
         };
         let bytecode_compressed = if emit_bc_compressed {
             Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
-                    .with_extension(RLIB_BYTECODE_EXTENSION))
+                        .with_extension(RLIB_BYTECODE_EXTENSION))
         } else {
             None
         };
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 8485db4210c..c9f51efdc50 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -122,6 +122,7 @@ pub enum Attribute {
     SanitizeThread  = 20,
     SanitizeAddress = 21,
     SanitizeMemory  = 22,
+    NonLazyBind     = 23,
 }
 
 /// LLVMIntPredicate
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 9e8ff204703..8456cf2f480 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -52,8 +52,9 @@ fn require_inited() {
 }
 
 unsafe fn configure_llvm(sess: &Session) {
-    let mut llvm_c_strs = Vec::new();
-    let mut llvm_args = Vec::new();
+    let n_args = sess.opts.cg.llvm_args.len();
+    let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
+    let mut llvm_args = Vec::with_capacity(n_args + 1);
 
     {
         let mut add = |arg: &str| {
diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs
index a4526a53769..7752465d885 100644
--- a/src/librustc_codegen_llvm/metadata.rs
+++ b/src/librustc_codegen_llvm/metadata.rs
@@ -63,7 +63,7 @@ impl MetadataLoader for LlvmMetadataLoader {
             let of = ObjectFile::new(mb)
                 .map(|of| OwningRef::new(box of))
                 .ok_or_else(|| format!("provided path not an object file: '{}'",
-                                        filename.display()))?;
+                                       filename.display()))?;
             let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
             Ok(rustc_erase_owner!(buf))
         }
diff --git a/src/librustc_codegen_llvm/meth.rs b/src/librustc_codegen_llvm/meth.rs
index 8a1159bc477..db06b87f44e 100644
--- a/src/librustc_codegen_llvm/meth.rs
+++ b/src/librustc_codegen_llvm/meth.rs
@@ -72,7 +72,7 @@ impl<'a, 'tcx> VirtualIndex {
 pub fn get_vtable(
     cx: &CodegenCx<'ll, 'tcx>,
     ty: Ty<'tcx>,
-    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
 ) -> &'ll Value {
     let tcx = cx.tcx;
 
@@ -86,23 +86,19 @@ pub fn get_vtable(
     // Not in the cache. Build it.
     let nullptr = C_null(Type::i8p(cx));
 
+    let methods = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
+    let methods = methods.iter().cloned().map(|opt_mth| {
+        opt_mth.map_or(nullptr, |(def_id, substs)| {
+            callee::resolve_and_get_fn(cx, def_id, substs)
+        })
+    });
+
     let (size, align) = cx.size_and_align_of(ty);
-    let mut components: Vec<_> = [
+    let components: Vec<_> = [
         callee::get_fn(cx, monomorphize::resolve_drop_in_place(cx.tcx, ty)),
         C_usize(cx, size.bytes()),
         C_usize(cx, align.abi())
-    ].iter().cloned().collect();
-
-    if let Some(trait_ref) = trait_ref {
-        let trait_ref = trait_ref.with_self_ty(tcx, ty);
-        let methods = tcx.vtable_methods(trait_ref);
-        let methods = methods.iter().cloned().map(|opt_mth| {
-            opt_mth.map_or(nullptr, |(def_id, substs)| {
-                callee::resolve_and_get_fn(cx, def_id, substs)
-            })
-        });
-        components.extend(methods);
-    }
+    ].iter().cloned().chain(methods).collect();
 
     let vtable_const = C_struct(cx, &components, false);
     let align = cx.data_layout().pointer_align;
diff --git a/src/librustc_codegen_llvm/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs
index c3e3785a724..a0d6cc46295 100644
--- a/src/librustc_codegen_llvm/mir/analyze.rs
+++ b/src/librustc_codegen_llvm/mir/analyze.rs
@@ -151,9 +151,9 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
     }
 
     fn visit_place(&mut self,
-                    place: &mir::Place<'tcx>,
-                    context: PlaceContext<'tcx>,
-                    location: Location) {
+                   place: &mir::Place<'tcx>,
+                   context: PlaceContext<'tcx>,
+                   location: Location) {
         debug!("visit_place(place={:?}, context={:?})", place, context);
         let cx = self.fx.cx;
 
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index db95b46c38e..5be176f75c9 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -49,9 +49,9 @@ impl FunctionCx<'a, 'll, 'tcx> {
     }
 
     fn codegen_terminator(&mut self,
-                        mut bx: Builder<'a, 'll, 'tcx>,
-                        bb: mir::BasicBlock,
-                        terminator: &mir::Terminator<'tcx>)
+                          mut bx: Builder<'a, 'll, 'tcx>,
+                          bb: mir::BasicBlock,
+                          terminator: &mir::Terminator<'tcx>)
     {
         debug!("codegen_terminator: {:?}", terminator);
 
diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs
index ce18f31da69..9f0f7443890 100644
--- a/src/librustc_codegen_llvm/mir/constant.rs
+++ b/src/librustc_codegen_llvm/mir/constant.rs
@@ -92,7 +92,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
     let pointer_size = layout.pointer_size.bytes() as usize;
 
     let mut next_offset = 0;
-    for &(offset, alloc_id) in alloc.relocations.iter() {
+    for &(offset, ((), alloc_id)) in alloc.relocations.iter() {
         let offset = offset.bytes();
         assert_eq!(offset as usize as u64, offset);
         let offset = offset as usize;
@@ -105,7 +105,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
         ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
         llvals.push(scalar_to_llvm(
             cx,
-            Pointer { alloc_id, offset: Size::from_bytes(ptr_offset) }.into(),
+            Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
             &layout::Scalar {
                 value: layout::Primitive::Pointer,
                 valid_range: 0..=!0
diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs
index 6bd41bfe16f..93be0074f6e 100644
--- a/src/librustc_codegen_llvm/mir/statement.rs
+++ b/src/librustc_codegen_llvm/mir/statement.rs
@@ -15,6 +15,7 @@ use builder::Builder;
 
 use super::FunctionCx;
 use super::LocalRef;
+use super::OperandValue;
 
 impl FunctionCx<'a, 'll, 'tcx> {
     pub fn codegen_statement(&mut self,
@@ -82,14 +83,27 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     self.codegen_place(&bx, output)
                 }).collect();
 
-                let input_vals = inputs.iter().map(|input| {
-                    self.codegen_operand(&bx, input).immediate()
-                }).collect();
+                let input_vals = inputs.iter()
+                    .try_fold(Vec::with_capacity(inputs.len()), |mut acc, input| {
+                        let op = self.codegen_operand(&bx, input);
+                        if let OperandValue::Immediate(_) = op.val {
+                            acc.push(op.immediate());
+                            Ok(acc)
+                        } else {
+                            Err(op)
+                        }
+                });
 
-                let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
-                if !res {
-                    span_err!(bx.sess(), statement.source_info.span, E0668,
-                              "malformed inline assembly");
+                if input_vals.is_err() {
+                   span_err!(bx.sess(), statement.source_info.span, E0669,
+                             "invalid value for constraint in inline assembly");
+                } else {
+                    let input_vals = input_vals.unwrap();
+                    let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
+                    if !res {
+                        span_err!(bx.sess(), statement.source_info.span, E0668,
+                                  "malformed inline assembly");
+                    }
                 }
                 bx
             }
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index a8502e92447..dab9b147cc0 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -108,8 +108,8 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
         match *self.as_mono_item() {
             MonoItem::Fn(instance) => {
                 format!("Fn({:?}, {})",
-                         instance.def,
-                         instance.substs.as_ptr() as usize)
+                        instance.def,
+                        instance.substs.as_ptr() as usize)
             }
             MonoItem::Static(id) => {
                 format!("Static({:?})", id)
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 765708aeafd..03ded64e642 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -65,13 +65,12 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             let mut name = String::with_capacity(32);
             let printer = DefPathBasedNames::new(cx.tcx, true, true);
             printer.push_type_name(layout.ty, &mut name);
-            match (&layout.ty.sty, &layout.variants) {
-                (&ty::Adt(def, _), &layout::Variants::Single { index }) => {
-                    if def.is_enum() && !def.variants.is_empty() {
-                        write!(&mut name, "::{}", def.variants[index].name).unwrap();
-                    }
+            if let (&ty::Adt(def, _), &layout::Variants::Single { index })
+                 = (&layout.ty.sty, &layout.variants)
+            {
+                if def.is_enum() && !def.variants.is_empty() {
+                    write!(&mut name, "::{}", def.variants[index].name).unwrap();
                 }
-                _ => {}
             }
             Some(name)
         }
@@ -132,7 +131,7 @@ fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
         debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?} \
                 effective_field_align: {}",
-            i, field, offset, target_offset, effective_field_align.abi());
+               i, field, offset, target_offset, effective_field_align.abi());
         assert!(target_offset >= offset);
         let padding = target_offset - offset;
         let padding_align = prev_effective_align.min(effective_field_align);
@@ -155,7 +154,7 @@ fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
                padding, offset, layout.size);
         result.push(Type::padding_filler(cx, padding, padding_align));
-        assert!(result.len() == 1 + field_count * 2);
+        assert_eq!(result.len(), 1 + field_count * 2);
     } else {
         debug!("struct_llfields: offset: {:?} stride: {:?}",
                offset, layout.size);
diff --git a/src/librustc_codegen_llvm/value.rs b/src/librustc_codegen_llvm/value.rs
index 3328948c295..4bf5b09baa6 100644
--- a/src/librustc_codegen_llvm/value.rs
+++ b/src/librustc_codegen_llvm/value.rs
@@ -34,6 +34,6 @@ impl fmt::Debug for Value {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(&llvm::build_string(|s| unsafe {
             llvm::LLVMRustWriteValueToString(self, s);
-        }).expect("nun-UTF8 value description from LLVM"))
+        }).expect("non-UTF8 value description from LLVM"))
     }
 }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 8c945ccbe95..276b7290c2e 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -21,7 +21,6 @@
 #![feature(box_syntax)]
 #![cfg_attr(unix, feature(libc))]
 #![feature(nll)]
-#![feature(option_replace)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index 2799f2cc81f..870eeadc081 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -76,9 +76,9 @@ pub enum StringPart {
 }
 
 impl StringPart {
-    pub fn content(&self) -> String {
+    pub fn content(&self) -> &str {
         match self {
-            &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
+            &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s
         }
     }
 }
@@ -398,7 +398,7 @@ impl Diagnostic {
     }
 
     pub fn message(&self) -> String {
-        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
+        self.message.iter().map(|i| i.0.as_str()).collect::<String>()
     }
 
     pub fn styled_message(&self) -> &Vec<(String, Style)> {
@@ -448,7 +448,7 @@ impl Diagnostic {
 
 impl SubDiagnostic {
     pub fn message(&self) -> String {
-        self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
+        self.message.iter().map(|i| i.0.as_str()).collect::<String>()
     }
 
     pub fn styled_message(&self) -> &Vec<(String, Style)> {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index ae178888b6a..7d178d20967 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -59,15 +59,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
         }
 
         let t = cx.tables.expr_ty(&expr);
-        let ty_warned = match t.sty {
-            ty::Tuple(ref tys) if tys.is_empty() => return,
-            ty::Never => return,
+        // FIXME(varkor): replace with `t.is_unit() || t.conservative_is_uninhabited()`.
+        let type_permits_no_use = match t.sty {
+            ty::Tuple(ref tys) if tys.is_empty() => true,
+            ty::Never => true,
             ty::Adt(def, _) => {
                 if def.variants.is_empty() {
-                    return;
+                    true
+                } else {
+                    check_must_use(cx, def.did, s.span, "")
                 }
-                check_must_use(cx, def.did, s.span, "")
-            },
+            }
             _ => false,
         };
 
@@ -78,10 +80,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
                 match callee.node {
                     hir::ExprKind::Path(ref qpath) => {
                         let def = cx.tables.qpath_def(qpath, callee.hir_id);
-                        if let Def::Fn(_) = def {
-                            Some(def)
-                        } else {  // `Def::Local` if it was a closure, for which we
-                            None  // do not currently support must-use linting
+                        match def {
+                            Def::Fn(_) | Def::Method(_) => Some(def),
+                            // `Def::Local` if it was a closure, for which we
+                            // do not currently support must-use linting
+                            _ => None
                         }
                     },
                     _ => None
@@ -95,7 +98,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
         if let Some(def) = maybe_def {
             let def_id = def.def_id();
             fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
+        } else if type_permits_no_use {
+            // We don't warn about unused unit or uninhabited types.
+            // (See https://github.com/rust-lang/rust/issues/43806 for details.)
+            return;
         }
+
         let must_use_op = match expr.node {
             // Hardcoding operators here seemed more expedient than the
             // refactoring that would be needed to look up the `#[must_use]`
@@ -139,7 +147,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
             op_warned = true;
         }
 
-        if !(ty_warned || fn_warned || op_warned) {
+        if !(type_permits_no_use || fn_warned || op_warned) {
             cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
         }
 
@@ -233,7 +241,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
                 .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
                 .is_some();
 
-            // Has a plugin registered this attribute as one which must be used at
+            // Has a plugin registered this attribute as one that must be used at
             // the crate level?
             let plugin_crate = plugin_attributes.iter()
                 .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 0943b36440a..9cbaf35acd3 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -544,7 +544,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                         // be encoeded through MIR place derefs instead.
                         self.access_place(
                             context,
-                            (output, span),
+                            (output, o.span),
                             (Deep, Read(ReadKind::Copy)),
                             LocalMutationIsAllowed::No,
                             flow_state,
@@ -552,13 +552,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                         self.check_if_path_or_subpath_is_moved(
                             context,
                             InitializationRequiringAction::Use,
-                            (output, span),
+                            (output, o.span),
                             flow_state,
                         );
                     } else {
                         self.mutate_place(
                             context,
-                            (output, span),
+                            (output, o.span),
                             if o.is_rw { Deep } else { Shallow(None) },
                             if o.is_rw { WriteAndRead } else { JustWrite },
                             flow_state,
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index 693cfea3c95..ea62694f8be 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -68,6 +68,7 @@ enum GroupedMoveError<'tcx> {
 enum BorrowedContentSource {
     Arc,
     Rc,
+    DerefRawPointer,
     Other,
 }
 
@@ -76,6 +77,7 @@ impl Display for BorrowedContentSource {
         match *self {
             BorrowedContentSource::Arc => write!(f, "an `Arc`"),
             BorrowedContentSource::Rc => write!(f, "an `Rc`"),
+            BorrowedContentSource::DerefRawPointer => write!(f, "dereference of raw pointer"),
             BorrowedContentSource::Other => write!(f, "borrowed content"),
         }
     }
@@ -279,6 +281,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                             self.prefixes(&original_path, PrefixSet::All)
                             .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx)
                                  .is_some());
+                        debug!("report: ty={:?}", ty);
                         match ty.sty {
                             ty::Array(..) | ty::Slice(..) =>
                                 self.infcx.tcx.cannot_move_out_of_interior_noncopy(
@@ -582,6 +585,18 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
+        // If we didn't find an `Arc` or an `Rc`, then check specifically for
+        // a dereference of a place that has the type of a raw pointer.
+        // We can't use `place.ty(..).to_ty(..)` here as that strips away the raw pointer.
+        if let Place::Projection(box Projection {
+            base,
+            elem: ProjectionElem::Deref,
+        }) = place {
+            if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() {
+                return BorrowedContentSource::DerefRawPointer;
+            }
+        }
+
         BorrowedContentSource::Other
     }
 }
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 e55469436ab..307112f8ba1 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -13,8 +13,10 @@ use borrow_check::error_reporting::UseSpans;
 use borrow_check::nll::region_infer::Cause;
 use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
 use rustc::ty::{self, Region, TyCtxt};
-use rustc::mir::{FakeReadCause, Local, Location, Mir, Operand};
-use rustc::mir::{Place, StatementKind, TerminatorKind};
+use rustc::mir::{
+    CastKind, FakeReadCause, Local, Location, Mir, Operand, Place, Projection, ProjectionElem,
+    Rvalue, Statement, StatementKind, TerminatorKind
+};
 use rustc_errors::DiagnosticBuilder;
 use syntax_pos::Span;
 
@@ -34,6 +36,7 @@ pub(in borrow_check) enum BorrowExplanation<'tcx> {
 
 #[derive(Clone, Copy)]
 pub(in borrow_check) enum LaterUseKind {
+    TraitCapture,
     ClosureCapture,
     Call,
     FakeLetRead,
@@ -51,6 +54,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
         match *self {
             BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
                 let message = match later_use_kind {
+                    LaterUseKind::TraitCapture => "borrow later captured here by trait object",
                     LaterUseKind::ClosureCapture => "borrow later captured here by closure",
                     LaterUseKind::Call =>  "borrow later used by call",
                     LaterUseKind::FakeLetRead => "borrow later stored here",
@@ -60,9 +64,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
             },
             BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
                 let message = match later_use_kind {
-                    LaterUseKind::ClosureCapture => {
-                        "borrow captured here by closure, in later iteration of loop"
-                    },
+                    LaterUseKind::TraitCapture =>
+                        "borrow captured here by trait object, in later iteration of loop",
+                    LaterUseKind::ClosureCapture =>
+                        "borrow captured here by closure, in later iteration of loop",
                     LaterUseKind::Call =>  "borrow used by call, in later iteration of loop",
                     LaterUseKind::FakeLetRead => "borrow later stored here",
                     LaterUseKind::Other => "borrow used here, in later iteration of loop",
@@ -200,13 +205,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     .or_else(|| self.borrow_spans(span, location));
 
                 if self.is_borrow_location_in_loop(context.loc) {
-                    let later_use = self.later_use_kind(spans, location);
+                    let later_use = self.later_use_kind(borrow, spans, location);
                     BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
                 } else {
                     // Check if the location represents a `FakeRead`, and adapt the error
                     // message to the `FakeReadCause` it is from: in particular,
                     // the ones inserted in optimized `let var = <expr>` patterns.
-                    let later_use = self.later_use_kind(spans, location);
+                    let later_use = self.later_use_kind(borrow, spans, location);
                     BorrowExplanation::UsedLater(later_use.0, later_use.1)
                 }
             }
@@ -316,42 +321,184 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         false
     }
 
-    fn later_use_kind(&self, use_spans: UseSpans, location: Location) -> (LaterUseKind, Span) {
-        use self::LaterUseKind::*;
-
-        let block = &self.mir.basic_blocks()[location.block];
+    /// Determine how the borrow was later used.
+    fn later_use_kind(
+        &self,
+        borrow: &BorrowData<'tcx>,
+        use_spans: UseSpans,
+        location: Location
+    ) -> (LaterUseKind, Span) {
         match use_spans {
-            UseSpans::ClosureUse { var_span, .. } => (LaterUseKind::ClosureCapture, var_span),
+            UseSpans::ClosureUse { var_span, .. } => {
+                // Used in a closure.
+                (LaterUseKind::ClosureCapture, var_span)
+            },
             UseSpans::OtherUse(span) => {
-                (if let Some(stmt) = block.statements.get(location.statement_index) {
-                    match stmt.kind {
-                        StatementKind::FakeRead(FakeReadCause::ForLet, _) => FakeLetRead,
-                        _ => Other,
+                let block = &self.mir.basic_blocks()[location.block];
+
+                let kind = if let Some(&Statement {
+                    kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
+                    ..
+                }) = block.statements.get(location.statement_index) {
+                    LaterUseKind::FakeLetRead
+                } else if self.was_captured_by_trait_object(borrow) {
+                    LaterUseKind::TraitCapture
+                } else if location.statement_index == block.statements.len() {
+                    if let TerminatorKind::Call {
+                        ref func, from_hir_call: true, ..
+                    } = block.terminator().kind {
+                        // Just point to the function, to reduce the chance of overlapping spans.
+                        let function_span = match func {
+                            Operand::Constant(c) => c.span,
+                            Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => {
+                                let local_decl = &self.mir.local_decls[*l];
+                                if local_decl.name.is_none() {
+                                    local_decl.source_info.span
+                                } else {
+                                    span
+                                }
+                            },
+                            _ => span,
+                        };
+                        return (LaterUseKind::Call, function_span);
+                    } else {
+                        LaterUseKind::Other
                     }
                 } else {
-                    assert_eq!(location.statement_index, block.statements.len());
-                    match block.terminator().kind {
-                        TerminatorKind::Call { ref func, from_hir_call: true, .. } => {
-                            // Just point to the function, to reduce the chance
-                            // of overlapping spans.
-                            let function_span = match func {
-                                Operand::Constant(c) => c.span,
-                                Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => {
-                                    let local_decl = &self.mir.local_decls[*l];
-                                    if local_decl.name.is_none() {
-                                        local_decl.source_info.span
-                                    } else {
-                                        span
-                                    }
-                                },
-                                _ => span,
-                            };
-                            return (Call, function_span);
+                    LaterUseKind::Other
+                };
+
+                (kind, span)
+            }
+        }
+    }
+
+    /// Check if a borrowed value was captured by a trait object. We do this by
+    /// looking forward in the MIR from the reserve location and checking if we see
+    /// a unsized cast to a trait object on our data.
+    fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
+        // Start at the reserve location, find the place that we want to see cast to a trait object.
+        let location = borrow.reserve_location;
+        let block = &self.mir[location.block];
+        let stmt = block.statements.get(location.statement_index);
+        debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt);
+
+        // We make a `queue` vector that has the locations we want to visit. As of writing, this
+        // will only ever have one item at any given time, but by using a vector, we can pop from
+        // it which simplifies the termination logic.
+        let mut queue = vec![location];
+        let mut target = if let Some(&Statement {
+            kind: StatementKind::Assign(Place::Local(local), _),
+            ..
+        }) = stmt {
+            local
+        } else {
+            return false;
+        };
+
+        debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue);
+        while let Some(current_location) = queue.pop() {
+            debug!("was_captured_by_trait: target={:?}", target);
+            let block = &self.mir[current_location.block];
+            // We need to check the current location to find out if it is a terminator.
+            let is_terminator = current_location.statement_index == block.statements.len();
+            if !is_terminator {
+                let stmt = &block.statements[current_location.statement_index];
+                debug!("was_captured_by_trait_object: stmt={:?}", stmt);
+
+                // The only kind of statement that we care about is assignments...
+                if let StatementKind::Assign(
+                    place,
+                    box rvalue,
+                ) = &stmt.kind {
+                    let into = match place {
+                        Place::Local(into) => into,
+                        Place::Projection(box Projection {
+                            base: Place::Local(into),
+                            elem: ProjectionElem::Deref,
+                        }) => into,
+                        _ =>  {
+                            // Continue at the next location.
+                            queue.push(current_location.successor_within_block());
+                            continue;
                         },
-                        _ => Other,
+                    };
+
+                    match rvalue {
+                        // If we see a use, we should check whether it is our data, and if so
+                        // update the place that we're looking for to that new place.
+                        Rvalue::Use(operand) => match operand {
+                            Operand::Copy(Place::Local(from)) |
+                            Operand::Move(Place::Local(from)) if *from == target => {
+                                target = *into;
+                            },
+                            _ => {},
+                        },
+                        // If we see a unsized cast, then if it is our data we should check
+                        // whether it is being cast to a trait object.
+                        Rvalue::Cast(CastKind::Unsize, operand, ty) => match operand {
+                            Operand::Copy(Place::Local(from)) |
+                            Operand::Move(Place::Local(from)) if *from == target => {
+                                debug!("was_captured_by_trait_object: ty={:?}", ty);
+                                // Check the type for a trait object.
+                                match ty.sty {
+                                    // `&dyn Trait`
+                                    ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true,
+                                    // `Box<dyn Trait>`
+                                    _ if ty.is_box() && ty.boxed_ty().is_trait() =>
+                                        return true,
+                                    // `dyn Trait`
+                                    _ if ty.is_trait() => return true,
+                                    // Anything else.
+                                    _ => return false,
+                                }
+                            },
+                            _ => return false,
+                        },
+                        _ => {},
                     }
-                }, span)
+                }
+
+                // Continue at the next location.
+                queue.push(current_location.successor_within_block());
+            } else {
+                // The only thing we need to do for terminators is progress to the next block.
+                let terminator = block.terminator();
+                debug!("was_captured_by_trait_object: terminator={:?}", terminator);
+
+                match &terminator.kind {
+                    TerminatorKind::Call {
+                        destination: Some((Place::Local(dest), block)),
+                        args,
+                        ..
+                    } => {
+                        debug!(
+                            "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
+                            target, dest, args
+                        );
+                        // Check if one of the arguments to this function is the target place.
+                        let found_target = args.iter().any(|arg| {
+                            if let Operand::Move(Place::Local(potential)) = arg {
+                                *potential == target
+                            } else {
+                                false
+                            }
+                        });
+
+                        // If it is, follow this to the next block and update the target.
+                        if found_target {
+                            target = *dest;
+                            queue.push(block.start_location());
+                        }
+                    },
+                    _ => {},
+                }
             }
+
+            debug!("was_captured_by_trait: queue={:?}", queue);
         }
+
+        // We didn't find anything and ran out of locations to check.
+        false
     }
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index 43dc68fdb3b..8191dd720e7 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -10,7 +10,9 @@
 
 use borrow_check::nll::constraints::{OutlivesConstraint};
 use borrow_check::nll::region_infer::RegionInferenceContext;
+use borrow_check::nll::region_infer::error_reporting::region_name::RegionNameSource;
 use borrow_check::nll::type_check::Locations;
+use borrow_check::nll::universal_regions::DefiningTy;
 use rustc::hir::def_id::DefId;
 use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc::infer::InferCtxt;
@@ -263,6 +265,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
                fr_is_local, outlived_fr_is_local, category);
         match (category, fr_is_local, outlived_fr_is_local) {
+            (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) =>
+                self.report_fnmut_error(mir, infcx, mir_def_id, fr, outlived_fr, span,
+                                        errors_buffer),
             (ConstraintCategory::Assignment, true, false) |
             (ConstraintCategory::CallArgument, true, false) =>
                 self.report_escaping_data_error(mir, infcx, mir_def_id, fr, outlived_fr,
@@ -274,6 +279,85 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         };
     }
 
+    /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
+    /// This function expects `fr` to be local and `outlived_fr` to not be local.
+    ///
+    /// ```text
+    /// error: captured variable cannot escape `FnMut` closure body
+    ///   --> $DIR/issue-53040.rs:15:8
+    ///    |
+    /// LL |     || &mut v;
+    ///    |     -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
+    ///    |     |
+    ///    |     inferred to be a `FnMut` closure
+    ///    |
+    ///    = note: `FnMut` closures only have access to their captured variables while they are
+    ///            executing...
+    ///    = note: ...therefore, returned references to captured variables will escape the closure
+    /// ```
+    fn report_fnmut_error(
+        &self,
+        mir: &Mir<'tcx>,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        mir_def_id: DefId,
+        _fr: RegionVid,
+        outlived_fr: RegionVid,
+        span: Span,
+        errors_buffer: &mut Vec<Diagnostic>,
+    ) {
+        let mut diag = infcx.tcx.sess.struct_span_err(
+            span,
+            "captured variable cannot escape `FnMut` closure body",
+        );
+
+        // We should check if the return type of this closure is in fact a closure - in that
+        // case, we can special case the error further.
+        let return_type_is_closure = self.universal_regions.unnormalized_output_ty.is_closure();
+        let message = if return_type_is_closure {
+            "returns a closure that contains a reference to a captured variable, which then \
+             escapes the closure body"
+        } else {
+            "returns a reference to a captured variable which escapes the closure body"
+        };
+
+        diag.span_label(
+            span,
+            message,
+        );
+
+        match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1).source {
+            RegionNameSource::NamedEarlyBoundRegion(fr_span) |
+            RegionNameSource::NamedFreeRegion(fr_span) |
+            RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _) |
+            RegionNameSource::CannotMatchHirTy(fr_span, _) |
+            RegionNameSource::MatchedHirTy(fr_span) |
+            RegionNameSource::MatchedAdtAndSegment(fr_span) |
+            RegionNameSource::AnonRegionFromUpvar(fr_span, _) |
+            RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
+                diag.span_label(fr_span, "inferred to be a `FnMut` closure");
+            },
+            _ => {},
+        }
+
+        diag.note("`FnMut` closures only have access to their captured variables while they are \
+                   executing...");
+        diag.note("...therefore, they cannot allow references to captured variables to escape");
+
+        diag.buffer(errors_buffer);
+    }
+
+    /// Reports a error specifically for when data is escaping a closure.
+    ///
+    /// ```text
+    /// error: borrowed data escapes outside of function
+    ///   --> $DIR/lifetime-bound-will-change-warning.rs:44:5
+    ///    |
+    /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
+    ///    |              - `x` is a reference that is only valid in the function body
+    /// LL |     // but ref_obj will not, so warn.
+    /// LL |     ref_obj(x)
+    ///    |     ^^^^^^^^^^ `x` escapes the function body here
+    /// ```
     fn report_escaping_data_error(
         &self,
         mir: &Mir<'tcx>,
@@ -305,31 +389,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             span, &format!("borrowed data escapes outside of {}", escapes_from),
         );
 
-        if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span {
-            if let Some(name) = outlived_fr_name {
-                diag.span_label(
-                    outlived_fr_span,
-                    format!("`{}` is declared here, outside of the {} body", name, escapes_from),
-                );
-            }
+        if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
+            diag.span_label(
+                outlived_fr_span,
+                format!(
+                    "`{}` is declared here, outside of the {} body",
+                    outlived_fr_name, escapes_from
+                ),
+            );
         }
 
-        if let Some((fr_name, fr_span)) = fr_name_and_span {
-            if let Some(name) = fr_name {
-                diag.span_label(
-                    fr_span,
-                    format!("`{}` is a reference that is only valid in the {} body",
-                            name, escapes_from),
-                );
+        if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
+            diag.span_label(
+                fr_span,
+                format!(
+                    "`{}` is a reference that is only valid in the {} body",
+                    fr_name, escapes_from
+                ),
+            );
 
-                diag.span_label(span, format!("`{}` escapes the {} body here",
-                                               name, escapes_from));
-            }
+            diag.span_label(span, format!("`{}` escapes the {} body here", fr_name, escapes_from));
         }
 
         diag.buffer(errors_buffer);
     }
 
+    /// Reports a region inference error for the general case with named/synthesized lifetimes to
+    /// explain what is happening.
+    ///
+    /// ```text
+    /// error: unsatisfied lifetime constraints
+    ///   --> $DIR/regions-creating-enums3.rs:17:5
+    ///    |
+    /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
+    ///    |                -- -- lifetime `'b` defined here
+    ///    |                |
+    ///    |                lifetime `'a` defined here
+    /// LL |     ast::add(x, y)
+    ///    |     ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
+    ///    |                    is returning data with lifetime `'b`
+    /// ```
     fn report_general_error(
         &self,
         mir: &Mir<'tcx>,
@@ -380,6 +479,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         diag.buffer(errors_buffer);
     }
 
+    /// Adds a suggestion to errors where a `impl Trait` is returned.
+    ///
+    /// ```text
+    /// help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as
+    ///       a constraint
+    ///    |
+    /// LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
+    ///    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    /// ```
     fn add_static_impl_trait_suggestion(
         &self,
         infcx: &InferCtxt<'_, '_, 'tcx>,
@@ -500,4 +608,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             .get(&(constraint.sup, constraint.sub));
         *opt_span_category.unwrap_or(&(constraint.category, mir.source_info(loc).span))
     }
+
+    /// Returns `true` if a closure is inferred to be an `FnMut` closure.
+    crate fn is_closure_fn_mut(
+        &self,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        fr: RegionVid,
+    ) -> bool {
+        if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
+            if let ty::BoundRegion::BrEnv = free_region.bound_region {
+                if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty {
+                    let closure_kind_ty = substs.closure_kind_ty(def_id, infcx.tcx);
+                    return Some(ty::ClosureKind::FnMut) == closure_kind_ty.to_opt_closure_kind();
+                }
+            }
+        }
+
+        false
+    }
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index 3a545d9adbf..65ba2f537bf 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -27,8 +27,8 @@ use syntax_pos::symbol::InternedString;
 
 #[derive(Debug)]
 crate struct RegionName {
-    name: InternedString,
-    source: RegionNameSource,
+    crate name: InternedString,
+    crate source: RegionNameSource,
 }
 
 #[derive(Debug)]
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs
index 57ff0f4c10a..73fa1b0cfb7 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs
@@ -50,11 +50,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             .defining_ty
             .upvar_tys(tcx)
             .position(|upvar_ty| {
-                debug!(
-                    "get_upvar_index_for_region: upvar_ty = {:?}",
-                    upvar_ty,
-                );
-                tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr)
+                debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
+                tcx.any_free_region_meets(&upvar_ty, |r| {
+                    let r = r.to_region_vid();
+                    debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr);
+                    r == fr
+                })
             })?;
 
         let upvar_ty = self
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 36eb695186c..e11f452e16b 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -310,12 +310,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.super_local_decl(local, local_decl);
         self.sanitize_type(local_decl, local_decl.ty);
 
-        if let Some(user_ty) = local_decl.user_ty {
+        if let Some((user_ty, span)) = local_decl.user_ty {
             if let Err(terr) = self.cx.relate_type_and_user_type(
                 local_decl.ty,
                 ty::Variance::Invariant,
                 user_ty,
-                Locations::All(local_decl.source_info.span),
+                Locations::All(span),
                 ConstraintCategory::TypeAnnotation,
             ) {
                 span_mirbug!(
@@ -970,7 +970,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        relate_tys::relate_type_and_user_type(
+        let ty = relate_tys::relate_type_and_user_type(
             self.infcx,
             a,
             v,
@@ -978,7 +978,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             locations,
             category,
             self.borrowck_context.as_mut().map(|x| &mut **x),
-        )
+        )?;
+        self.prove_predicate(
+            ty::Predicate::WellFormed(ty),
+            locations,
+            category,
+        );
+        Ok(())
     }
 
     fn eq_opaque_type_and_type(
diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
index 41aab02d1e8..1e279aef079 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
@@ -10,7 +10,7 @@
 
 use borrow_check::nll::constraints::OutlivesConstraint;
 use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
-use rustc::infer::canonical::{Canonical, CanonicalVarInfos};
+use rustc::infer::canonical::{Canonical, CanonicalVarInfos, CanonicalVarValues};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc::mir::ConstraintCategory;
 use rustc::traits::query::Fallible;
@@ -70,7 +70,7 @@ pub(super) fn relate_type_and_user_type<'tcx>(
     locations: Locations,
     category: ConstraintCategory,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
-) -> Fallible<()> {
+) -> Fallible<Ty<'tcx>> {
     debug!(
         "sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
         a, b, locations
@@ -85,13 +85,24 @@ pub(super) fn relate_type_and_user_type<'tcx>(
     // variance to get the right relationship.
     let v1 = ty::Contravariant.xform(v);
 
-    TypeRelating::new(
+    let mut type_relating = TypeRelating::new(
         infcx.tcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         v1,
         b_variables,
-    ).relate(&b_value, &a)?;
-    Ok(())
+    );
+    type_relating.relate(&b_value, &a)?;
+
+    Ok(b.substitute(
+        infcx.tcx,
+        &CanonicalVarValues {
+            var_values: type_relating
+                .canonical_var_values
+                .into_iter()
+                .map(|x| x.expect("unsubstituted canonical variable"))
+                .collect(),
+        },
+    ))
 }
 
 struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index c2a7172d54c..394fa4e077c 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -292,30 +292,32 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     ..
                 },
                 user_ty: ascription_user_ty,
+                user_ty_span,
             } => {
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
                 unpack!(block = self.into(&place, block, initializer));
 
-                let source_info = self.source_info(irrefutable_pat.span);
+                // Inject a fake read, see comments on `FakeReadCause::ForLet`.
+                let pattern_source_info = self.source_info(irrefutable_pat.span);
                 self.cfg.push(
                     block,
                     Statement {
-                        source_info,
-                        kind: StatementKind::AscribeUserType(
-                            place.clone(),
-                            ty::Variance::Invariant,
-                            ascription_user_ty,
-                        ),
+                        source_info: pattern_source_info,
+                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()),
                     },
                 );
 
-                // Inject a fake read, see comments on `FakeReadCause::ForLet`.
+                let ty_source_info = self.source_info(user_ty_span);
                 self.cfg.push(
                     block,
                     Statement {
-                        source_info,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()),
+                        source_info: ty_source_info,
+                        kind: StatementKind::AscribeUserType(
+                            place.clone(),
+                            ty::Variance::Invariant,
+                            ascription_user_ty,
+                        ),
                     },
                 );
 
@@ -489,7 +491,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn visit_bindings(
         &mut self,
         pattern: &Pattern<'tcx>,
-        mut pattern_user_ty: Option<CanonicalTy<'tcx>>,
+        mut pattern_user_ty: Option<(CanonicalTy<'tcx>, Span)>,
         f: &mut impl FnMut(
             &mut Self,
             Mutability,
@@ -498,7 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             NodeId,
             Span,
             Ty<'tcx>,
-            Option<CanonicalTy<'tcx>>,
+            Option<(CanonicalTy<'tcx>, Span)>,
         ),
     ) {
         match *pattern.kind {
@@ -549,16 +551,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // FIXME(#47184): extract or handle `pattern_user_ty` somehow
                 self.visit_bindings(subpattern, None, f);
             }
-            PatternKind::AscribeUserType { ref subpattern, user_ty } => {
+            PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => {
                 // This corresponds to something like
                 //
                 // ```
-                // let (p1: T1): T2 = ...;
+                // let A::<'a>(_): A<'static> = ...;
                 // ```
                 //
-                // Not presently possible, though maybe someday.
-                assert!(pattern_user_ty.is_none());
-                self.visit_bindings(subpattern, Some(user_ty), f)
+                // FIXME(#47184): handle `pattern_user_ty` somehow
+                self.visit_bindings(subpattern, Some((user_ty, user_ty_span)), f)
             }
             PatternKind::Leaf { ref subpatterns }
             | PatternKind::Variant {
@@ -1469,7 +1470,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         num_patterns: usize,
         var_id: NodeId,
         var_ty: Ty<'tcx>,
-        user_var_ty: Option<CanonicalTy<'tcx>>,
+        user_var_ty: Option<(CanonicalTy<'tcx>, Span)>,
         has_guard: ArmHasGuard,
         opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
         pat_span: Span,
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 14da8e90838..494e7c03c3e 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -63,9 +63,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                  candidate: &mut Candidate<'pat, 'tcx>)
                                  -> Result<(), MatchPair<'pat, 'tcx>> {
         match *match_pair.pattern.kind {
-            PatternKind::AscribeUserType { ref subpattern, user_ty } => {
+            PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => {
                 candidate.ascriptions.push(Ascription {
-                    span: match_pair.pattern.span,
+                    span: user_ty_span,
                     user_ty,
                     source: match_pair.place.clone(),
                 });
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 0c669b9ec31..2cfd058831f 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -12,6 +12,9 @@
 
 use std::fmt;
 use std::error::Error;
+use std::borrow::{Borrow, Cow};
+use std::hash::Hash;
+use std::collections::hash_map::Entry;
 
 use rustc::hir::{self, def_id::DefId};
 use rustc::mir::interpret::ConstEvalErr;
@@ -20,16 +23,17 @@ use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
 use rustc::ty::layout::{self, LayoutOf, TyLayout};
 use rustc::ty::subst::Subst;
 use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::fx::FxHashMap;
 
 use syntax::ast::Mutability;
 use syntax::source_map::{Span, DUMMY_SP};
 
 use rustc::mir::interpret::{
     EvalResult, EvalError, EvalErrorKind, GlobalId,
-    Scalar, Allocation, ConstValue,
+    Scalar, Allocation, AllocId, ConstValue,
 };
 use interpret::{self,
-    Place, PlaceTy, MemPlace, OpTy, Operand, Value,
+    PlaceTy, MemPlace, OpTy, Operand, Value,
     EvalContext, StackPopCleanup, MemoryKind,
     snapshot,
 };
@@ -51,13 +55,14 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
     let param_env = tcx.param_env(instance.def_id());
     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
     // insert a stack frame so any queries have the correct substs
+    // cannot use `push_stack_frame`; if we do `const_prop` explodes
     ecx.stack.push(interpret::Frame {
         block: mir::START_BLOCK,
         locals: IndexVec::new(),
         instance,
         span,
         mir,
-        return_place: Place::null(tcx),
+        return_place: None,
         return_to_block: StackPopCleanup::Goto(None), // never pop
         stmt: 0,
     });
@@ -78,7 +83,7 @@ pub fn mk_eval_cx<'a, 'tcx>(
         instance,
         mir.span,
         mir,
-        Place::null(tcx),
+        None,
         StackPopCleanup::Goto(None), // never pop
     )?;
     Ok(ecx)
@@ -118,9 +123,9 @@ pub fn op_to_const<'tcx>(
         }
     };
     let val = match normalized_op {
-        Err(MemPlace { ptr, align, extra }) => {
+        Err(MemPlace { ptr, align, meta }) => {
             // extract alloc-offset pair
-            assert!(extra.is_none());
+            assert!(meta.is_none());
             let ptr = ptr.to_ptr()?;
             let alloc = ecx.memory.get(ptr.alloc_id)?;
             assert!(alloc.align.abi() >= align.abi());
@@ -183,7 +188,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         cid.instance,
         mir.span,
         mir,
-        Place::Ptr(*ret),
+        Some(ret.into()),
         StackPopCleanup::None { cleanup: false },
     )?;
 
@@ -264,6 +269,67 @@ impl<'a, 'mir, 'tcx> CompileTimeInterpreter<'a, 'mir, 'tcx> {
     }
 }
 
+impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
+    #[inline(always)]
+    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
+        where K: Borrow<Q>
+    {
+        FxHashMap::contains_key(self, k)
+    }
+
+    #[inline(always)]
+    fn insert(&mut self, k: K, v: V) -> Option<V>
+    {
+        FxHashMap::insert(self, k, v)
+    }
+
+    #[inline(always)]
+    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
+        where K: Borrow<Q>
+    {
+        FxHashMap::remove(self, k)
+    }
+
+    #[inline(always)]
+    fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
+        self.iter()
+            .filter_map(move |(k, v)| f(k, &*v))
+            .collect()
+    }
+
+    #[inline(always)]
+    fn get_or<E>(
+        &self,
+        k: K,
+        vacant: impl FnOnce() -> Result<V, E>
+    ) -> Result<&V, E>
+    {
+        match self.get(&k) {
+            Some(v) => Ok(v),
+            None => {
+                vacant()?;
+                bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading")
+            }
+        }
+    }
+
+    #[inline(always)]
+    fn get_mut_or<E>(
+        &mut self,
+        k: K,
+        vacant: impl FnOnce() -> Result<V, E>
+    ) -> Result<&mut V, E>
+    {
+        match self.entry(k) {
+            Entry::Occupied(e) => Ok(e.into_mut()),
+            Entry::Vacant(e) => {
+                let v = vacant()?;
+                Ok(e.insert(v))
+            }
+        }
+    }
+}
+
 type CompileTimeEvalContext<'a, 'mir, 'tcx> =
     EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>;
 
@@ -272,9 +338,16 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
 {
     type MemoryData = ();
     type MemoryKinds = !;
+    type PointerTag = ();
 
-    const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
-    const ENFORCE_VALIDITY: bool = false; // for now, we don't
+    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
+
+    const STATIC_KIND: Option<!> = None; // no copying of statics allowed
+
+    #[inline(always)]
+    fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
+        false // for now, we don't enforce validity
+    }
 
     fn find_fn(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
@@ -339,10 +412,18 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     fn find_foreign_static(
         _tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
         _def_id: DefId,
-    ) -> EvalResult<'tcx, &'tcx Allocation> {
+    ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
         err!(ReadForeignStatic)
     }
 
+    #[inline(always)]
+    fn static_with_default_tag(
+        alloc: &'_ Allocation
+    ) -> Cow<'_, Allocation<Self::PointerTag>> {
+        // We do not use a tag so we can just cheaply forward the reference
+        Cow::Borrowed(alloc)
+    }
+
     fn box_alloc(
         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _dest: PlaceTy<'tcx>,
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 2ab0a57a855..022c606a0f8 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -92,6 +92,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                     span: pattern.span,
                                     kind: Box::new(PatternKind::AscribeUserType {
                                         user_ty: *user_ty,
+                                        user_ty_span: ty.span,
                                         subpattern: pattern
                                     })
                                 };
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 04090e5087f..0238a23895e 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -71,6 +71,7 @@ pub enum PatternKind<'tcx> {
     AscribeUserType {
         user_ty: CanonicalTy<'tcx>,
         subpattern: Pattern<'tcx>,
+        user_ty_span: Span,
     },
 
     /// x, ref x, x @ P, etc
@@ -692,6 +693,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
             kind = PatternKind::AscribeUserType {
                 subpattern,
                 user_ty,
+                user_ty_span: span,
             };
         }
 
@@ -1015,9 +1017,11 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
             PatternKind::AscribeUserType {
                 ref subpattern,
                 user_ty,
+                user_ty_span,
             } => PatternKind::AscribeUserType {
                 subpattern: subpattern.fold_with(folder),
                 user_ty: user_ty.fold_with(folder),
+                user_ty_span,
             },
             PatternKind::Binding {
                 mutability,
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index c6b527f4229..f4ddfa5293e 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -33,9 +33,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     pub fn cast(
         &mut self,
-        src: OpTy<'tcx>,
+        src: OpTy<'tcx, M::PointerTag>,
         kind: CastKind,
-        dest: PlaceTy<'tcx>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         let src_layout = src.layout;
         let dst_layout = dest.layout;
@@ -143,10 +143,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     pub(super) fn cast_scalar(
         &self,
-        val: Scalar,
+        val: Scalar<M::PointerTag>,
         src_layout: TyLayout<'tcx>,
         dest_layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, Scalar> {
+    ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
         use rustc::ty::TyKind::*;
         trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
 
@@ -182,7 +182,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         v: u128,
         src_layout: TyLayout<'tcx>,
         dest_layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, Scalar> {
+    ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
         let signed = src_layout.abi.is_signed();
         let v = if signed {
             self.sign_extend(v, src_layout)
@@ -239,7 +239,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         bits: u128,
         fty: FloatTy,
         dest_ty: Ty<'tcx>
-    ) -> EvalResult<'tcx, Scalar> {
+    ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
         use rustc::ty::TyKind::*;
         use rustc_apfloat::FloatConvert;
         match dest_ty.sty {
@@ -283,7 +283,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         }
     }
 
-    fn cast_from_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
+    fn cast_from_ptr(
+        &self,
+        ptr: Pointer<M::PointerTag>,
+        ty: Ty<'tcx>
+    ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
         use rustc::ty::TyKind::*;
         match ty.sty {
             // Casting to a reference or fn pointer is not permitted by rustc,
@@ -298,8 +302,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     fn unsize_into_ptr(
         &mut self,
-        src: OpTy<'tcx>,
-        dest: PlaceTy<'tcx>,
+        src: OpTy<'tcx, M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
         // The pointee types
         sty: Ty<'tcx>,
         dty: Ty<'tcx>,
@@ -318,11 +322,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 // For now, upcasts are limited to changes in marker
                 // traits, and hence never actually require an actual
                 // change to the vtable.
-                self.copy_op(src, dest)
+                let val = self.read_value(src)?;
+                self.write_value(*val, dest)
             }
             (_, &ty::Dynamic(ref data, _)) => {
                 // Initial cast from sized to dyn trait
-                let trait_ref = data.principal().unwrap().with_self_ty(
+                let trait_ref = data.principal().with_self_ty(
                     *self.tcx,
                     src_pointee_ty,
                 );
@@ -339,8 +344,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     fn unsize_into(
         &mut self,
-        src: OpTy<'tcx>,
-        dest: PlaceTy<'tcx>,
+        src: OpTy<'tcx, M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         match (&src.layout.ty.sty, &dest.layout.ty.sty) {
             (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index e15a721731e..85a8376134a 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -31,7 +31,7 @@ use rustc::mir::interpret::{
 use syntax::source_map::{self, Span};
 
 use super::{
-    Value, Operand, MemPlace, MPlaceTy, Place, ScalarMaybeUndef,
+    Value, Operand, MemPlace, MPlaceTy, Place, PlaceTy, ScalarMaybeUndef,
     Memory, Machine
 };
 
@@ -49,12 +49,12 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
     pub memory: Memory<'a, 'mir, 'tcx, M>,
 
     /// The virtual call stack.
-    pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
+    pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag>>,
 }
 
 /// A stack frame.
 #[derive(Clone)]
-pub struct Frame<'mir, 'tcx: 'mir> {
+pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
     ////////////////////////////////////////////////////////////////////////////////
     // Function and callsite information
     ////////////////////////////////////////////////////////////////////////////////
@@ -73,15 +73,16 @@ pub struct Frame<'mir, 'tcx: 'mir> {
     /// Work to perform when returning from this function
     pub return_to_block: StackPopCleanup,
 
-    /// The location where the result of the current stack frame should be written to.
-    pub return_place: Place,
+    /// The location where the result of the current stack frame should be written to,
+    /// and its layout in the caller.
+    pub return_place: Option<PlaceTy<'tcx, Tag>>,
 
     /// The list of locals for this stack frame, stored in order as
     /// `[return_ptr, arguments..., variables..., temporaries...]`.
     /// The locals are stored as `Option<Value>`s.
     /// `None` represents a local that is currently dead, while a live local
     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
-    pub locals: IndexVec<mir::Local, LocalValue<AllocId>>,
+    pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
 
     ////////////////////////////////////////////////////////////////////////////////
     // Current position within the function
@@ -97,7 +98,8 @@ pub struct Frame<'mir, 'tcx: 'mir> {
 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
 pub enum StackPopCleanup {
     /// Jump to the next block in the caller, or cause UB if None (that's a function
-    /// that may never return).
+    /// that may never return). Also store layout of return place so
+    /// we can validate it at that layout.
     Goto(Option<mir::BasicBlock>),
     /// Just do nohing: Used by Main and for the box_alloc hook in miri.
     /// `cleanup` says whether locals are deallocated.  Static computation
@@ -108,24 +110,24 @@ pub enum StackPopCleanup {
 
 // State of a local variable
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub enum LocalValue<Id=AllocId> {
+pub enum LocalValue<Tag=(), Id=AllocId> {
     Dead,
     // Mostly for convenience, we re-use the `Operand` type here.
     // This is an optimization over just always having a pointer here;
     // we can thus avoid doing an allocation when the local just stores
     // immediate values *and* never has its address taken.
-    Live(Operand<Id>),
+    Live(Operand<Tag, Id>),
 }
 
-impl<'tcx> LocalValue {
-    pub fn access(&self) -> EvalResult<'tcx, &Operand> {
+impl<'tcx, Tag> LocalValue<Tag> {
+    pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
         match self {
             LocalValue::Dead => err!(DeadLocal),
             LocalValue::Live(ref val) => Ok(val),
         }
     }
 
-    pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand> {
+    pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> {
         match self {
             LocalValue::Dead => err!(DeadLocal),
             LocalValue::Live(ref mut val) => Ok(val),
@@ -218,7 +220,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
         &mut self.memory
     }
 
-    pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
+    pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag>] {
         &self.stack
     }
 
@@ -230,7 +232,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
 
     /// Mark a storage as live, killing the previous content and returning it.
     /// Remember to deallocate that!
-    pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, LocalValue> {
+    pub fn storage_live(
+        &mut self,
+        local: mir::Local
+    ) -> EvalResult<'tcx, LocalValue<M::PointerTag>> {
         assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
         trace!("{:?} is now live", local);
 
@@ -242,14 +247,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
 
     /// Returns the old value of the local.
     /// Remember to deallocate that!
-    pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue {
+    pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
         assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
         trace!("{:?} is now dead", local);
 
         mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead)
     }
 
-    pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
+    pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value<M::PointerTag>> {
         let ptr = self.memory.allocate_static_bytes(s.as_bytes());
         Ok(Value::new_slice(Scalar::Ptr(ptr), s.len() as u64, self.tcx.tcx))
     }
@@ -327,22 +332,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
     }
 
     /// Return the actual dynamic size and alignment of the place at the given type.
-    /// Only the "extra" (metadata) part of the place matters.
+    /// Only the "meta" (metadata) part of the place matters.
+    /// This can fail to provide an answer for extern types.
     pub(super) fn size_and_align_of(
         &self,
-        metadata: Option<Scalar>,
+        metadata: Option<Scalar<M::PointerTag>>,
         layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, (Size, Align)> {
-        let metadata = match metadata {
-            None => {
-                assert!(!layout.is_unsized());
-                return Ok(layout.size_and_align())
-            }
-            Some(metadata) => {
-                assert!(layout.is_unsized());
-                metadata
-            }
-        };
+    ) -> EvalResult<'tcx, Option<(Size, Align)>> {
+        if !layout.is_unsized() {
+            return Ok(Some(layout.size_and_align()));
+        }
         match layout.ty.sty {
             ty::Adt(..) | ty::Tuple(..) => {
                 // First get the size of all statically known fields.
@@ -362,9 +361,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
                 );
 
                 // Recurse to get the size of the dynamically sized field (must be
-                // the last field).
+                // the last field).  Can't have foreign types here, how would we
+                // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1)?;
-                let (unsized_size, unsized_align) = self.size_and_align_of(Some(metadata), field)?;
+                let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)?
+                    .expect("Fields cannot be extern types");
 
                 // FIXME (#26403, #27023): We should be adding padding
                 // to `sized_size` (to accommodate the `unsized_align`
@@ -391,18 +392,22 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
                 //
                 //   `(size + (align-1)) & -align`
 
-                Ok((size.abi_align(align), align))
+                Ok(Some((size.abi_align(align), align)))
             }
             ty::Dynamic(..) => {
-                let vtable = metadata.to_ptr()?;
+                let vtable = metadata.expect("dyn trait fat ptr must have vtable").to_ptr()?;
                 // the second entry in the vtable is the dynamic size of the object.
-                self.read_size_and_align_from_vtable(vtable)
+                Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
             }
 
             ty::Slice(_) | ty::Str => {
-                let len = metadata.to_usize(self)?;
+                let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?;
                 let (elem_size, align) = layout.field(self, 0)?.size_and_align();
-                Ok((elem_size * len, align))
+                Ok(Some((elem_size * len, align)))
+            }
+
+            ty::Foreign(_) => {
+                Ok(None)
             }
 
             _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
@@ -411,9 +416,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
     #[inline]
     pub fn size_and_align_of_mplace(
         &self,
-        mplace: MPlaceTy<'tcx>
-    ) -> EvalResult<'tcx, (Size, Align)> {
-        self.size_and_align_of(mplace.extra, mplace.layout)
+        mplace: MPlaceTy<'tcx, M::PointerTag>
+    ) -> EvalResult<'tcx, Option<(Size, Align)>> {
+        self.size_and_align_of(mplace.meta, mplace.layout)
     }
 
     pub fn push_stack_frame(
@@ -421,7 +426,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
         instance: ty::Instance<'tcx>,
         span: source_map::Span,
         mir: &'mir mir::Mir<'tcx>,
-        return_place: Place,
+        return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> EvalResult<'tcx> {
         ::log_settings::settings().indentation += 1;
@@ -506,20 +511,46 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
             }
             StackPopCleanup::None { cleanup } => {
                 if !cleanup {
-                    // Leak the locals
+                    // Leak the locals. Also skip validation, this is only used by
+                    // static/const computation which does its own (stronger) final
+                    // validation.
                     return Ok(());
                 }
             }
         }
-        // deallocate all locals that are backed by an allocation
+        // Deallocate all locals that are backed by an allocation.
         for local in frame.locals {
             self.deallocate_local(local)?;
         }
+        // Validate the return value.
+        if let Some(return_place) = frame.return_place {
+            if M::enforce_validity(self) {
+                // Data got changed, better make sure it matches the type!
+                // It is still possible that the return place held invalid data while
+                // the function is running, but that's okay because nobody could have
+                // accessed that same data from the "outside" to observe any broken
+                // invariant -- that is, unless a function somehow has a ptr to
+                // its return place... but the way MIR is currently generated, the
+                // return place is always a local and then this cannot happen.
+                self.validate_operand(
+                    self.place_to_op(return_place)?,
+                    &mut vec![],
+                    None,
+                    /*const_mode*/false,
+                )?;
+            }
+        } else {
+            // Uh, that shouln't happen... the function did not intend to return
+            return err!(Unreachable);
+        }
 
         Ok(())
     }
 
-    pub(super) fn deallocate_local(&mut self, local: LocalValue) -> EvalResult<'tcx> {
+    pub(super) fn deallocate_local(
+        &mut self,
+        local: LocalValue<M::PointerTag>,
+    ) -> EvalResult<'tcx> {
         // FIXME: should we tell the user that there was a local which was never written to?
         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
             trace!("deallocating local");
@@ -541,12 +572,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
     }
 
     #[inline(always)]
-    pub fn frame(&self) -> &Frame<'mir, 'tcx> {
+    pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag> {
         self.stack.last().expect("no call frames exist")
     }
 
     #[inline(always)]
-    pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
+    pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag> {
         self.stack.last_mut().expect("no call frames exist")
     }
 
@@ -562,7 +593,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
         }
     }
 
-    pub fn dump_place(&self, place: Place) {
+    pub fn dump_place(&self, place: Place<M::PointerTag>) {
         // Debug output
         if !log_enabled!(::log::Level::Trace) {
             return;
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 5fee49ba2fc..5fa0fef3693 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -25,11 +25,11 @@ use super::{
 };
 
 
-fn numeric_intrinsic<'tcx>(
+fn numeric_intrinsic<'tcx, Tag>(
     name: &str,
     bits: u128,
     kind: Primitive,
-) -> EvalResult<'tcx, Scalar> {
+) -> EvalResult<'tcx, Scalar<Tag>> {
     let size = match kind {
         Primitive::Int(integer, _) => integer.size(),
         _ => bug!("invalid `{}` argument: {:?}", name, bits),
@@ -51,8 +51,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn emulate_intrinsic(
         &mut self,
         instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx>],
-        dest: PlaceTy<'tcx>,
+        args: &[OpTy<'tcx, M::PointerTag>],
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx, bool> {
         let substs = instance.substs;
 
@@ -151,11 +151,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 self.write_scalar(val, dest)?;
             }
             "transmute" => {
-                // Go through an allocation, to make sure the completely different layouts
-                // do not pose a problem.  (When the user transmutes through a union,
-                // there will not be a layout mismatch.)
-                let dest = self.force_allocation(dest)?;
-                self.copy_op(args[0], dest.into())?;
+                self.copy_op_transmute(args[0], dest)?;
             }
 
             _ => return Ok(false),
@@ -169,8 +165,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn hook_fn(
         &mut self,
         instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx>],
-        dest: Option<PlaceTy<'tcx>>,
+        args: &[OpTy<'tcx, M::PointerTag>],
+        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
     ) -> EvalResult<'tcx, bool> {
         let def_id = instance.def_id();
         // Some fn calls are actually BinOp intrinsics
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index f90a7efce47..560698f3f57 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -12,17 +12,55 @@
 //! This separation exists to ensure that no fancy miri features like
 //! interpreting common C functions leak into CTFE.
 
+use std::borrow::{Borrow, Cow};
+use std::hash::Hash;
+
 use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
+use rustc::mir::interpret::{Allocation, AllocId, EvalResult, Scalar};
 use rustc::mir;
 use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
 
-use super::{EvalContext, PlaceTy, OpTy};
+use super::{EvalContext, PlaceTy, OpTy, MemoryKind};
+
+/// The functionality needed by memory to manage its allocations
+pub trait AllocMap<K: Hash + Eq, V> {
+    /// Test if the map contains the given key.
+    /// Deliberately takes `&mut` because that is sufficient, and some implementations
+    /// can be more efficient then (using `RefCell::get_mut`).
+    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
+        where K: Borrow<Q>;
+
+    /// Insert new entry into the map.
+    fn insert(&mut self, k: K, v: V) -> Option<V>;
+
+    /// Remove entry from the map.
+    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
+        where K: Borrow<Q>;
+
+    /// Return data based the keys and values in the map.
+    fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;
+
+    /// Return a reference to entry `k`.  If no such entry exists, call
+    /// `vacant` and either forward its error, or add its result to the map
+    /// and return a reference to *that*.
+    fn get_or<E>(
+        &self,
+        k: K,
+        vacant: impl FnOnce() -> Result<V, E>
+    ) -> Result<&V, E>;
+
+    /// Return a mutable reference to entry `k`.  If no such entry exists, call
+    /// `vacant` and either forward its error, or add its result to the map
+    /// and return a reference to *that*.
+    fn get_mut_or<E>(
+        &mut self,
+        k: K,
+        vacant: impl FnOnce() -> Result<V, E>
+    ) -> Result<&mut V, E>;
+}
 
 /// Methods of this trait signifies a point where CTFE evaluation would fail
 /// and some use case dependent behaviour can instead be applied.
-/// FIXME: We should be able to get rid of the 'a here if we can get rid of the 'a in
-/// `snapshot::EvalSnapshot`.
 pub trait Machine<'a, 'mir, 'tcx>: Sized {
     /// Additional data that can be accessed via the Memory
     type MemoryData;
@@ -30,11 +68,25 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
     type MemoryKinds: ::std::fmt::Debug + Copy + Eq;
 
-    /// The memory kind to use for mutated statics -- or None if those are not supported.
-    const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
+    /// Memory's allocation map
+    type MemoryMap:
+        AllocMap<AllocId, (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag>)> +
+        Default +
+        Clone;
+
+    /// Tag tracked alongside every pointer.  This is inert for now, in preparation for
+    /// a future implementation of "Stacked Borrows"
+    /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
+    type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
+
+    /// The memory kind to use for copied statics -- or None if those are not supported.
+    /// Statics are copied under two circumstances: When they are mutated, and when
+    /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
+    /// that is added to the memory so that the work is not done twice.
+    const STATIC_KIND: Option<Self::MemoryKinds>;
 
     /// Whether to enforce the validity invariant
-    const ENFORCE_VALIDITY: bool;
+    fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool;
 
     /// Called before a basic block terminator is executed.
     /// You can use this to detect endlessly running programs.
@@ -53,8 +105,8 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     fn find_fn(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx>],
-        dest: Option<PlaceTy<'tcx>>,
+        args: &[OpTy<'tcx, Self::PointerTag>],
+        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
         ret: Option<mir::BasicBlock>,
     ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;
 
@@ -63,18 +115,30 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     fn call_intrinsic(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx>],
-        dest: PlaceTy<'tcx>,
+        args: &[OpTy<'tcx, Self::PointerTag>],
+        dest: PlaceTy<'tcx, Self::PointerTag>,
     ) -> EvalResult<'tcx>;
 
     /// Called for read access to a foreign static item.
-    /// This can be called multiple times for the same static item and should return consistent
-    /// results.  Once the item is *written* the first time, as usual for statics a copy is
-    /// made and this function is not called again.
+    ///
+    /// This will only be called once per static and machine; the result is cached in
+    /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
+    /// owned allocation to the map even when the map is shared.)
     fn find_foreign_static(
         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
         def_id: DefId,
-    ) -> EvalResult<'tcx, &'tcx Allocation>;
+    ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>>;
+
+    /// Called to turn an allocation obtained from the `tcx` into one that has
+    /// the appropriate tags on each pointer.
+    ///
+    /// This should avoid copying if no work has to be done! If this returns an owned
+    /// allocation (because a copy had to be done to add the tags), machine memory will
+    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
+    /// owned allocation to the map even when the map is shared.)
+    fn static_with_default_tag(
+        alloc: &'_ Allocation
+    ) -> Cow<'_, Allocation<Self::PointerTag>>;
 
     /// Called for all binary operations on integer(-like) types when one operand is a pointer
     /// value, and for the `Offset` operation that is inherently about pointers.
@@ -83,18 +147,18 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     fn ptr_op(
         ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
         bin_op: mir::BinOp,
-        left: Scalar,
+        left: Scalar<Self::PointerTag>,
         left_layout: TyLayout<'tcx>,
-        right: Scalar,
+        right: Scalar<Self::PointerTag>,
         right_layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, (Scalar, bool)>;
+    ) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
 
     /// Heap allocations via the `box` keyword
     ///
     /// Returns a pointer to the allocated memory
     fn box_alloc(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        dest: PlaceTy<'tcx>,
+        dest: PlaceTy<'tcx, Self::PointerTag>,
     ) -> EvalResult<'tcx>;
 
     /// Execute a validation operation
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 5437c8ababc..4b0c0c3ee61 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -18,23 +18,28 @@
 
 use std::collections::VecDeque;
 use std::ptr;
+use std::borrow::Cow;
 
 use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
 use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
-use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, GlobalId,
-                            EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
-                            truncate};
+use rustc::mir::interpret::{
+    Pointer, AllocId, Allocation, ConstValue, GlobalId,
+    EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
+    truncate
+};
 pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 
 use syntax::ast::Mutability;
 
-use super::{Machine, ScalarMaybeUndef};
+use super::{Machine, AllocMap, ScalarMaybeUndef};
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
 pub enum MemoryKind<T> {
     /// Error if deallocated except during a stack pop
     Stack,
+    /// Error if ever deallocated
+    Vtable,
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
     Machine(T),
 }
@@ -48,9 +53,13 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
     /// Allocations local to this instance of the miri engine.  The kind
     /// helps ensure that the same mechanism is used for allocation and
     /// deallocation.  When an allocation is not found here, it is a
-    /// static and looked up in the `tcx` for read access.  Writing to
-    /// a static creates a copy here, in the machine.
-    alloc_map: FxHashMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
+    /// static and looked up in the `tcx` for read access.  Some machines may
+    /// have to mutate this map even on a read-only access to a static (because
+    /// they do pointer provenance tracking and the allocations in `tcx` have
+    /// the wrong type), so we let the machine override this type.
+    /// Either way, if the machine allows writing to a static, doing so will
+    /// create a copy of the static allocation here.
+    alloc_map: M::MemoryMap,
 
     /// To be able to compare pointers with NULL, and to check alignment for accesses
     /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
@@ -98,23 +107,23 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
         Memory {
             data,
-            alloc_map: FxHashMap::default(),
+            alloc_map: Default::default(),
             dead_alloc_map: FxHashMap::default(),
             tcx,
         }
     }
 
-    pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer {
-        self.tcx.alloc_map.lock().create_fn_alloc(instance).into()
+    pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer<M::PointerTag> {
+        Pointer::from(self.tcx.alloc_map.lock().create_fn_alloc(instance)).with_default_tag()
     }
 
-    pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer {
-        self.tcx.allocate_bytes(bytes).into()
+    pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer<M::PointerTag> {
+        Pointer::from(self.tcx.allocate_bytes(bytes)).with_default_tag()
     }
 
     pub fn allocate_with(
         &mut self,
-        alloc: Allocation,
+        alloc: Allocation<M::PointerTag>,
         kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx, AllocId> {
         let id = self.tcx.alloc_map.lock().reserve();
@@ -127,19 +136,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         size: Size,
         align: Align,
         kind: MemoryKind<M::MemoryKinds>,
-    ) -> EvalResult<'tcx, Pointer> {
-        self.allocate_with(Allocation::undef(size, align), kind).map(Pointer::from)
+    ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
+        let ptr = Pointer::from(self.allocate_with(Allocation::undef(size, align), kind)?);
+        Ok(ptr.with_default_tag())
     }
 
     pub fn reallocate(
         &mut self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         old_size: Size,
         old_align: Align,
         new_size: Size,
         new_align: Align,
         kind: MemoryKind<M::MemoryKinds>,
-    ) -> EvalResult<'tcx, Pointer> {
+    ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
         if ptr.offset.bytes() != 0 {
             return err!(ReallocateNonBasePtr);
         }
@@ -160,7 +170,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     }
 
     /// Deallocate a local, or do nothing if that local has been made into a static
-    pub fn deallocate_local(&mut self, ptr: Pointer) -> EvalResult<'tcx> {
+    pub fn deallocate_local(&mut self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx> {
         // The allocation might be already removed by static interning.
         // This can only really happen in the CTFE instance, not in miri.
         if self.alloc_map.contains_key(&ptr.alloc_id) {
@@ -172,7 +182,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     pub fn deallocate(
         &mut self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         size_and_align: Option<(Size, Align)>,
         kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx> {
@@ -231,7 +241,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     /// Check that the pointer is aligned AND non-NULL. This supports ZSTs in two ways:
     /// You can pass a scalar, and a `Pointer` does not have to actually still be allocated.
-    pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx> {
+    pub fn check_align(
+        &self,
+        ptr: Scalar<M::PointerTag>,
+        required_align: Align
+    ) -> EvalResult<'tcx> {
         // Check non-NULL/Undef, extract offset
         let (offset, alloc_align) = match ptr {
             Scalar::Ptr(ptr) => {
@@ -240,7 +254,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                 // of some (potentially dead) allocation.
                 if ptr.offset > size {
                     return err!(PointerOutOfBounds {
-                        ptr,
+                        ptr: ptr.erase_tag(),
                         access: true,
                         allocation_size: size,
                     });
@@ -284,12 +298,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// If you want to check bounds before doing a memory access, be sure to
     /// check the pointer one past the end of your access, then everything will
     /// work out exactly.
-    pub fn check_bounds_ptr(&self, ptr: Pointer, access: bool) -> EvalResult<'tcx> {
+    pub fn check_bounds_ptr(&self, ptr: Pointer<M::PointerTag>, access: bool) -> EvalResult<'tcx> {
         let alloc = self.get(ptr.alloc_id)?;
         let allocation_size = alloc.bytes.len() as u64;
         if ptr.offset.bytes() > allocation_size {
             return err!(PointerOutOfBounds {
-                ptr,
+                ptr: ptr.erase_tag(),
                 access,
                 allocation_size: Size::from_bytes(allocation_size),
             });
@@ -299,7 +313,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     /// Check if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
     #[inline(always)]
-    pub fn check_bounds(&self, ptr: Pointer, size: Size, access: bool) -> EvalResult<'tcx> {
+    pub fn check_bounds(
+        &self,
+        ptr: Pointer<M::PointerTag>,
+        size: Size,
+        access: bool
+    ) -> EvalResult<'tcx> {
         // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
         self.check_bounds_ptr(ptr.offset(size, &*self)?, access)
     }
@@ -307,15 +326,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
 /// Allocation accessors
 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
-    /// Helper function to obtain the global (tcx) allocation for a static
+    /// Helper function to obtain the global (tcx) allocation for a static.
+    /// This attempts to return a reference to an existing allocation if
+    /// one can be found in `tcx`. That, however, is only possible if `tcx` and
+    /// this machine use the same pointer tag, so it is indirected through
+    /// `M::static_with_default_tag`.
     fn get_static_alloc(
         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
         id: AllocId,
-    ) -> EvalResult<'tcx, &'tcx Allocation> {
+    ) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag>>> {
         let alloc = tcx.alloc_map.lock().get(id);
         let def_id = match alloc {
             Some(AllocType::Memory(mem)) => {
-                return Ok(mem)
+                // We got tcx memory. Let the machine figure out whether and how to
+                // turn that into memory with the right pointer tag.
+                return Ok(M::static_with_default_tag(mem))
             }
             Some(AllocType::Function(..)) => {
                 return err!(DerefFunctionPointer)
@@ -342,20 +367,73 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             EvalErrorKind::ReferencedConstant(err).into()
         }).map(|const_val| {
             if let ConstValue::ByRef(_, allocation, _) = const_val.val {
-                allocation
+                // We got tcx memory. Let the machine figure out whether and how to
+                // turn that into memory with the right pointer tag.
+                M::static_with_default_tag(allocation)
             } else {
                 bug!("Matching on non-ByRef static")
             }
         })
     }
 
-    pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
-        match self.alloc_map.get(&id) {
-            // Normal alloc?
-            Some(alloc) => Ok(&alloc.1),
-            // Static. No need to make any copies, just provide read access to the global static
-            // memory in tcx.
-            None => Self::get_static_alloc(self.tcx, id),
+    pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<M::PointerTag>> {
+        // The error type of the inner closure here is somewhat funny.  We have two
+        // ways of "erroring": An actual error, or because we got a reference from
+        // `get_static_alloc` that we can actually use directly without inserting anything anywhere.
+        // So the error type is `EvalResult<'tcx, &Allocation<M::PointerTag>>`.
+        let a = self.alloc_map.get_or(id, || {
+            let alloc = Self::get_static_alloc(self.tcx, id).map_err(Err)?;
+            match alloc {
+                Cow::Borrowed(alloc) => {
+                    // We got a ref, cheaply return that as an "error" so that the
+                    // map does not get mutated.
+                    Err(Ok(alloc))
+                }
+                Cow::Owned(alloc) => {
+                    // Need to put it into the map and return a ref to that
+                    let kind = M::STATIC_KIND.expect(
+                        "I got an owned allocation that I have to copy but the machine does \
+                            not expect that to happen"
+                    );
+                    Ok((MemoryKind::Machine(kind), alloc))
+                }
+            }
+        });
+        // Now unpack that funny error type
+        match a {
+            Ok(a) => Ok(&a.1),
+            Err(a) => a
+        }
+    }
+
+    pub fn get_mut(
+        &mut self,
+        id: AllocId,
+    ) -> EvalResult<'tcx, &mut Allocation<M::PointerTag>> {
+        let tcx = self.tcx;
+        let a = self.alloc_map.get_mut_or(id, || {
+            // Need to make a copy, even if `get_static_alloc` is able
+            // to give us a cheap reference.
+            let alloc = Self::get_static_alloc(tcx, id)?;
+            if alloc.mutability == Mutability::Immutable {
+                return err!(ModifiedConstantMemory);
+            }
+            let kind = M::STATIC_KIND.expect(
+                "An allocation is being mutated but the machine does not expect that to happen"
+            );
+            Ok((MemoryKind::Machine(kind), alloc.into_owned()))
+        });
+        // Unpack the error type manually because type inference doesn't
+        // work otherwise (and we cannot help it because `impl Trait`)
+        match a {
+            Err(e) => Err(e),
+            Ok(a) => {
+                let a = &mut a.1;
+                if a.mutability == Mutability::Immutable {
+                    return err!(ModifiedConstantMemory);
+                }
+                Ok(a)
+            }
         }
     }
 
@@ -367,7 +445,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         match self.tcx.alloc_map.lock().get(id) {
             Some(AllocType::Function(..)) => (Size::ZERO, Align::from_bytes(1, 1).unwrap()),
             Some(AllocType::Static(did)) => {
-                // The only way `get` couldnÄt have worked here is if this is an extern static
+                // The only way `get` couldn't have worked here is if this is an extern static
                 assert!(self.tcx.is_foreign_item(did));
                 // Use size and align of the type
                 let ty = self.tcx.type_of(did);
@@ -383,31 +461,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         }
     }
 
-    pub fn get_mut(
-        &mut self,
-        id: AllocId,
-    ) -> EvalResult<'tcx, &mut Allocation> {
-        // Static?
-        if !self.alloc_map.contains_key(&id) {
-            // Ask the machine for what to do
-            if let Some(kind) = M::MUT_STATIC_KIND {
-                // The machine supports mutating statics.  Make a copy, use that.
-                self.deep_copy_static(id, MemoryKind::Machine(kind))?;
-            } else {
-                return err!(ModifiedConstantMemory)
-            }
-        }
-        // If we come here, we know the allocation is in our map
-        let alloc = &mut self.alloc_map.get_mut(&id).unwrap().1;
-        // See if we are allowed to mutate this
-        if alloc.mutability == Mutability::Immutable {
-            err!(ModifiedConstantMemory)
-        } else {
-            Ok(alloc)
-        }
-    }
-
-    pub fn get_fn(&self, ptr: Pointer) -> EvalResult<'tcx, Instance<'tcx>> {
+    pub fn get_fn(&self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx, Instance<'tcx>> {
         if ptr.offset.bytes() != 0 {
             return err!(InvalidFunctionPointer);
         }
@@ -418,108 +472,132 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         }
     }
 
+    pub fn mark_immutable(&mut self, id: AllocId) -> EvalResult<'tcx> {
+        self.get_mut(id)?.mutability = Mutability::Immutable;
+        Ok(())
+    }
+
     /// For debugging, print an allocation and all allocations it points to, recursively.
     pub fn dump_alloc(&self, id: AllocId) {
-        if !log_enabled!(::log::Level::Trace) {
-            return;
-        }
         self.dump_allocs(vec![id]);
     }
 
+    fn dump_alloc_helper<Tag>(
+        &self,
+        allocs_seen: &mut FxHashSet<AllocId>,
+        allocs_to_print: &mut VecDeque<AllocId>,
+        mut msg: String,
+        alloc: &Allocation<Tag>,
+        extra: String,
+    ) {
+        use std::fmt::Write;
+
+        let prefix_len = msg.len();
+        let mut relocations = vec![];
+
+        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 + Size::from_bytes(1)).is_ok() {
+                // this `as usize` is fine, since `i` came from a `usize`
+                write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap();
+            } else {
+                msg.push_str("__ ");
+            }
+        }
+
+        trace!(
+            "{}({} bytes, alignment {}){}",
+            msg,
+            alloc.bytes.len(),
+            alloc.align.abi(),
+            extra
+        );
+
+        if !relocations.is_empty() {
+            msg.clear();
+            write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces.
+            let mut pos = Size::ZERO;
+            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).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();
+                pos = i + self.pointer_size();
+            }
+            trace!("{}", msg);
+        }
+    }
+
     /// For debugging, print a list of allocations and all allocations they point to, recursively.
     pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
         if !log_enabled!(::log::Level::Trace) {
             return;
         }
-        use std::fmt::Write;
         allocs.sort();
         allocs.dedup();
         let mut allocs_to_print = VecDeque::from(allocs);
         let mut allocs_seen = FxHashSet::default();
 
         while let Some(id) = allocs_to_print.pop_front() {
-            let mut msg = format!("Alloc {:<5} ", format!("{}:", id));
-            let prefix_len = msg.len();
-            let mut relocations = vec![];
-
-            let (alloc, immutable) =
-                // normal alloc?
-                match self.alloc_map.get(&id) {
-                    Some((kind, alloc)) => (alloc, match kind {
+            let msg = format!("Alloc {:<5} ", format!("{}:", id));
+
+            // normal alloc?
+            match self.alloc_map.get_or(id, || Err(())) {
+                Ok((kind, alloc)) => {
+                    let extra = match kind {
                         MemoryKind::Stack => " (stack)".to_owned(),
+                        MemoryKind::Vtable => " (vtable)".to_owned(),
                         MemoryKind::Machine(m) => format!(" ({:?})", m),
-                    }),
-                    None => {
-                        // static alloc?
-                        match self.tcx.alloc_map.lock().get(id) {
-                            Some(AllocType::Memory(a)) => (a, " (immutable)".to_owned()),
-                            Some(AllocType::Function(func)) => {
-                                trace!("{} {}", msg, func);
-                                continue;
-                            }
-                            Some(AllocType::Static(did)) => {
-                                trace!("{} {:?}", msg, did);
-                                continue;
-                            }
-                            None => {
-                                trace!("{} (deallocated)", msg);
-                                continue;
-                            }
+                    };
+                    self.dump_alloc_helper(
+                        &mut allocs_seen, &mut allocs_to_print,
+                        msg, alloc, extra
+                    );
+                },
+                Err(()) => {
+                    // static alloc?
+                    match self.tcx.alloc_map.lock().get(id) {
+                        Some(AllocType::Memory(alloc)) => {
+                            self.dump_alloc_helper(
+                                &mut allocs_seen, &mut allocs_to_print,
+                                msg, alloc, " (immutable)".to_owned()
+                            );
+                        }
+                        Some(AllocType::Function(func)) => {
+                            trace!("{} {}", msg, func);
+                        }
+                        Some(AllocType::Static(did)) => {
+                            trace!("{} {:?}", msg, did);
+                        }
+                        None => {
+                            trace!("{} (deallocated)", msg);
                         }
-                    },
-                };
-
-            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 + Size::from_bytes(1)).is_ok() {
-                    // this `as usize` is fine, since `i` came from a `usize`
-                    write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap();
-                } else {
-                    msg.push_str("__ ");
-                }
-            }
-
-            trace!(
-                "{}({} bytes, alignment {}){}",
-                msg,
-                alloc.bytes.len(),
-                alloc.align.abi(),
-                immutable
-            );
+                },
+            };
 
-            if !relocations.is_empty() {
-                msg.clear();
-                write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces.
-                let mut pos = Size::ZERO;
-                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).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();
-                    pos = i + self.pointer_size();
-                }
-                trace!("{}", msg);
-            }
         }
     }
 
     pub fn leak_report(&self) -> usize {
         trace!("### LEAK REPORT ###");
-        let mut_static_kind = M::MUT_STATIC_KIND.map(|k| MemoryKind::Machine(k));
-        let leaks: Vec<_> = self.alloc_map
-            .iter()
-            .filter_map(|(&id, &(kind, _))|
-                // exclude mutable statics
-                if Some(kind) == mut_static_kind { None } else { Some(id) } )
-            .collect();
+        let leaks: Vec<_> = self.alloc_map.filter_map_collect(|&id, &(kind, _)| {
+            // exclude statics and vtables
+            let exclude = match kind {
+                MemoryKind::Stack => false,
+                MemoryKind::Vtable => true,
+                MemoryKind::Machine(k) => Some(k) == M::STATIC_KIND,
+            };
+            if exclude { None } else { Some(id) }
+        });
         let n = leaks.len();
         self.dump_allocs(leaks);
         n
@@ -531,9 +609,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// The last argument controls whether we error out when there are undefined
     /// or pointer bytes.  You should never call this, call `get_bytes` or
     /// `get_bytes_with_undef_and_ptr` instead,
+    ///
+    /// This function also guarantees that the resulting pointer will remain stable
+    /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
+    /// on that.
     fn get_bytes_internal(
         &self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         size: Size,
         align: Align,
         check_defined_and_ptr: bool,
@@ -558,16 +640,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     }
 
     #[inline]
-    fn get_bytes(&self, ptr: Pointer, size: Size, align: Align) -> EvalResult<'tcx, &[u8]> {
+    fn get_bytes(
+        &self,
+        ptr: Pointer<M::PointerTag>,
+        size: Size,
+        align: Align
+    ) -> EvalResult<'tcx, &[u8]> {
         self.get_bytes_internal(ptr, size, align, true)
     }
 
     /// It is the caller's responsibility to handle undefined and pointer bytes.
-    /// However, this still checks that there are no relocations on the egdes.
+    /// However, this still checks that there are no relocations on the *egdes*.
     #[inline]
     fn get_bytes_with_undef_and_ptr(
         &self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         size: Size,
         align: Align
     ) -> EvalResult<'tcx, &[u8]> {
@@ -578,7 +665,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// so be sure to actually put data there!
     fn get_bytes_mut(
         &mut self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         size: Size,
         align: Align,
     ) -> EvalResult<'tcx, &mut [u8]> {
@@ -597,8 +684,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     }
 }
 
-/// Reading and writing
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+/// Interning (for CTFE)
+impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
+where
+    M: Machine<'a, 'mir, 'tcx, PointerTag=()>,
+    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<()>)>,
+{
     /// mark an allocation as static and initialized, either mutable or not
     pub fn intern_static(
         &mut self,
@@ -614,14 +705,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         let (kind, mut alloc) = self.alloc_map.remove(&alloc_id).unwrap();
         match kind {
             MemoryKind::Machine(_) => bug!("Static cannot refer to machine memory"),
-            MemoryKind::Stack => {},
+            MemoryKind::Stack | MemoryKind::Vtable => {},
         }
         // ensure llvm knows not to put this into immutable memory
         alloc.mutability = mutability;
         let alloc = self.tcx.intern_const_alloc(alloc);
         self.tcx.alloc_map.lock().set_id_memory(alloc_id, alloc);
         // recurse into inner allocations
-        for &alloc in alloc.relocations.values() {
+        for &(_, alloc) in alloc.relocations.values() {
             // FIXME: Reusing the mutability here is likely incorrect.  It is originally
             // determined via `is_freeze`, and data is considered frozen if there is no
             // `UnsafeCell` *immediately* in that data -- however, this search stops
@@ -635,28 +726,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         }
         Ok(())
     }
+}
 
-    /// The alloc_id must refer to a (mutable) static; a deep copy of that
-    /// static is made into this memory.
-    fn deep_copy_static(
-        &mut self,
-        id: AllocId,
-        kind: MemoryKind<M::MemoryKinds>,
-    ) -> EvalResult<'tcx> {
-        let alloc = Self::get_static_alloc(self.tcx, id)?;
-        if alloc.mutability == Mutability::Immutable {
-            return err!(ModifiedConstantMemory);
-        }
-        let old = self.alloc_map.insert(id, (kind, alloc.clone()));
-        assert!(old.is_none(), "deep_copy_static: must not overwrite existing memory");
-        Ok(())
-    }
-
+/// Reading and writing
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn copy(
         &mut self,
-        src: Scalar,
+        src: Scalar<M::PointerTag>,
         src_align: Align,
-        dest: Scalar,
+        dest: Scalar<M::PointerTag>,
         dest_align: Align,
         size: Size,
         nonoverlapping: bool,
@@ -666,9 +744,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     pub fn copy_repeatedly(
         &mut self,
-        src: Scalar,
+        src: Scalar<M::PointerTag>,
         src_align: Align,
-        dest: Scalar,
+        dest: Scalar<M::PointerTag>,
         dest_align: Align,
         size: Size,
         length: u64,
@@ -695,9 +773,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                 new_relocations.extend(
                     relocations
                     .iter()
-                    .map(|&(offset, alloc_id)| {
+                    .map(|&(offset, reloc)| {
                     (offset + dest.offset - src.offset + (i * size * relocations.len() as u64),
-                    alloc_id)
+                     reloc)
                     })
                 );
             }
@@ -712,6 +790,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         // SAFE: The above indexing would have panicked if there weren't at least `size` bytes
         // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
         // `dest` could possibly overlap.
+        // The pointers above remain valid even if the `HashMap` table is moved around because they
+        // point into the `Vec` storing the bytes.
         unsafe {
             assert_eq!(size.bytes() as usize as u64, size.bytes());
             if src.alloc_id == dest.alloc_id {
@@ -747,7 +827,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub fn read_c_str(&self, ptr: Pointer) -> EvalResult<'tcx, &[u8]> {
+    pub fn read_c_str(&self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx, &[u8]> {
         let alloc = self.get(ptr.alloc_id)?;
         assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
         let offset = ptr.offset.bytes() as usize;
@@ -758,11 +838,34 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                 self.check_defined(ptr, p1)?;
                 Ok(&alloc.bytes[offset..offset + size])
             }
-            None => err!(UnterminatedCString(ptr)),
+            None => err!(UnterminatedCString(ptr.erase_tag())),
+        }
+    }
+
+    pub fn check_bytes(
+        &self,
+        ptr: Scalar<M::PointerTag>,
+        size: Size,
+        allow_ptr_and_undef: bool,
+    ) -> 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();
+        if size.bytes() == 0 {
+            self.check_align(ptr, align)?;
+            return Ok(());
         }
+        let ptr = ptr.to_ptr()?;
+        // Check bounds, align and relocations on the edges
+        self.get_bytes_with_undef_and_ptr(ptr, size, align)?;
+        // Check undef and ptr
+        if !allow_ptr_and_undef {
+            self.check_defined(ptr, size)?;
+            self.check_relocations(ptr, size)?;
+        }
+        Ok(())
     }
 
-    pub fn read_bytes(&self, ptr: Scalar, size: Size) -> EvalResult<'tcx, &[u8]> {
+    pub fn read_bytes(&self, ptr: Scalar<M::PointerTag>, 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();
         if size.bytes() == 0 {
@@ -772,7 +875,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         self.get_bytes(ptr.to_ptr()?, size, align)
     }
 
-    pub fn write_bytes(&mut self, ptr: Scalar, src: &[u8]) -> EvalResult<'tcx> {
+    pub fn write_bytes(&mut self, ptr: Scalar<M::PointerTag>, src: &[u8]) -> 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();
         if src.is_empty() {
@@ -784,7 +887,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub fn write_repeat(&mut self, ptr: Scalar, val: u8, count: Size) -> EvalResult<'tcx> {
+    pub fn write_repeat(
+        &mut self,
+        ptr: Scalar<M::PointerTag>,
+        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();
         if count.bytes() == 0 {
@@ -801,10 +909,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// Read a *non-ZST* scalar
     pub fn read_scalar(
         &self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         ptr_align: Align,
         size: Size
-    ) -> EvalResult<'tcx, ScalarMaybeUndef> {
+    ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
         // get_bytes_unchecked tests alignment and relocation edges
         let bytes = self.get_bytes_with_undef_and_ptr(
             ptr, size, ptr_align.min(self.int_align(size))
@@ -825,8 +933,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         } else {
             let alloc = self.get(ptr.alloc_id)?;
             match alloc.relocations.get(&ptr.offset) {
-                Some(&alloc_id) => {
-                    let ptr = Pointer::new(alloc_id, Size::from_bytes(bits as u64));
+                Some(&(tag, alloc_id)) => {
+                    let ptr = Pointer::new_with_tag(alloc_id, Size::from_bytes(bits as u64), tag);
                     return Ok(ScalarMaybeUndef::Scalar(ptr.into()))
                 }
                 None => {},
@@ -836,17 +944,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size)))
     }
 
-    pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align)
-        -> EvalResult<'tcx, ScalarMaybeUndef> {
+    pub fn read_ptr_sized(
+        &self,
+        ptr: Pointer<M::PointerTag>,
+        ptr_align: Align
+    ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
         self.read_scalar(ptr, ptr_align, self.pointer_size())
     }
 
     /// Write a *non-ZST* scalar
     pub fn write_scalar(
         &mut self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         ptr_align: Align,
-        val: ScalarMaybeUndef,
+        val: ScalarMaybeUndef<M::PointerTag>,
         type_size: Size,
     ) -> EvalResult<'tcx> {
         let val = match val {
@@ -880,7 +991,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             Scalar::Ptr(val) => {
                 self.get_mut(ptr.alloc_id)?.relocations.insert(
                     ptr.offset,
-                    val.alloc_id,
+                    (val.tag, val.alloc_id),
                 );
             }
             _ => {}
@@ -889,8 +1000,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub fn write_ptr_sized(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef)
-        -> EvalResult<'tcx> {
+    pub fn write_ptr_sized(
+        &mut self,
+        ptr: Pointer<M::PointerTag>,
+        ptr_align: Align,
+        val: ScalarMaybeUndef<M::PointerTag>
+    ) -> EvalResult<'tcx> {
         let ptr_size = self.pointer_size();
         self.write_scalar(ptr.into(), ptr_align, val, ptr_size)
     }
@@ -915,9 +1030,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// Return all relocations overlapping with the given ptr-offset pair.
     fn relocations(
         &self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         size: Size,
-    ) -> EvalResult<'tcx, &[(Size, AllocId)]> {
+    ) -> EvalResult<'tcx, &[(Size, (M::PointerTag, AllocId))]> {
         // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
         // the beginning of this range.
         let start = ptr.offset.bytes().saturating_sub(self.pointer_size().bytes() - 1);
@@ -927,7 +1042,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     /// Check that there ar eno relocations overlapping with the given range.
     #[inline(always)]
-    fn check_relocations(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+    fn check_relocations(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
         if self.relocations(ptr, size)?.len() != 0 {
             err!(ReadPointerAsBytes)
         } else {
@@ -941,7 +1056,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// uninitialized.  This is a somewhat odd "spooky action at a distance",
     /// but it allows strictly more code to run than if we would just error
     /// immediately in that case.
-    fn clear_relocations(&mut self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+    fn clear_relocations(&mut self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
         // Find the start and end of the given range and its outermost relocations.
         let (first, last) = {
             // Find all relocations overlapping the given range.
@@ -976,7 +1091,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// Error if there are relocations overlapping with the egdes of the
     /// given memory range.
     #[inline]
-    fn check_relocation_edges(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+    fn check_relocation_edges(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
         self.check_relocations(ptr, Size::ZERO)?;
         self.check_relocations(ptr.offset(size, self)?, Size::ZERO)?;
         Ok(())
@@ -988,8 +1103,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     // FIXME: Add a fast version for the common, nonoverlapping case
     fn copy_undef_mask(
         &mut self,
-        src: Pointer,
-        dest: Pointer,
+        src: Pointer<M::PointerTag>,
+        dest: Pointer<M::PointerTag>,
         size: Size,
         repeat: u64,
     ) -> EvalResult<'tcx> {
@@ -1016,7 +1131,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes`
     /// error which will report the first byte which is undefined.
     #[inline]
-    fn check_defined(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+    fn check_defined(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
         let alloc = self.get(ptr.alloc_id)?;
         alloc.undef_mask.is_range_defined(
             ptr.offset,
@@ -1026,7 +1141,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     pub fn mark_definedness(
         &mut self,
-        ptr: Pointer,
+        ptr: Pointer<M::PointerTag>,
         size: Size,
         new_state: bool,
     ) -> EvalResult<'tcx> {
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 9e0efaa9c78..39628598ef3 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -32,7 +32,7 @@ pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
 
 pub use self::memory::{Memory, MemoryKind};
 
-pub use self::machine::Machine;
+pub use self::machine::{Machine, AllocMap};
 
 pub use self::operand::{ScalarMaybeUndef, Value, ValTy, Operand, OpTy};
 
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index b53bcfa993d..c72a5894b6a 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -11,7 +11,6 @@
 //! Functions concerning immediate values and operands, and reading from operands.
 //! All high-level functions to read from memory work on operands as sources.
 
-use std::hash::{Hash, Hasher};
 use std::convert::TryInto;
 
 use rustc::{mir, ty};
@@ -25,21 +24,42 @@ use rustc::mir::interpret::{
 use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum ScalarMaybeUndef<Id=AllocId> {
-    Scalar(Scalar<Id>),
+pub enum ScalarMaybeUndef<Tag=(), Id=AllocId> {
+    Scalar(Scalar<Tag, Id>),
     Undef,
 }
 
-impl From<Scalar> for ScalarMaybeUndef {
+impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
     #[inline(always)]
-    fn from(s: Scalar) -> Self {
+    fn from(s: Scalar<Tag>) -> Self {
         ScalarMaybeUndef::Scalar(s)
     }
 }
 
-impl<'tcx> ScalarMaybeUndef {
+impl<'tcx> ScalarMaybeUndef<()> {
     #[inline]
-    pub fn not_undef(self) -> EvalResult<'static, Scalar> {
+    pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
+        where Tag: Default
+    {
+        match self {
+            ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_default_tag()),
+            ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+        }
+    }
+}
+
+impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
+    #[inline]
+    pub fn erase_tag(self) -> ScalarMaybeUndef
+    {
+        match self {
+            ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.erase_tag()),
+            ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+        }
+    }
+
+    #[inline]
+    pub fn not_undef(self) -> EvalResult<'static, Scalar<Tag>> {
         match self {
             ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
             ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
@@ -47,7 +67,7 @@ impl<'tcx> ScalarMaybeUndef {
     }
 
     #[inline(always)]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
         self.not_undef()?.to_ptr()
     }
 
@@ -126,26 +146,49 @@ impl<'tcx> ScalarMaybeUndef {
 /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
 /// defined on `Value`, and do not have to work with a `Place`.
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Value<Id=AllocId> {
-    Scalar(ScalarMaybeUndef<Id>),
-    ScalarPair(ScalarMaybeUndef<Id>, ScalarMaybeUndef<Id>),
+pub enum Value<Tag=(), Id=AllocId> {
+    Scalar(ScalarMaybeUndef<Tag, Id>),
+    ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
 }
 
-impl<'tcx> Value {
+impl Value {
+    #[inline]
+    pub fn with_default_tag<Tag>(self) -> Value<Tag>
+        where Tag: Default
+    {
+        match self {
+            Value::Scalar(x) => Value::Scalar(x.with_default_tag()),
+            Value::ScalarPair(x, y) =>
+                Value::ScalarPair(x.with_default_tag(), y.with_default_tag()),
+        }
+    }
+}
+
+impl<'tcx, Tag> Value<Tag> {
+    #[inline]
+    pub fn erase_tag(self) -> Value
+    {
+        match self {
+            Value::Scalar(x) => Value::Scalar(x.erase_tag()),
+            Value::ScalarPair(x, y) =>
+                Value::ScalarPair(x.erase_tag(), y.erase_tag()),
+        }
+    }
+
     pub fn new_slice(
-        val: Scalar,
+        val: Scalar<Tag>,
         len: u64,
         cx: impl HasDataLayout
     ) -> Self {
         Value::ScalarPair(val.into(), Scalar::from_uint(len, cx.data_layout().pointer_size).into())
     }
 
-    pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
+    pub fn new_dyn_trait(val: Scalar<Tag>, vtable: Pointer<Tag>) -> Self {
         Value::ScalarPair(val.into(), Scalar::Ptr(vtable).into())
     }
 
     #[inline]
-    pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef {
+    pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef<Tag> {
         match self {
             Value::Scalar(val) => val,
             Value::ScalarPair(..) => bug!("Got a fat pointer where a scalar was expected"),
@@ -153,12 +196,12 @@ impl<'tcx> Value {
     }
 
     #[inline]
-    pub fn to_scalar(self) -> EvalResult<'tcx, Scalar> {
+    pub fn to_scalar(self) -> EvalResult<'tcx, Scalar<Tag>> {
         self.to_scalar_or_undef().not_undef()
     }
 
     #[inline]
-    pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar, Scalar)> {
+    pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
         match self {
             Value::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"),
             Value::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?))
@@ -168,7 +211,7 @@ impl<'tcx> Value {
     /// Convert the value into a pointer (or a pointer-sized integer).
     /// Throws away the second half of a ScalarPair!
     #[inline]
-    pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> {
+    pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar<Tag>> {
         match self {
             Value::Scalar(ptr) |
             Value::ScalarPair(ptr, _) => ptr.not_undef(),
@@ -179,15 +222,15 @@ impl<'tcx> Value {
 // ScalarPair needs a type to interpret, so we often have a value and a type together
 // as input for binary and cast operations.
 #[derive(Copy, Clone, Debug)]
-pub struct ValTy<'tcx> {
-    value: Value,
+pub struct ValTy<'tcx, Tag=()> {
+    value: Value<Tag>,
     pub layout: TyLayout<'tcx>,
 }
 
-impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
-    type Target = Value;
+impl<'tcx, Tag> ::std::ops::Deref for ValTy<'tcx, Tag> {
+    type Target = Value<Tag>;
     #[inline(always)]
-    fn deref(&self) -> &Value {
+    fn deref(&self) -> &Value<Tag> {
         &self.value
     }
 }
@@ -196,14 +239,37 @@ impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
 /// or still in memory.  The latter is an optimization, to delay reading that chunk of
 /// memory and to avoid having to store arbitrary-sized data here.
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Operand<Id=AllocId> {
-    Immediate(Value<Id>),
-    Indirect(MemPlace<Id>),
+pub enum Operand<Tag=(), Id=AllocId> {
+    Immediate(Value<Tag, Id>),
+    Indirect(MemPlace<Tag, Id>),
 }
 
 impl Operand {
     #[inline]
-    pub fn to_mem_place(self) -> MemPlace {
+    pub fn with_default_tag<Tag>(self) -> Operand<Tag>
+        where Tag: Default
+    {
+        match self {
+            Operand::Immediate(x) => Operand::Immediate(x.with_default_tag()),
+            Operand::Indirect(x) => Operand::Indirect(x.with_default_tag()),
+        }
+    }
+}
+
+impl<Tag> Operand<Tag> {
+    #[inline]
+    pub fn erase_tag(self) -> Operand
+    {
+        match self {
+            Operand::Immediate(x) => Operand::Immediate(x.erase_tag()),
+            Operand::Indirect(x) => Operand::Indirect(x.erase_tag()),
+        }
+    }
+
+    #[inline]
+    pub fn to_mem_place(self) -> MemPlace<Tag>
+        where Tag: ::std::fmt::Debug
+    {
         match self {
             Operand::Indirect(mplace) => mplace,
             _ => bug!("to_mem_place: expected Operand::Indirect, got {:?}", self),
@@ -212,7 +278,9 @@ impl Operand {
     }
 
     #[inline]
-    pub fn to_immediate(self) -> Value {
+    pub fn to_immediate(self) -> Value<Tag>
+        where Tag: ::std::fmt::Debug
+    {
         match self {
             Operand::Immediate(val) => val,
             _ => bug!("to_immediate: expected Operand::Immediate, got {:?}", self),
@@ -221,23 +289,23 @@ impl Operand {
     }
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct OpTy<'tcx> {
-    crate op: Operand, // ideally we'd make this private, but const_prop needs this
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct OpTy<'tcx, Tag=()> {
+    crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
     pub layout: TyLayout<'tcx>,
 }
 
-impl<'tcx> ::std::ops::Deref for OpTy<'tcx> {
-    type Target = Operand;
+impl<'tcx, Tag> ::std::ops::Deref for OpTy<'tcx, Tag> {
+    type Target = Operand<Tag>;
     #[inline(always)]
-    fn deref(&self) -> &Operand {
+    fn deref(&self) -> &Operand<Tag> {
         &self.op
     }
 }
 
-impl<'tcx> From<MPlaceTy<'tcx>> for OpTy<'tcx> {
+impl<'tcx, Tag: Copy> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
-    fn from(mplace: MPlaceTy<'tcx>) -> Self {
+    fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
         OpTy {
             op: Operand::Indirect(*mplace),
             layout: mplace.layout
@@ -245,9 +313,9 @@ impl<'tcx> From<MPlaceTy<'tcx>> for OpTy<'tcx> {
     }
 }
 
-impl<'tcx> From<ValTy<'tcx>> for OpTy<'tcx> {
+impl<'tcx, Tag> From<ValTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
-    fn from(val: ValTy<'tcx>) -> Self {
+    fn from(val: ValTy<'tcx, Tag>) -> Self {
         OpTy {
             op: Operand::Immediate(val.value),
             layout: val.layout
@@ -255,19 +323,17 @@ impl<'tcx> From<ValTy<'tcx>> for OpTy<'tcx> {
     }
 }
 
-// Validation needs to hash OpTy, but we cannot hash Layout -- so we just hash the type
-impl<'tcx> Hash for OpTy<'tcx> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.op.hash(state);
-        self.layout.ty.hash(state);
-    }
-}
-impl<'tcx> PartialEq for OpTy<'tcx> {
-    fn eq(&self, other: &Self) -> bool {
-        self.op == other.op && self.layout.ty == other.layout.ty
+impl<'tcx, Tag> OpTy<'tcx, Tag>
+{
+    #[inline]
+    pub fn erase_tag(self) -> OpTy<'tcx>
+    {
+        OpTy {
+            op: self.op.erase_tag(),
+            layout: self.layout,
+        }
     }
 }
-impl<'tcx> Eq for OpTy<'tcx> {}
 
 // Use the existing layout if given (but sanity check in debug mode),
 // or compute the layout.
@@ -295,8 +361,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Return None if the layout does not permit loading this as a value.
     pub(super) fn try_read_value_from_mplace(
         &self,
-        mplace: MPlaceTy<'tcx>,
-    ) -> EvalResult<'tcx, Option<Value>> {
+        mplace: MPlaceTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx, Option<Value<M::PointerTag>>> {
         if mplace.layout.is_unsized() {
             // Dont touch unsized
             return Ok(None);
@@ -339,8 +405,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// in a `Value`, not on which data is stored there currently.
     pub(crate) fn try_read_value(
         &self,
-        src: OpTy<'tcx>,
-    ) -> EvalResult<'tcx, Result<Value, MemPlace>> {
+        src: OpTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx, Result<Value<M::PointerTag>, MemPlace<M::PointerTag>>> {
         Ok(match src.try_as_mplace() {
             Ok(mplace) => {
                 if let Some(val) = self.try_read_value_from_mplace(mplace)? {
@@ -355,7 +421,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     /// Read a value from a place, asserting that that is possible with the given layout.
     #[inline(always)]
-    pub fn read_value(&self, op: OpTy<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
+    pub fn read_value(
+        &self,
+        op: OpTy<'tcx, M::PointerTag>
+    ) -> EvalResult<'tcx, ValTy<'tcx, M::PointerTag>> {
         if let Ok(value) = self.try_read_value(op)? {
             Ok(ValTy { value, layout: op.layout })
         } else {
@@ -364,7 +433,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     }
 
     /// Read a scalar from a place
-    pub fn read_scalar(&self, op: OpTy<'tcx>) -> EvalResult<'tcx, ScalarMaybeUndef> {
+    pub fn read_scalar(
+        &self,
+        op: OpTy<'tcx, M::PointerTag>
+    ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
         match *self.read_value(op)? {
             Value::ScalarPair(..) => bug!("got ScalarPair for type: {:?}", op.layout.ty),
             Value::Scalar(val) => Ok(val),
@@ -374,7 +446,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     // Turn the MPlace into a string (must already be dereferenced!)
     pub fn read_str(
         &self,
-        mplace: MPlaceTy<'tcx>,
+        mplace: MPlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx, &str> {
         let len = mplace.len(self)?;
         let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
@@ -383,7 +455,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         Ok(str)
     }
 
-    pub fn uninit_operand(&mut self, layout: TyLayout<'tcx>) -> EvalResult<'tcx, Operand> {
+    pub fn uninit_operand(
+        &mut self,
+        layout: TyLayout<'tcx>
+    ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
         // This decides which types we will use the Immediate optimization for, and hence should
         // match what `try_read_value` and `eval_place_to_op` support.
         if layout.is_zst() {
@@ -410,9 +485,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Projection functions
     pub fn operand_field(
         &self,
-        op: OpTy<'tcx>,
+        op: OpTy<'tcx, M::PointerTag>,
         field: u64,
-    ) -> EvalResult<'tcx, OpTy<'tcx>> {
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         let base = match op.try_as_mplace() {
             Ok(mplace) => {
                 // The easy case
@@ -445,9 +520,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     pub fn operand_downcast(
         &self,
-        op: OpTy<'tcx>,
+        op: OpTy<'tcx, M::PointerTag>,
         variant: usize,
-    ) -> EvalResult<'tcx, OpTy<'tcx>> {
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
         Ok(match op.try_as_mplace() {
             Ok(mplace) => {
@@ -464,8 +539,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     // will always be a MemPlace.
     pub(super) fn deref_operand(
         &self,
-        src: OpTy<'tcx>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+        src: OpTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let val = self.read_value(src)?;
         trace!("deref to {} on {:?}", val.layout.ty, *val);
         Ok(self.ref_to_mplace(val)?)
@@ -473,9 +548,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     pub fn operand_projection(
         &self,
-        base: OpTy<'tcx>,
+        base: OpTy<'tcx, M::PointerTag>,
         proj_elem: &mir::PlaceElem<'tcx>,
-    ) -> EvalResult<'tcx, OpTy<'tcx>> {
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc::mir::ProjectionElem::*;
         Ok(match *proj_elem {
             Field(field, _) => self.operand_field(base, field.index() as u64)?,
@@ -503,7 +578,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         &self,
         mir_place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
-    ) -> EvalResult<'tcx, OpTy<'tcx>> {
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc::mir::Place::*;
         let op = match *mir_place {
             Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
@@ -533,7 +608,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         &self,
         mir_op: &mir::Operand<'tcx>,
         layout: Option<TyLayout<'tcx>>,
-    ) -> EvalResult<'tcx, OpTy<'tcx>> {
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc::mir::Operand::*;
         let op = match *mir_op {
             // FIXME: do some more logic on `move` to invalidate the old location
@@ -558,7 +633,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub(super) fn eval_operands(
         &self,
         ops: &[mir::Operand<'tcx>],
-    ) -> EvalResult<'tcx, Vec<OpTy<'tcx>>> {
+    ) -> EvalResult<'tcx, Vec<OpTy<'tcx, M::PointerTag>>> {
         ops.into_iter()
             .map(|op| self.eval_operand(op, None))
             .collect()
@@ -568,7 +643,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub(super) fn const_value_to_op(
         &self,
         val: ConstValue<'tcx>,
-    ) -> EvalResult<'tcx, Operand> {
+    ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
         trace!("const_value_to_op: {:?}", val);
         match val {
             ConstValue::Unevaluated(def_id, substs) => {
@@ -581,23 +656,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
             ConstValue::ByRef(id, alloc, offset) => {
                 // We rely on mutability being set correctly in that allocation to prevent writes
                 // where none should happen -- and for `static mut`, we copy on demand anyway.
-                Ok(Operand::Indirect(MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)))
+                Ok(Operand::Indirect(
+                    MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)
+                ).with_default_tag())
             },
             ConstValue::ScalarPair(a, b) =>
-                Ok(Operand::Immediate(Value::ScalarPair(a.into(), b.into()))),
+                Ok(Operand::Immediate(Value::ScalarPair(a.into(), b.into())).with_default_tag()),
             ConstValue::Scalar(x) =>
-                Ok(Operand::Immediate(Value::Scalar(x.into()))),
+                Ok(Operand::Immediate(Value::Scalar(x.into())).with_default_tag()),
         }
     }
     pub fn const_to_op(
         &self,
         cnst: &ty::Const<'tcx>,
-    ) -> EvalResult<'tcx, OpTy<'tcx>> {
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         let op = self.const_value_to_op(cnst.val)?;
         Ok(OpTy { op, layout: self.layout_of(cnst.ty)? })
     }
 
-    pub(super) fn global_to_op(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Operand> {
+    pub(super) fn global_to_op(
+        &self,
+        gid: GlobalId<'tcx>
+    ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
         let cv = self.const_eval(gid)?;
         self.const_value_to_op(cv.val)
     }
@@ -605,7 +685,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Read discriminant, return the runtime value as well as the variant index.
     pub fn read_discriminant(
         &self,
-        rval: OpTy<'tcx>,
+        rval: OpTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx, (u128, usize)> {
         trace!("read_discriminant_value {:#?}", rval.layout);
         if rval.layout.abi.is_uninhabited() {
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index dd6ee374c0f..5f4bafc39f3 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -24,9 +24,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn binop_with_overflow(
         &mut self,
         op: mir::BinOp,
-        left: ValTy<'tcx>,
-        right: ValTy<'tcx>,
-        dest: PlaceTy<'tcx>,
+        left: ValTy<'tcx, M::PointerTag>,
+        right: ValTy<'tcx, M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         let (val, overflowed) = self.binary_op_val(op, left, right)?;
         let val = Value::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
@@ -38,9 +38,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn binop_ignore_overflow(
         &mut self,
         op: mir::BinOp,
-        left: ValTy<'tcx>,
-        right: ValTy<'tcx>,
-        dest: PlaceTy<'tcx>,
+        left: ValTy<'tcx, M::PointerTag>,
+        right: ValTy<'tcx, M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         let (val, _overflowed) = self.binary_op_val(op, left, right)?;
         self.write_scalar(val, dest)
@@ -53,7 +53,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         bin_op: mir::BinOp,
         l: char,
         r: char,
-    ) -> EvalResult<'tcx, (Scalar, bool)> {
+    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         use rustc::mir::BinOp::*;
 
         let res = match bin_op {
@@ -73,7 +73,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         bin_op: mir::BinOp,
         l: bool,
         r: bool,
-    ) -> EvalResult<'tcx, (Scalar, bool)> {
+    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         use rustc::mir::BinOp::*;
 
         let res = match bin_op {
@@ -98,7 +98,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         // passing in raw bits
         l: u128,
         r: u128,
-    ) -> EvalResult<'tcx, (Scalar, bool)> {
+    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         use rustc::mir::BinOp::*;
 
         macro_rules! float_math {
@@ -138,7 +138,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         left_layout: TyLayout<'tcx>,
         r: u128,
         right_layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, (Scalar, bool)> {
+    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         use rustc::mir::BinOp::*;
 
         // Shift ops can have an RHS with a different numeric type.
@@ -288,9 +288,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn binary_op_val(
         &self,
         bin_op: mir::BinOp,
-        left: ValTy<'tcx>,
-        right: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, (Scalar, bool)> {
+        left: ValTy<'tcx, M::PointerTag>,
+        right: ValTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         self.binary_op(
             bin_op,
             left.to_scalar()?, left.layout,
@@ -302,11 +302,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn binary_op(
         &self,
         bin_op: mir::BinOp,
-        left: Scalar,
+        left: Scalar<M::PointerTag>,
         left_layout: TyLayout<'tcx>,
-        right: Scalar,
+        right: Scalar<M::PointerTag>,
         right_layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, (Scalar, bool)> {
+    ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
         trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
             bin_op, left, left_layout.ty, right, right_layout.ty);
 
@@ -352,9 +352,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn unary_op(
         &self,
         un_op: mir::UnOp,
-        val: Scalar,
+        val: Scalar<M::PointerTag>,
         layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, Scalar> {
+    ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
         use rustc::mir::UnOp::*;
         use rustc_apfloat::ieee::{Single, Double};
         use rustc_apfloat::Float;
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index b75ceb61feb..e4055947b64 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -13,33 +13,37 @@
 //! All high-level functions to write to memory work on places as destinations.
 
 use std::convert::TryFrom;
+use std::hash::Hash;
 
 use rustc::mir;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
 
 use rustc::mir::interpret::{
-    GlobalId, AllocId, Scalar, EvalResult, Pointer, PointerArithmetic
+    GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic
+};
+use super::{
+    EvalContext, Machine, AllocMap,
+    Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
 };
-use super::{EvalContext, Machine, Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind};
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct MemPlace<Id=AllocId> {
+pub struct MemPlace<Tag=(), Id=AllocId> {
     /// A place may have an integral pointer for ZSTs, and since it might
     /// be turned back into a reference before ever being dereferenced.
     /// However, it may never be undef.
-    pub ptr: Scalar<Id>,
+    pub ptr: Scalar<Tag, Id>,
     pub align: Align,
     /// Metadata for unsized places.  Interpretation is up to the type.
     /// Must not be present for sized types, but can be missing for unsized types
     /// (e.g. `extern type`).
-    pub extra: Option<Scalar<Id>>,
+    pub meta: Option<Scalar<Tag, Id>>,
 }
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Place<Id=AllocId> {
+pub enum Place<Tag=(), Id=AllocId> {
     /// A place referring to a value allocated in the `Memory` system.
-    Ptr(MemPlace<Id>),
+    Ptr(MemPlace<Tag, Id>),
 
     /// To support alloc-free locals, we are able to write directly to a local.
     /// (Without that optimization, we'd just always be a `MemPlace`.)
@@ -50,37 +54,37 @@ pub enum Place<Id=AllocId> {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub struct PlaceTy<'tcx> {
-    place: Place,
+pub struct PlaceTy<'tcx, Tag=()> {
+    place: Place<Tag>,
     pub layout: TyLayout<'tcx>,
 }
 
-impl<'tcx> ::std::ops::Deref for PlaceTy<'tcx> {
-    type Target = Place;
+impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
+    type Target = Place<Tag>;
     #[inline(always)]
-    fn deref(&self) -> &Place {
+    fn deref(&self) -> &Place<Tag> {
         &self.place
     }
 }
 
 /// A MemPlace with its layout. Constructing it is only possible in this module.
 #[derive(Copy, Clone, Debug)]
-pub struct MPlaceTy<'tcx> {
-    mplace: MemPlace,
+pub struct MPlaceTy<'tcx, Tag=()> {
+    mplace: MemPlace<Tag>,
     pub layout: TyLayout<'tcx>,
 }
 
-impl<'tcx> ::std::ops::Deref for MPlaceTy<'tcx> {
-    type Target = MemPlace;
+impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
+    type Target = MemPlace<Tag>;
     #[inline(always)]
-    fn deref(&self) -> &MemPlace {
+    fn deref(&self) -> &MemPlace<Tag> {
         &self.mplace
     }
 }
 
-impl<'tcx> From<MPlaceTy<'tcx>> for PlaceTy<'tcx> {
+impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
-    fn from(mplace: MPlaceTy<'tcx>) -> Self {
+    fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
         PlaceTy {
             place: Place::Ptr(mplace.mplace),
             layout: mplace.layout
@@ -89,29 +93,52 @@ impl<'tcx> From<MPlaceTy<'tcx>> for PlaceTy<'tcx> {
 }
 
 impl MemPlace {
+    #[inline]
+    pub fn with_default_tag<Tag>(self) -> MemPlace<Tag>
+        where Tag: Default
+    {
+        MemPlace {
+            ptr: self.ptr.with_default_tag(),
+            align: self.align,
+            meta: self.meta.map(Scalar::with_default_tag),
+        }
+    }
+}
+
+impl<Tag> MemPlace<Tag> {
+    #[inline]
+    pub fn erase_tag(self) -> MemPlace
+    {
+        MemPlace {
+            ptr: self.ptr.erase_tag(),
+            align: self.align,
+            meta: self.meta.map(Scalar::erase_tag),
+        }
+    }
+
     #[inline(always)]
-    pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
+    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
         MemPlace {
             ptr,
             align,
-            extra: None,
+            meta: None,
         }
     }
 
     #[inline(always)]
-    pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
+    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
         Self::from_scalar_ptr(ptr.into(), align)
     }
 
     #[inline(always)]
-    pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
-        assert_eq!(self.extra, None);
+    pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
+        assert!(self.meta.is_none());
         (self.ptr, self.align)
     }
 
-    /// Extract the ptr part of the mplace
+    /// metact the ptr part of the mplace
     #[inline(always)]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
         // At this point, we forget about the alignment information --
         // the place has been turned into a reference, and no matter where it came from,
         // it now must be aligned.
@@ -120,17 +147,17 @@ impl MemPlace {
 
     /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
     /// This is the inverse of `ref_to_mplace`.
-    pub fn to_ref(self) -> Value {
+    pub fn to_ref(self) -> Value<Tag> {
         // We ignore the alignment of the place here -- special handling for packed structs ends
         // at the `&` operator.
-        match self.extra {
+        match self.meta {
             None => Value::Scalar(self.ptr.into()),
-            Some(extra) => Value::ScalarPair(self.ptr.into(), extra.into()),
+            Some(meta) => Value::ScalarPair(self.ptr.into(), meta.into()),
         }
     }
 }
 
-impl<'tcx> MPlaceTy<'tcx> {
+impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
     /// Produces a MemPlace that works for ZST but nothing else
     #[inline]
     pub fn dangling(layout: TyLayout<'tcx>, cx: impl HasDataLayout) -> Self {
@@ -144,17 +171,17 @@ impl<'tcx> MPlaceTy<'tcx> {
     }
 
     #[inline]
-    fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
+    fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
         MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align), layout }
     }
 
     #[inline]
     pub(super) fn len(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
         if self.layout.is_unsized() {
-            // We need to consult `extra` metadata
+            // We need to consult `meta` metadata
             match self.layout.ty.sty {
                 ty::Slice(..) | ty::Str =>
-                    return self.extra.unwrap().to_usize(cx),
+                    return self.mplace.meta.unwrap().to_usize(cx),
                 _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
             }
         } else {
@@ -168,30 +195,30 @@ impl<'tcx> MPlaceTy<'tcx> {
     }
 
     #[inline]
-    pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer> {
+    pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer<Tag>> {
         match self.layout.ty.sty {
-            ty::Dynamic(..) => self.extra.unwrap().to_ptr(),
+            ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(),
             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
         }
     }
 }
 
-impl<'tcx> OpTy<'tcx> {
+impl<'tcx, Tag: ::std::fmt::Debug> OpTy<'tcx, Tag> {
     #[inline(always)]
-    pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx>, Value> {
-        match *self {
+    pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, Value<Tag>> {
+        match self.op {
             Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
             Operand::Immediate(value) => Err(value),
         }
     }
 
     #[inline(always)]
-    pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
+    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
         self.try_as_mplace().unwrap()
     }
 }
 
-impl<'tcx> Place {
+impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
     /// Produces a Place that will error if attempted to be read from or written to
     #[inline]
     pub fn null(cx: impl HasDataLayout) -> Self {
@@ -199,17 +226,17 @@ impl<'tcx> Place {
     }
 
     #[inline]
-    pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
+    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
         Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
     }
 
     #[inline]
-    pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
+    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
         Place::Ptr(MemPlace::from_ptr(ptr, align))
     }
 
     #[inline]
-    pub fn to_mem_place(self) -> MemPlace {
+    pub fn to_mem_place(self) -> MemPlace<Tag> {
         match self {
             Place::Ptr(mplace) => mplace,
             _ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
@@ -218,43 +245,43 @@ impl<'tcx> Place {
     }
 
     #[inline]
-    pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
+    pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
         self.to_mem_place().to_scalar_ptr_align()
     }
 
     #[inline]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
         self.to_mem_place().to_ptr()
     }
 }
 
-impl<'tcx> PlaceTy<'tcx> {
-    /// Produces a Place that will error if attempted to be read from or written to
-    #[inline]
-    pub fn null(cx: impl HasDataLayout, layout: TyLayout<'tcx>) -> Self {
-        PlaceTy { place: Place::from_scalar_ptr(Scalar::ptr_null(cx), layout.align), layout }
-    }
-
+impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
     #[inline]
-    pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
+    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
         MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
     }
 }
 
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
+impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
+where
+    Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
+    M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
+    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag>)>,
+{
     /// Take a value, which represents a (thin or fat) reference, and make it a place.
     /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref`.
     pub fn ref_to_mplace(
-        &self, val: ValTy<'tcx>
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+        &self, val: ValTy<'tcx, M::PointerTag>
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
         let layout = self.layout_of(pointee_type)?;
         let align = layout.align;
         let mplace = match *val {
             Value::Scalar(ptr) =>
-                MemPlace { ptr: ptr.not_undef()?, align, extra: None },
-            Value::ScalarPair(ptr, extra) =>
-                MemPlace { ptr: ptr.not_undef()?, align, extra: Some(extra.not_undef()?) },
+                MemPlace { ptr: ptr.not_undef()?, align, meta: None },
+            Value::ScalarPair(ptr, meta) =>
+                MemPlace { ptr: ptr.not_undef()?, align, meta: Some(meta.not_undef()?) },
         };
         Ok(MPlaceTy { mplace, layout })
     }
@@ -265,9 +292,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     #[inline(always)]
     pub fn mplace_field(
         &self,
-        base: MPlaceTy<'tcx>,
+        base: MPlaceTy<'tcx, M::PointerTag>,
         field: u64,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Not using the layout method because we want to compute on u64
         let offset = match base.layout.fields {
             layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
@@ -290,13 +317,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
 
         // Offset may need adjustment for unsized fields
-        let (extra, offset) = if field_layout.is_unsized() {
+        let (meta, offset) = if field_layout.is_unsized() {
             // re-use parent metadata to determine dynamic field layout
-            let (_, align) = self.size_and_align_of(base.extra, field_layout)?;
-            (base.extra, offset.abi_align(align))
-
+            let (_, align) = self.size_and_align_of(base.meta, field_layout)?
+                .expect("Fields cannot be extern types");
+            (base.meta, offset.abi_align(align))
         } else {
-            // base.extra could be present; we might be accessing a sized field of an unsized
+            // base.meta could be present; we might be accessing a sized field of an unsized
             // struct.
             (None, offset)
         };
@@ -307,15 +334,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
             // codegen -- mostly to see if we can get away with that
             .restrict_for_offset(offset); // must be last thing that happens
 
-        Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout })
+        Ok(MPlaceTy { mplace: MemPlace { ptr, align, meta }, layout: field_layout })
     }
 
     // Iterates over all fields of an array. Much more efficient than doing the
     // same by repeatedly calling `mplace_array`.
     pub fn mplace_array_fields(
         &self,
-        base: MPlaceTy<'tcx>,
-    ) -> EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx>>> + 'a> {
+        base: MPlaceTy<'tcx, Tag>,
+    ) ->
+        EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
+    {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let stride = match base.layout.fields {
             layout::FieldPlacement::Array { stride, .. } => stride,
@@ -326,7 +355,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         Ok((0..len).map(move |i| {
             let ptr = base.ptr.ptr_offset(i * stride, dl)?;
             Ok(MPlaceTy {
-                mplace: MemPlace { ptr, align: base.align, extra: None },
+                mplace: MemPlace { ptr, align: base.align, meta: None },
                 layout
             })
         }))
@@ -334,10 +363,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     pub fn mplace_subslice(
         &self,
-        base: MPlaceTy<'tcx>,
+        base: MPlaceTy<'tcx, M::PointerTag>,
         from: u64,
         to: u64,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         assert!(from <= len - to);
 
@@ -350,9 +379,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         };
         let ptr = base.ptr.ptr_offset(from_offset, self)?;
 
-        // Compute extra and new layout
+        // Compute meta and new layout
         let inner_len = len - to - from;
-        let (extra, ty) = match base.layout.ty.sty {
+        let (meta, ty) = match base.layout.ty.sty {
             // It is not nice to match on the type, but that seems to be the only way to
             // implement this.
             ty::Array(inner, _) =>
@@ -367,27 +396,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         let layout = self.layout_of(ty)?;
 
         Ok(MPlaceTy {
-            mplace: MemPlace { ptr, align: base.align, extra },
+            mplace: MemPlace { ptr, align: base.align, meta },
             layout
         })
     }
 
     pub fn mplace_downcast(
         &self,
-        base: MPlaceTy<'tcx>,
+        base: MPlaceTy<'tcx, M::PointerTag>,
         variant: usize,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
-        assert_eq!(base.extra, None);
+        assert!(base.meta.is_none());
         Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
     }
 
     /// Project into an mplace
     pub fn mplace_projection(
         &self,
-        base: MPlaceTy<'tcx>,
+        base: MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: &mir::PlaceElem<'tcx>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::ProjectionElem::*;
         Ok(match *proj_elem {
             Field(field, _) => self.mplace_field(base, field.index() as u64)?,
@@ -428,9 +457,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Just a convenience function, but used quite a bit.
     pub fn place_field(
         &mut self,
-        base: PlaceTy<'tcx>,
+        base: PlaceTy<'tcx, M::PointerTag>,
         field: u64,
-    ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // FIXME: We could try to be smarter and avoid allocation for fields that span the
         // entire place.
         let mplace = self.force_allocation(base)?;
@@ -439,9 +468,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     pub fn place_downcast(
         &mut self,
-        base: PlaceTy<'tcx>,
+        base: PlaceTy<'tcx, M::PointerTag>,
         variant: usize,
-    ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // Downcast just changes the layout
         Ok(match base.place {
             Place::Ptr(mplace) =>
@@ -456,9 +485,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Project into a place
     pub fn place_projection(
         &mut self,
-        base: PlaceTy<'tcx>,
+        base: PlaceTy<'tcx, M::PointerTag>,
         proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
-    ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::ProjectionElem::*;
         Ok(match *proj_elem {
             Field(field, _) =>  self.place_field(base, field.index() as u64)?,
@@ -478,7 +507,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub(super) fn eval_place_to_mplace(
         &self,
         mir_place: &mir::Place<'tcx>
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::Place::*;
         Ok(match *mir_place {
             Promoted(ref promoted) => {
@@ -515,7 +544,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 // and miri: They use the same query to eventually obtain a `ty::Const`
                 // and use that for further computation.
                 let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
-                MPlaceTy::from_aligned_ptr(alloc.into(), layout)
+                MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
             }
 
             _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
@@ -524,12 +553,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     /// Compute a place.  You should only use this if you intend to write into this
     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
-    pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+    pub fn eval_place(
+        &mut self,
+        mir_place: &mir::Place<'tcx>
+    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::Place::*;
         let place = match *mir_place {
-            Local(mir::RETURN_PLACE) => PlaceTy {
-                place: self.frame().return_place,
-                layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
+            Local(mir::RETURN_PLACE) => match self.frame().return_place {
+                Some(return_place) =>
+                    // We use our layout to verify our assumption; caller will validate
+                    // their layout on return.
+                    PlaceTy {
+                        place: *return_place,
+                        layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
+                    },
+                None => return err!(InvalidNullPointerUsage),
             },
             Local(local) => PlaceTy {
                 place: Place::Local {
@@ -554,26 +592,55 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Write a scalar to a place
     pub fn write_scalar(
         &mut self,
-        val: impl Into<ScalarMaybeUndef>,
-        dest: PlaceTy<'tcx>,
+        val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         self.write_value(Value::Scalar(val.into()), dest)
     }
 
     /// Write a value to a place
+    #[inline(always)]
     pub fn write_value(
         &mut self,
-        src_val: Value,
-        dest: PlaceTy<'tcx>,
+        src_val: Value<M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
-        trace!("write_value: {:?} <- {:?}", *dest, src_val);
-        // Check that the value actually is okay for that type
-        if M::ENFORCE_VALIDITY {
-            // Something changed somewhere, better make sure it matches the type!
-            let op = OpTy { op: Operand::Immediate(src_val), layout: dest.layout };
-            self.validate_operand(op, &mut vec![], None, /*const_mode*/false)?;
+        self.write_value_no_validate(src_val, dest)?;
+
+        if M::enforce_validity(self) {
+            // Data got changed, better make sure it matches the type!
+            self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
         }
 
+        Ok(())
+    }
+
+    /// Write a value to a place.
+    /// If you use this you are responsible for validating that things got copied at the
+    /// right type.
+    fn write_value_no_validate(
+        &mut self,
+        src_val: Value<M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx> {
+        if cfg!(debug_assertions) {
+            // This is a very common path, avoid some checks in release mode
+            assert!(!dest.layout.is_unsized(), "Cannot write unsized data");
+            match src_val {
+                Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) =>
+                    assert_eq!(self.pointer_size(), dest.layout.size,
+                        "Size mismatch when writing pointer"),
+                Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) =>
+                    assert_eq!(Size::from_bytes(size.into()), dest.layout.size,
+                        "Size mismatch when writing bits"),
+                Value::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size
+                Value::ScalarPair(_, _) => {
+                    // FIXME: Can we check anything here?
+                }
+            }
+        }
+        trace!("write_value: {:?} <- {:?}: {}", *dest, src_val, dest.layout.ty);
+
         // See if we can avoid an allocation. This is the counterpart to `try_read_value`,
         // but not factored as a separate function.
         let mplace = match dest.place {
@@ -589,18 +656,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
             },
             Place::Ptr(mplace) => mplace, // already in memory
         };
+        let dest = MPlaceTy { mplace, layout: dest.layout };
 
         // This is already in memory, write there.
-        let dest = MPlaceTy { mplace, layout: dest.layout };
-        self.write_value_to_mplace(src_val, dest)
+        self.write_value_to_mplace_no_validate(src_val, dest)
     }
 
-    /// Write a value to memory. This does NOT do validation, so you better had already
-    /// done that before calling this!
-    fn write_value_to_mplace(
+    /// Write a value to memory.
+    /// If you use this you are responsible for validating that things git copied at the
+    /// right type.
+    fn write_value_to_mplace_no_validate(
         &mut self,
-        value: Value,
-        dest: MPlaceTy<'tcx>,
+        value: Value<M::PointerTag>,
+        dest: MPlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         let (ptr, ptr_align) = dest.to_scalar_ptr_align();
         // Note that it is really important that the type here is the right one, and matches the
@@ -615,8 +683,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         }
 
         let ptr = ptr.to_ptr()?;
+        // FIXME: We should check that there are dest.layout.size many bytes available in
+        // memory.  The code below is not sufficient, with enough padding it might not
+        // cover all the bytes!
         match value {
             Value::Scalar(scalar) => {
+                match dest.layout.abi {
+                    layout::Abi::Scalar(_) => {}, // fine
+                    _ => bug!("write_value_to_mplace: invalid Scalar layout: {:#?}",
+                            dest.layout)
+                }
+
                 self.memory.write_scalar(
                     ptr, ptr_align.min(dest.layout.align), scalar, dest.layout.size
                 )
@@ -632,45 +709,109 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 let b_offset = a_size.abi_align(b_align);
                 let b_ptr = ptr.offset(b_offset, &self)?.into();
 
+                // It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
+                // but that does not work: We could be a newtype around a pair, then the
+                // fields do not match the `ScalarPair` components.
+
                 self.memory.write_scalar(ptr, ptr_align.min(a_align), a_val, a_size)?;
                 self.memory.write_scalar(b_ptr, ptr_align.min(b_align), b_val, b_size)
             }
         }
     }
 
-    /// Copy the data from an operand to a place
+    /// Copy the data from an operand to a place.  This does not support transmuting!
+    /// Use `copy_op_transmute` if the layouts could disagree.
+    #[inline(always)]
     pub fn copy_op(
         &mut self,
-        src: OpTy<'tcx>,
-        dest: PlaceTy<'tcx>,
+        src: OpTy<'tcx, M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx> {
+        self.copy_op_no_validate(src, dest)?;
+
+        if M::enforce_validity(self) {
+            // Data got changed, better make sure it matches the type!
+            self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
+        }
+
+        Ok(())
+    }
+
+    /// Copy the data from an operand to a place.  This does not support transmuting!
+    /// Use `copy_op_transmute` if the layouts could disagree.
+    /// Also, if you use this you are responsible for validating that things git copied at the
+    /// right type.
+    fn copy_op_no_validate(
+        &mut self,
+        src: OpTy<'tcx, M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
-        assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
+        debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
             "Cannot copy unsized data");
-        assert_eq!(src.layout.size, dest.layout.size,
-            "Size mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
+        // We do NOT compare the types for equality, because well-typed code can
+        // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
+        assert!(src.layout.details == dest.layout.details,
+            "Layout mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
 
         // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
-        let (src_ptr, src_align) = match self.try_read_value(src)? {
-            Ok(src_val) =>
-                // Yay, we got a value that we can write directly.  We write with the
-                // *source layout*, because that was used to load, and if they do not match
-                // this is a transmute we want to support.
-                return self.write_value(src_val, PlaceTy { place: *dest, layout: src.layout }),
-            Err(mplace) => mplace.to_scalar_ptr_align(),
+        let src = match self.try_read_value(src)? {
+            Ok(src_val) => {
+                // Yay, we got a value that we can write directly.
+                return self.write_value_no_validate(src_val, dest);
+            }
+            Err(mplace) => mplace,
         };
         // Slow path, this does not fit into an immediate. Just memcpy.
-        trace!("copy_op: {:?} <- {:?}", *dest, *src);
+        trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
+
         let dest = self.force_allocation(dest)?;
+        let (src_ptr, src_align) = src.to_scalar_ptr_align();
         let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
         self.memory.copy(
             src_ptr, src_align,
             dest_ptr, dest_align,
-            src.layout.size, false
+            dest.layout.size, false
         )?;
-        if M::ENFORCE_VALIDITY {
-            // Something changed somewhere, better make sure it matches the type!
+
+        Ok(())
+    }
+
+    /// Copy the data from an operand to a place.  The layouts may disagree, but they must
+    /// have the same size.
+    pub fn copy_op_transmute(
+        &mut self,
+        src: OpTy<'tcx, M::PointerTag>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx> {
+        if src.layout.details == dest.layout.details {
+            // Fast path: Just use normal `copy_op`
+            return self.copy_op(src, dest);
+        }
+        // We still require the sizes to match
+        debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
+            "Cannot copy unsized data");
+        assert!(src.layout.size == dest.layout.size,
+            "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
+
+        // The hard case is `ScalarPair`.  `src` is already read from memory in this case,
+        // using `src.layout` to figure out which bytes to use for the 1st and 2nd field.
+        // We have to write them to `dest` at the offsets they were *read at*, which is
+        // not necessarily the same as the offsets in `dest.layout`!
+        // Hence we do the copy with the source layout on both sides.  We also make sure to write
+        // into memory, because if `dest` is a local we would not even have a way to write
+        // at the `src` offsets; the fact that we came from a different layout would
+        // just be lost.
+        let dest = self.force_allocation(dest)?;
+        self.copy_op_no_validate(
+            src,
+            PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
+        )?;
+
+        if M::enforce_validity(self) {
+            // Data got changed, better make sure it matches the type!
             self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
         }
+
         Ok(())
     }
 
@@ -678,8 +819,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// This is essentially `force_to_memplace`.
     pub fn force_allocation(
         &mut self,
-        place: PlaceTy<'tcx>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+        place: PlaceTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let mplace = match place.place {
             Place::Local { frame, local } => {
                 match *self.stack[frame].locals[local].access()? {
@@ -696,7 +837,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                         let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
                         // We don't have to validate as we can assume the local
                         // was already valid for its type.
-                        self.write_value_to_mplace(value, ptr)?;
+                        self.write_value_to_mplace_no_validate(value, ptr)?;
                         let mplace = ptr.mplace;
                         // Update the local
                         *self.stack[frame].locals[local].access_mut()? =
@@ -715,7 +856,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         &mut self,
         layout: TyLayout<'tcx>,
         kind: MemoryKind<M::MemoryKinds>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
         let ptr = self.memory.allocate(layout.size, layout.align, kind)?;
         Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
@@ -724,7 +865,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn write_discriminant_index(
         &mut self,
         variant_index: usize,
-        dest: PlaceTy<'tcx>,
+        dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         match dest.layout.variants {
             layout::Variants::Single { index } => {
@@ -772,7 +913,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     /// Every place can be read from, so we can turm them into an operand
     #[inline(always)]
-    pub fn place_to_op(&self, place: PlaceTy<'tcx>) -> EvalResult<'tcx, OpTy<'tcx>> {
+    pub fn place_to_op(
+        &self,
+        place: PlaceTy<'tcx, M::PointerTag>
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         let op = match place.place {
             Place::Ptr(mplace) => {
                 Operand::Indirect(mplace)
@@ -785,8 +929,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
     /// Also return some more information so drop doesn't have to run the same code twice.
-    pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx>)
-    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx>)> {
+    pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
+    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
         let vtable = mplace.vtable()?; // also sanity checks the type
         let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
         let layout = self.layout_of(ty)?;
@@ -799,7 +943,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         }
 
         let mplace = MPlaceTy {
-            mplace: MemPlace { extra: None, ..*mplace },
+            mplace: MemPlace { meta: None, ..*mplace },
             layout
         };
         Ok((instance, mplace))
diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs
index 9b507eca363..11d5785bc56 100644
--- a/src/librustc_mir/interpret/snapshot.rs
+++ b/src/librustc_mir/interpret/snapshot.rs
@@ -99,6 +99,8 @@ macro_rules! __impl_snapshot_field {
     ($field:ident, $ctx:expr, $delegate:expr) => ($delegate);
 }
 
+// This assumes the type has two type parameters, first for the tag (set to `()`),
+// then for the id
 macro_rules! impl_snapshot_for {
     // FIXME(mark-i-m): Some of these should be `?` rather than `*`.
     (enum $enum_name:ident {
@@ -108,7 +110,7 @@ macro_rules! impl_snapshot_for {
         impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
             where Ctx: self::SnapshotContext<'a>,
         {
-            type Item = $enum_name<AllocIdSnapshot<'a>>;
+            type Item = $enum_name<(), AllocIdSnapshot<'a>>;
 
             #[inline]
             fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
@@ -129,7 +131,7 @@ macro_rules! impl_snapshot_for {
         impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
             where Ctx: self::SnapshotContext<'a>,
         {
-            type Item = $struct_name<AllocIdSnapshot<'a>>;
+            type Item = $struct_name<(), AllocIdSnapshot<'a>>;
 
             #[inline]
             fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
@@ -175,12 +177,13 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for AllocId
 impl_snapshot_for!(struct Pointer {
     alloc_id,
     offset -> *offset, // just copy offset verbatim
+    tag -> *tag, // just copy tag
 });
 
 impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
     where Ctx: SnapshotContext<'a>,
 {
-    type Item = Scalar<AllocIdSnapshot<'a>>;
+    type Item = Scalar<(), AllocIdSnapshot<'a>>;
 
     fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
         match self {
@@ -206,11 +209,11 @@ impl_snapshot_for!(enum ScalarMaybeUndef {
 impl_stable_hash_for!(struct ::interpret::MemPlace {
     ptr,
     align,
-    extra,
+    meta,
 });
 impl_snapshot_for!(struct MemPlace {
     ptr,
-    extra,
+    meta,
     align -> *align, // just copy alignment verbatim
 });
 
@@ -234,7 +237,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for Place {
 impl<'a, Ctx> Snapshot<'a, Ctx> for Place
     where Ctx: SnapshotContext<'a>,
 {
-    type Item = Place<AllocIdSnapshot<'a>>;
+    type Item = Place<(), AllocIdSnapshot<'a>>;
 
     fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
         match self {
@@ -278,11 +281,11 @@ impl_snapshot_for!(enum LocalValue {
 impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
     where Ctx: SnapshotContext<'a>,
 {
-    type Item = Relocations<AllocIdSnapshot<'a>>;
+    type Item = Relocations<(), AllocIdSnapshot<'a>>;
 
     fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
         Relocations::from_presorted(self.iter()
-            .map(|(size, id)| (*size, id.snapshot(ctx)))
+            .map(|(size, ((), id))| (*size, ((), id.snapshot(ctx))))
             .collect())
     }
 }
@@ -290,7 +293,7 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
 #[derive(Eq, PartialEq)]
 struct AllocationSnapshot<'a> {
     bytes: &'a [u8],
-    relocations: Relocations<AllocIdSnapshot<'a>>,
+    relocations: Relocations<(), AllocIdSnapshot<'a>>,
     undef_mask: &'a UndefMask,
     align: &'a Align,
     mutability: &'a Mutability,
@@ -334,8 +337,8 @@ struct FrameSnapshot<'a, 'tcx: 'a> {
     instance: &'a ty::Instance<'tcx>,
     span: &'a Span,
     return_to_block: &'a StackPopCleanup,
-    return_place: Place<AllocIdSnapshot<'a>>,
-    locals: IndexVec<mir::Local, LocalValue<AllocIdSnapshot<'a>>>,
+    return_place: Option<Place<(), AllocIdSnapshot<'a>>>,
+    locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
     block: &'a mir::BasicBlock,
     stmt: usize,
 }
@@ -359,7 +362,7 @@ impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir,
         } = self;
 
         (mir, instance, span, return_to_block).hash_stable(hcx, hasher);
-        (return_place, locals, block, stmt).hash_stable(hcx, hasher);
+        (return_place.as_ref().map(|r| &**r), locals, block, stmt).hash_stable(hcx, hasher);
     }
 }
 impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
@@ -385,7 +388,7 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
             return_to_block,
             block,
             stmt: *stmt,
-            return_place: return_place.snapshot(ctx),
+            return_place: return_place.map(|r| r.snapshot(ctx)),
             locals: locals.iter().map(|local| local.snapshot(ctx)).collect(),
         }
     }
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 862f61df227..a339fa34ae1 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi;
 
 use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
 use super::{
-    EvalContext, Machine, Value, OpTy, Place, PlaceTy, Operand, StackPopCleanup
+    EvalContext, Machine, Value, OpTy, PlaceTy, MPlaceTy, Operand, StackPopCleanup
 };
 
 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
@@ -39,7 +39,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         use rustc::mir::TerminatorKind::*;
         match terminator.kind {
             Return => {
-                self.dump_place(self.frame().return_place);
+                self.frame().return_place.map(|r| self.dump_place(*r));
                 self.pop_stack_frame()?
             }
 
@@ -205,8 +205,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     fn pass_argument(
         &mut self,
         skip_zst: bool,
-        caller_arg: &mut impl Iterator<Item=OpTy<'tcx>>,
-        callee_arg: PlaceTy<'tcx>,
+        caller_arg: &mut impl Iterator<Item=OpTy<'tcx, M::PointerTag>>,
+        callee_arg: PlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx> {
         if skip_zst && callee_arg.layout.is_zst() {
             // Nothing to do.
@@ -222,7 +222,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         if !Self::check_argument_compat(caller_arg.layout, callee_arg.layout) {
             return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty));
         }
-        self.copy_op(caller_arg, callee_arg)
+        // We allow some transmutes here
+        self.copy_op_transmute(caller_arg, callee_arg)
     }
 
     /// Call this function -- pushing the stack frame and initializing the arguments.
@@ -231,8 +232,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         instance: ty::Instance<'tcx>,
         span: Span,
         caller_abi: Abi,
-        args: &[OpTy<'tcx>],
-        dest: Option<PlaceTy<'tcx>>,
+        args: &[OpTy<'tcx, M::PointerTag>],
+        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
         ret: Option<mir::BasicBlock>,
     ) -> EvalResult<'tcx> {
         trace!("eval_fn_call: {:#?}", instance);
@@ -285,15 +286,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                     None => return Ok(()),
                 };
 
-                let return_place = match dest {
-                    Some(place) => *place,
-                    None => Place::null(&self), // any access will error. good!
-                };
                 self.push_stack_frame(
                     instance,
                     span,
                     mir,
-                    return_place,
+                    dest,
                     StackPopCleanup::Goto(ret),
                 )?;
 
@@ -330,7 +327,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                     // last incoming argument.  These two iterators do not have the same type,
                     // so to keep the code paths uniform we accept an allocation
                     // (for RustCall ABI only).
-                    let caller_args : Cow<[OpTy<'tcx>]> =
+                    let caller_args : Cow<[OpTy<'tcx, M::PointerTag>]> =
                         if caller_abi == Abi::RustCall && !args.is_empty() {
                             // Untuple
                             let (&untuple_arg, args) = args.split_last().unwrap();
@@ -339,7 +336,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                                 .chain((0..untuple_arg.layout.fields.count()).into_iter()
                                     .map(|i| self.operand_field(untuple_arg, i as u64))
                                 )
-                                .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?)
+                                .collect::<EvalResult<Vec<OpTy<'tcx, M::PointerTag>>>>()?)
                         } else {
                             // Plain arg passing
                             Cow::from(args)
@@ -382,10 +379,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                             ));
                         }
                     } else {
-                        // FIXME: The caller thinks this function cannot return. How do
-                        // we verify that the callee agrees?
-                        // On the plus side, the the callee ever writes to its return place,
-                        // that will be detected as UB (because we set that to NULL above).
+                        let callee_layout =
+                            self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?;
+                        if !callee_layout.abi.is_uninhabited() {
+                            return err!(FunctionRetMismatch(
+                                self.tcx.types.never, callee_layout.ty
+                            ));
+                        }
                     }
                     Ok(())
                 })();
@@ -426,7 +426,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     fn drop_in_place(
         &mut self,
-        place: PlaceTy<'tcx>,
+        place: PlaceTy<'tcx, M::PointerTag>,
         instance: ty::Instance<'tcx>,
         span: Span,
         target: mir::BasicBlock,
@@ -451,14 +451,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         };
 
         let ty = self.tcx.mk_unit(); // return type is ()
-        let dest = PlaceTy::null(&self, self.layout_of(ty)?);
+        let dest = MPlaceTy::dangling(self.layout_of(ty)?, &self);
 
         self.eval_fn_call(
             instance,
             span,
             Abi::Rust,
             &[arg],
-            Some(dest),
+            Some(dest.into()),
             Some(target),
         )
     }
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 5ea588b957a..227c85772d2 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -12,8 +12,6 @@ use rustc::ty::{self, Ty};
 use rustc::ty::layout::{Size, Align, LayoutOf};
 use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
 
-use syntax::ast::Mutability;
-
 use super::{EvalContext, Machine, MemoryKind};
 
 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
@@ -27,9 +25,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         &mut self,
         ty: Ty<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> EvalResult<'tcx, Pointer> {
+    ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
         debug!("get_vtable(trait_ref={:?})", trait_ref);
 
+        // FIXME: Cache this!
+
         let layout = self.layout_of(trait_ref.self_ty())?;
         assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
         let size = layout.size.bytes();
@@ -41,7 +41,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         let vtable = self.memory.allocate(
             ptr_size * (3 + methods.len() as u64),
             ptr_align,
-            MemoryKind::Stack,
+            MemoryKind::Vtable,
         )?;
 
         let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
@@ -63,10 +63,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
             }
         }
 
-        self.memory.intern_static(
-            vtable.alloc_id,
-            Mutability::Immutable,
-        )?;
+        self.memory.mark_immutable(vtable.alloc_id)?;
 
         Ok(vtable)
     }
@@ -74,7 +71,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Return the drop fn instance as well as the actual dynamic type
     pub fn read_drop_type_from_vtable(
         &self,
-        vtable: Pointer,
+        vtable: Pointer<M::PointerTag>,
     ) -> EvalResult<'tcx, (ty::Instance<'tcx>, ty::Ty<'tcx>)> {
         // we don't care about the pointee type, we just want a pointer
         let pointer_align = self.tcx.data_layout.pointer_align;
@@ -90,7 +87,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
 
     pub fn read_size_and_align_from_vtable(
         &self,
-        vtable: Pointer,
+        vtable: Pointer<M::PointerTag>,
     ) -> EvalResult<'tcx, (Size, Align)> {
         let pointer_size = self.pointer_size();
         let pointer_align = self.tcx.data_layout.pointer_align;
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index f481238bd5b..c446980d049 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use std::fmt::Write;
+use std::hash::Hash;
 
 use syntax_pos::symbol::Symbol;
 use rustc::ty::layout::{self, Size, Align, TyLayout};
@@ -80,13 +81,13 @@ pub enum PathElem {
 }
 
 /// State for tracking recursive validation of references
-pub struct RefTracking<'tcx> {
-    pub seen: FxHashSet<(OpTy<'tcx>)>,
-    pub todo: Vec<(OpTy<'tcx>, Vec<PathElem>)>,
+pub struct RefTracking<'tcx, Tag> {
+    pub seen: FxHashSet<(OpTy<'tcx, Tag>)>,
+    pub todo: Vec<(OpTy<'tcx, Tag>, Vec<PathElem>)>,
 }
 
-impl<'tcx> RefTracking<'tcx> {
-    pub fn new(op: OpTy<'tcx>) -> Self {
+impl<'tcx, Tag: Copy+Eq+Hash> RefTracking<'tcx, Tag> {
+    pub fn new(op: OpTy<'tcx, Tag>) -> Self {
         let mut ref_tracking = RefTracking {
             seen: FxHashSet(),
             todo: vec![(op, Vec::new())],
@@ -128,7 +129,7 @@ fn path_format(path: &Vec<PathElem>) -> String {
     out
 }
 
-fn scalar_format(value: ScalarMaybeUndef) -> String {
+fn scalar_format<Tag>(value: ScalarMaybeUndef<Tag>) -> String {
     match value {
         ScalarMaybeUndef::Undef =>
             "uninitialized bytes".to_owned(),
@@ -143,9 +144,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Make sure that `value` is valid for `ty`, *assuming* `ty` is a primitive type.
     fn validate_primitive_type(
         &self,
-        value: ValTy<'tcx>,
+        value: ValTy<'tcx, M::PointerTag>,
         path: &Vec<PathElem>,
-        ref_tracking: Option<&mut RefTracking<'tcx>>,
+        ref_tracking: Option<&mut RefTracking<'tcx, M::PointerTag>>,
         const_mode: bool,
     ) -> EvalResult<'tcx> {
         // Go over all the primitive types
@@ -185,7 +186,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                     let tail = self.tcx.struct_tail(place.layout.ty);
                     match tail.sty {
                         ty::Dynamic(..) => {
-                            let vtable = try_validation!(place.extra.unwrap().to_ptr(),
+                            let vtable = try_validation!(place.meta.unwrap().to_ptr(),
                                 "non-pointer vtable in fat pointer", path);
                             try_validation!(self.read_drop_type_from_vtable(vtable),
                                 "invalid drop fn in vtable", path);
@@ -194,7 +195,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                             // FIXME: More checks for the vtable.
                         }
                         ty::Slice(..) | ty::Str => {
-                            try_validation!(place.extra.unwrap().to_usize(self),
+                            try_validation!(place.meta.unwrap().to_usize(self),
                                 "non-integer slice length in fat pointer", path);
                         }
                         ty::Foreign(..) => {
@@ -207,7 +208,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 // for safe ptrs, also check the ptr values itself
                 if !ty.is_unsafe_ptr() {
                     // Make sure this is non-NULL and aligned
-                    let (size, align) = self.size_and_align_of(place.extra, place.layout)?;
+                    let (size, align) = self.size_and_align_of(place.meta, place.layout)?
+                        // for the purpose of validity, consider foreign types to have
+                        // alignment and size determined by the layout (size will be 0,
+                        // alignment should take attributes into account).
+                        .unwrap_or_else(|| place.layout.size_and_align());
                     match self.memory.check_align(place.ptr, align) {
                         Ok(_) => {},
                         Err(err) => match err.kind {
@@ -217,7 +222,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                                 return validation_failure!("unaligned reference", path),
                             _ =>
                                 return validation_failure!(
-                                    "dangling (deallocated) reference", path
+                                    "dangling (out-of-bounds) reference (might be NULL at \
+                                     run-time)",
+                                    path
                                 ),
                         }
                     }
@@ -272,7 +279,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// Make sure that `value` matches the
     fn validate_scalar_layout(
         &self,
-        value: ScalarMaybeUndef,
+        value: ScalarMaybeUndef<M::PointerTag>,
         size: Size,
         path: &Vec<PathElem>,
         layout: &layout::Scalar,
@@ -363,9 +370,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     /// validation (e.g., pointer values are fine in integers at runtime).
     pub fn validate_operand(
         &self,
-        dest: OpTy<'tcx>,
+        dest: OpTy<'tcx, M::PointerTag>,
         path: &mut Vec<PathElem>,
-        mut ref_tracking: Option<&mut RefTracking<'tcx>>,
+        mut ref_tracking: Option<&mut RefTracking<'tcx, M::PointerTag>>,
         const_mode: bool,
     ) -> EvalResult<'tcx> {
         trace!("validate_operand: {:?}, {:?}", *dest, dest.layout.ty);
@@ -489,9 +496,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                     }
                     // Special handling for arrays/slices of builtin integer types
                     ty::Array(tys, ..) | ty::Slice(tys) if {
-                        // This optimization applies only for integer types
+                        // This optimization applies only for integer and floating point types
+                        // (i.e., types that can hold arbitrary bytes).
                         match tys.sty {
-                            ty::Int(..) | ty::Uint(..) => true,
+                            ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
                             _ => false,
                         }
                     } => {
@@ -503,9 +511,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                         // This is the size in bytes of the whole array.
                         let size = Size::from_bytes(ty_size * len);
 
-                        match self.memory.read_bytes(dest.ptr, size) {
+                        // In run-time mode, we accept pointers in here.  This is actually more
+                        // permissive than a per-element check would be, e.g. we accept
+                        // an &[u8] that contains a pointer even though bytewise checking would
+                        // reject it.  However, that's good: We don't inherently want
+                        // to reject those pointers, we just do not have the machinery to
+                        // talk about parts of a pointer.
+                        // We also accept undef, for consistency with the type-based checks.
+                        match self.memory.check_bytes(
+                            dest.ptr,
+                            size,
+                            /*allow_ptr_and_undef*/!const_mode,
+                        ) {
                             // In the happy case, we needn't check anything else.
-                            Ok(_) => {},
+                            Ok(()) => {},
                             // Some error happened, try to provide a more detailed description.
                             Err(err) => {
                                 // For some errors we might be able to provide extra information
@@ -552,11 +571,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         match layout.ty.sty {
             // generators and closures.
             ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
-                if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
-                    let freevar = self.tcx.with_freevars(node_id, |fv| fv[field]);
-                    PathElem::ClosureVar(self.tcx.hir.name(freevar.var_id()))
+                if let Some(upvar) = self.tcx.optimized_mir(def_id).upvar_decls.get(field) {
+                    PathElem::ClosureVar(upvar.debug_name)
                 } else {
-                    // The closure is not local, so we cannot get the name
+                    // Sometimes the index is beyond the number of freevars (seen
+                    // for a generator).
                     PathElem::ClosureVar(Symbol::intern(&field.to_string()))
                 }
             }
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index b2fa8349384..dd83d3157ba 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -907,22 +907,20 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             !impl_ty.needs_subst() && !impl_ty.has_escaping_regions());
 
     if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty {
-        if let Some(principal) = trait_ty.principal() {
-            let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
-            assert!(!poly_trait_ref.has_escaping_regions());
-
-            // Walk all methods of the trait, including those of its supertraits
-            let methods = tcx.vtable_methods(poly_trait_ref);
-            let methods = methods.iter().cloned().filter_map(|method| method)
-                .map(|(def_id, substs)| ty::Instance::resolve(
-                        tcx,
-                        ty::ParamEnv::reveal_all(),
-                        def_id,
-                        substs).unwrap())
-                .filter(|&instance| should_monomorphize_locally(tcx, &instance))
-                .map(|instance| create_fn_mono_item(instance));
-            output.extend(methods);
-        }
+        let poly_trait_ref = trait_ty.principal().with_self_ty(tcx, impl_ty);
+        assert!(!poly_trait_ref.has_escaping_regions());
+
+        // Walk all methods of the trait, including those of its supertraits
+        let methods = tcx.vtable_methods(poly_trait_ref);
+        let methods = methods.iter().cloned().filter_map(|method| method)
+            .map(|(def_id, substs)| ty::Instance::resolve(
+                    tcx,
+                    ty::ParamEnv::reveal_all(),
+                    def_id,
+                    substs).unwrap())
+            .filter(|&instance| should_monomorphize_locally(tcx, &instance))
+            .map(|instance| create_fn_mono_item(instance));
+        output.extend(methods);
         // Also add the destructor
         visit_drop_use(tcx, impl_ty, false, output);
     }
@@ -1163,7 +1161,7 @@ fn collect_miri<'a, 'tcx>(
         }
         Some(AllocType::Memory(alloc)) => {
             trace!("collecting {:?} with {:#?}", alloc_id, alloc);
-            for &inner in alloc.relocations.values() {
+            for &((), inner) in alloc.relocations.values() {
                 collect_miri(tcx, inner, output);
             }
         },
@@ -1272,7 +1270,7 @@ fn collect_const<'a, 'tcx>(
         ConstValue::Scalar(Scalar::Ptr(ptr)) =>
             collect_miri(tcx, ptr.alloc_id, output),
         ConstValue::ByRef(_id, alloc, _offset) => {
-            for &id in alloc.relocations.values() {
+            for &((), id) in alloc.relocations.values() {
                 collect_miri(tcx, id, output);
             }
         }
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index f0ea93bfffd..4c4d56c8938 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -320,12 +320,13 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                 output.push(']');
             },
             ty::Dynamic(ref trait_data, ..) => {
-                if let Some(principal) = trait_data.principal() {
-                    self.push_def_path(principal.def_id(), output);
-                    self.push_type_params(principal.skip_binder().substs,
-                        trait_data.projection_bounds(),
-                        output);
-                }
+                let principal = trait_data.principal();
+                self.push_def_path(principal.def_id(), output);
+                self.push_type_params(
+                    principal.skip_binder().substs,
+                    trait_data.projection_bounds(),
+                    output,
+                );
             },
             ty::Foreign(did) => self.push_def_path(did, output),
             ty::FnDef(..) |
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 040ee35632c..5963f1a481c 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -19,7 +19,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 
 use rustc::mir::*;
 use rustc::mir::visit::*;
-use rustc::ty::{self, Instance, Ty, TyCtxt};
+use rustc::ty::{self, Instance, InstanceDef, Ty, TyCtxt};
 use rustc::ty::subst::{Subst,Substs};
 
 use std::collections::VecDeque;
@@ -100,12 +100,21 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
                                                                       param_env,
                                                                       callee_def_id,
                                                                       substs) {
-                                callsites.push_back(CallSite {
-                                    callee: instance.def_id(),
-                                    substs: instance.substs,
-                                    bb,
-                                    location: terminator.source_info
-                                });
+                                let is_virtual =
+                                    if let InstanceDef::Virtual(..) = instance.def {
+                                        true
+                                    } else {
+                                        false
+                                    };
+
+                                if !is_virtual {
+                                    callsites.push_back(CallSite {
+                                        callee: instance.def_id(),
+                                        substs: instance.substs,
+                                        bb,
+                                        location: terminator.source_info
+                                    });
+                                }
                             }
                         }
                     }
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 17fe78d325c..5e7050caeaf 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -495,20 +495,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     this.super_place(place, context, location);
                     match proj.elem {
                         ProjectionElem::Deref => {
-                            if let Mode::Fn = this.mode {
-                                this.add(Qualif::NOT_CONST);
-                            } else {
-                                let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
-                                if let ty::RawPtr(_) = base_ty.sty {
-                                    if !this.tcx.sess.features_untracked().const_raw_ptr_deref {
-                                        emit_feature_err(
-                                            &this.tcx.sess.parse_sess, "const_raw_ptr_deref",
-                                            this.span, GateIssue::Language,
-                                            &format!(
-                                                "dereferencing raw pointers in {}s is unstable",
-                                                this.mode,
-                                            ),
-                                        );
+                            this.add(Qualif::NOT_CONST);
+                            let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
+                            match this.mode {
+                                Mode::Fn => {},
+                                _ => {
+                                    if let ty::RawPtr(_) = base_ty.sty {
+                                        if !this.tcx.sess.features_untracked().const_raw_ptr_deref {
+                                            emit_feature_err(
+                                                &this.tcx.sess.parse_sess, "const_raw_ptr_deref",
+                                                this.span, GateIssue::Language,
+                                                &format!(
+                                                    "dereferencing raw pointers in {}s is unstable",
+                                                    this.mode,
+                                                ),
+                                            );
+                                        }
                                     }
                                 }
                             }
@@ -732,8 +734,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     (CastTy::Ptr(_), CastTy::Int(_)) |
                     (CastTy::FnPtr, CastTy::Int(_)) => {
                         if let Mode::Fn = self.mode {
+                            // in normal functions, mark such casts as not promotable
                             self.add(Qualif::NOT_CONST);
                         } else if !self.tcx.sess.features_untracked().const_raw_ptr_to_usize_cast {
+                            // in const fn and constants require the feature gate
+                            // FIXME: make it unsafe inside const fn and constants
                             emit_feature_err(
                                 &self.tcx.sess.parse_sess, "const_raw_ptr_to_usize_cast",
                                 self.span, GateIssue::Language,
@@ -756,8 +761,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                             op == BinOp::Offset);
 
                     if let Mode::Fn = self.mode {
+                        // raw pointer operations are not allowed inside promoteds
                         self.add(Qualif::NOT_CONST);
                     } else if !self.tcx.sess.features_untracked().const_compare_raw_pointers {
+                        // require the feature gate inside constants and const fn
+                        // FIXME: make it unsafe to use these operations
                         emit_feature_err(
                             &self.tcx.sess.parse_sess,
                             "const_compare_raw_pointers",
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 60679d6d430..989851bb1b9 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -93,8 +93,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
         let ty_def_id = match self.tcx.type_of(item_def_id).sty {
             ty::Adt(adt, _) => adt.did,
             ty::Foreign(did) => did,
-            ty::Dynamic(ref obj, ..) if obj.principal().is_some() =>
-                obj.principal().unwrap().def_id(),
+            ty::Dynamic(ref obj, ..) => obj.principal().def_id(),
             ty::Projection(ref proj) => proj.trait_ref(self.tcx).def_id,
             _ => return Some(AccessLevel::Public)
         };
@@ -484,7 +483,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
         let ty_def_id = match ty.sty {
             ty::Adt(adt, _) => Some(adt.did),
             ty::Foreign(did) => Some(did),
-            ty::Dynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
+            ty::Dynamic(ref obj, ..) => Some(obj.principal().def_id()),
             ty::Projection(ref proj) => Some(proj.item_def_id),
             ty::FnDef(def_id, ..) |
             ty::Closure(def_id, ..) |
@@ -1456,7 +1455,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
         let ty_def_id = match ty.sty {
             ty::Adt(adt, _) => Some(adt.did),
             ty::Foreign(did) => Some(did),
-            ty::Dynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
+            ty::Dynamic(ref obj, ..) => Some(obj.principal().def_id()),
             ty::Projection(ref proj) => {
                 if self.required_visibility == ty::Visibility::Invisible {
                     // Conservatively approximate the whole type alias as public without
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 96eb6916322..6b28fd09174 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -874,7 +874,7 @@ impl LayoutDetails {
 /// to those obtained from `layout_of(ty)`, as we need to produce
 /// layouts for which Rust types do not exist, such as enum variants
 /// or synthetic fields of enums (i.e. discriminants) and fat pointers.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct TyLayout<'a, Ty> {
     pub ty: Ty,
     pub details: &'a LayoutDetails
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 3f1e8ee5528..9c0f945326d 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -576,6 +576,9 @@ pub struct TargetOptions {
     /// the functions in the executable are not randomized and can be used
     /// during an exploit of a vulnerability in any code.
     pub position_independent_executables: bool,
+    /// Determines if the target always requires using the PLT for indirect
+    /// library calls or not. This controls the default value of the `-Z plt` flag.
+    pub needs_plt: bool,
     /// Either partial, full, or off. Full RELRO makes the dynamic linker
     /// resolve all symbols at startup and marks the GOT read-only before
     /// starting the program, preventing overwriting the GOT.
@@ -720,6 +723,7 @@ impl Default for TargetOptions {
             has_rpath: false,
             no_default_libraries: true,
             position_independent_executables: false,
+            needs_plt: false,
             relro_level: RelroLevel::None,
             pre_link_objects_exe: Vec::new(),
             pre_link_objects_exe_crt: Vec::new(),
@@ -1009,6 +1013,7 @@ impl Target {
         key!(has_rpath, bool);
         key!(no_default_libraries, bool);
         key!(position_independent_executables, bool);
+        key!(needs_plt, bool);
         try!(key!(relro_level, RelroLevel));
         key!(archive_format);
         key!(allow_asm, bool);
@@ -1217,6 +1222,7 @@ impl ToJson for Target {
         target_option_val!(has_rpath);
         target_option_val!(no_default_libraries);
         target_option_val!(position_independent_executables);
+        target_option_val!(needs_plt);
         target_option_val!(relro_level);
         target_option_val!(archive_format);
         target_option_val!(allow_asm);
diff --git a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs
index 72b5bd27c7d..fd61067ba51 100644
--- a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs
+++ b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs
@@ -17,6 +17,9 @@ pub fn target() -> TargetResult {
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
     base.stack_probes = true;
     base.has_elf_tls = false;
+    // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
+    // breaks code gen. See LLVM bug 36743
+    base.needs_plt = true;
 
     Ok(Target {
         llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml
index cd21ee601a7..16f0f11757a 100644
--- a/src/librustc_traits/Cargo.toml
+++ b/src/librustc_traits/Cargo.toml
@@ -16,5 +16,5 @@ rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-chalk-engine = { version = "0.7.0", default-features=false }
+chalk-engine = { version = "0.8.0", default-features=false }
 smallvec = { version = "0.6.5", features = ["union"] }
diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs
index 4c28df97bdf..dea3aa4372a 100644
--- a/src/librustc_traits/chalk_context.rs
+++ b/src/librustc_traits/chalk_context.rs
@@ -19,6 +19,7 @@ use rustc::traits::{
     ExClauseFold,
     ExClauseLift,
     Goal,
+    GoalKind,
     ProgramClause,
     QuantifierKind
 };
@@ -92,7 +93,7 @@ impl context::Context for ChalkArenas<'tcx> {
 
     type DomainGoal = DomainGoal<'tcx>;
 
-    type BindersGoal = ty::Binder<&'tcx Goal<'tcx>>;
+    type BindersGoal = ty::Binder<Goal<'tcx>>;
 
     type Parameter = Kind<'tcx>;
 
@@ -102,14 +103,6 @@ impl context::Context for ChalkArenas<'tcx> {
 
     type UnificationResult = InferOk<'tcx, ()>;
 
-    fn into_goal(domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> {
-        Goal::DomainGoal(domain_goal)
-    }
-
-    fn cannot_prove() -> Goal<'tcx> {
-        Goal::CannotProve
-    }
-
     fn goal_in_environment(
         env: &ty::ParamEnv<'tcx>,
         goal: Goal<'tcx>,
@@ -251,15 +244,23 @@ impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
 impl context::InferenceTable<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
     for ChalkInferenceContext<'cx, 'gcx, 'tcx>
 {
+    fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> {
+        self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal))
+    }
+
+    fn cannot_prove(&self) -> Goal<'tcx> {
+        self.infcx.tcx.mk_goal(GoalKind::CannotProve)
+    }
+
     fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> {
-        match goal {
-            Goal::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"),
-            Goal::And(left, right) => HhGoal::And(*left, *right),
-            Goal::Not(subgoal) => HhGoal::Not(*subgoal),
-            Goal::DomainGoal(d) => HhGoal::DomainGoal(d),
-            Goal::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
-            Goal::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
-            Goal::CannotProve => HhGoal::CannotProve,
+        match *goal {
+            GoalKind::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"),
+            GoalKind::And(left, right) => HhGoal::And(left, right),
+            GoalKind::Not(subgoal) => HhGoal::Not(subgoal),
+            GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d),
+            GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
+            GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
+            GoalKind::CannotProve => HhGoal::CannotProve,
         }
     }
 
@@ -363,21 +364,21 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
 
     fn instantiate_binders_universally(
         &mut self,
-        _arg: &ty::Binder<&'tcx Goal<'tcx>>,
+        _arg: &ty::Binder<Goal<'tcx>>,
     ) -> Goal<'tcx> {
         panic!("FIXME -- universal instantiation needs sgrif's branch")
     }
 
     fn instantiate_binders_existentially(
         &mut self,
-        arg: &ty::Binder<&'tcx Goal<'tcx>>,
+        arg: &ty::Binder<Goal<'tcx>>,
     ) -> Goal<'tcx> {
         let (value, _map) = self.infcx.replace_late_bound_regions_with_fresh_var(
             DUMMY_SP,
             LateBoundRegionConversionTime::HigherRankedType,
             arg,
         );
-        *value
+        value
     }
 
     fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box<dyn Debug + 'v> {
diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs
index ad724babe49..181106d3f84 100644
--- a/src/librustc_traits/lowering.rs
+++ b/src/librustc_traits/lowering.rs
@@ -13,7 +13,14 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::map::definitions::DefPathData;
 use rustc::hir::{self, ImplPolarity};
 use rustc::traits::{
-    Clause, Clauses, DomainGoal, FromEnv, Goal, PolyDomainGoal, ProgramClause, WellFormed,
+    Clause,
+    Clauses,
+    DomainGoal,
+    FromEnv,
+    GoalKind,
+    PolyDomainGoal,
+    ProgramClause,
+    WellFormed,
     WhereClause,
 };
 use rustc::ty::query::Providers;
@@ -249,7 +256,7 @@ fn program_clauses_for_trait<'a, 'tcx>(
     let impl_trait: DomainGoal = trait_pred.lower();
 
     // `FromEnv(Self: Trait<P1..Pn>)`
-    let from_env_goal = impl_trait.into_from_env_goal().into_goal();
+    let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal());
     let hypotheses = tcx.intern_goals(&[from_env_goal]);
 
     // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
@@ -308,7 +315,7 @@ fn program_clauses_for_trait<'a, 'tcx>(
     let wf_clause = ProgramClause {
         goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
         hypotheses: tcx.mk_goals(
-            wf_conditions.map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+            wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
         ),
     };
     let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause)));
@@ -352,10 +359,10 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
         hypotheses: tcx.mk_goals(
             where_clauses
                 .into_iter()
-                .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+                .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
         ),
     };
-    tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))])
+    tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
 }
 
 pub fn program_clauses_for_type_def<'a, 'tcx>(
@@ -388,7 +395,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
             where_clauses
                 .iter()
                 .cloned()
-                .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+                .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
         ),
     };
 
@@ -404,7 +411,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
     // ```
 
     // `FromEnv(Ty<...>)`
-    let from_env_goal = DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal();
+    let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal());
     let hypotheses = tcx.intern_goals(&[from_env_goal]);
 
     // For each where clause `WC`:
@@ -423,10 +430,86 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
 }
 
 pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
-    _tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    _item_id: DefId,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    item_id: DefId,
 ) -> Clauses<'tcx> {
-    unimplemented!()
+    // Rule ProjectionEq-Skolemize
+    //
+    // ```
+    // trait Trait<P1..Pn> {
+    //     type AssocType<Pn+1..Pm>;
+    // }
+    // ```
+    //
+    // `ProjectionEq` can succeed by skolemizing, see "associated type"
+    // chapter for more:
+    // ```
+    // forall<Self, P1..Pn, Pn+1..Pm> {
+    //     ProjectionEq(
+    //         <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
+    //         (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
+    //     )
+    // }
+    // ```
+
+    let item = tcx.associated_item(item_id);
+    debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
+    let trait_id = match item.container {
+        ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id,
+        _ => bug!("not an trait container"),
+    };
+    let trait_ref = ty::TraitRef::identity(tcx, trait_id);
+
+    let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
+    let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
+    let projection_eq = WhereClause::ProjectionEq(ty::ProjectionPredicate {
+        projection_ty,
+        ty: placeholder_ty,
+    });
+
+    let projection_eq_clause = ProgramClause {
+        goal: DomainGoal::Holds(projection_eq),
+        hypotheses: &ty::List::empty(),
+    };
+
+    // Rule WellFormed-AssocTy
+    // ```
+    // forall<Self, P1..Pn, Pn+1..Pm> {
+    //     WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
+    //         :- Implemented(Self: Trait<P1..Pn>)
+    // }
+    // ```
+
+    let trait_predicate = ty::TraitPredicate { trait_ref };
+    let hypothesis = tcx.mk_goal(
+        DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal()
+    );
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
+        hypotheses: tcx.mk_goals(iter::once(hypothesis)),
+    };
+
+    // Rule Implied-Trait-From-AssocTy
+    // ```
+    // forall<Self, P1..Pn, Pn+1..Pm> {
+    //     FromEnv(Self: Trait<P1..Pn>)
+    //         :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
+    // }
+    // ```
+
+    let hypothesis = tcx.mk_goal(
+        DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal()
+    );
+    let from_env_clause = ProgramClause {
+        goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
+        hypotheses: tcx.mk_goals(iter::once(hypothesis)),
+    };
+
+    let clauses = iter::once(projection_eq_clause)
+        .chain(iter::once(wf_clause))
+        .chain(iter::once(from_env_clause));
+    let clauses = clauses.map(|clause| Clause::ForAll(ty::Binder::dummy(clause)));
+    tcx.mk_clauses(clauses)
 }
 
 pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
@@ -435,10 +518,11 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
 ) -> Clauses<'tcx> {
     // Rule Normalize-From-Impl (see rustc guide)
     //
-    // ```impl<P0..Pn> Trait<A1..An> for A0
-    // {
+    // ```
+    // impl<P0..Pn> Trait<A1..An> for A0 {
     //     type AssocType<Pn+1..Pm> = T;
-    // }```
+    // }
+    // ```
     //
     // FIXME: For the moment, we don't account for where clauses written on the associated
     // ty definition (i.e. in the trait def, as in `type AssocType<T> where T: Sized`).
@@ -482,10 +566,10 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
         hypotheses: tcx.mk_goals(
             hypotheses
                 .into_iter()
-                .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+                .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
         ),
     };
-    tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))])
+    tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
 }
 
 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e4ad02595d1..32889ef8698 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -30,7 +30,7 @@ use std::slice;
 use require_c_abi_if_variadic;
 use util::common::ErrorReported;
 use util::nodemap::FxHashMap;
-use errors::{FatalError, DiagnosticId};
+use errors::{Applicability, FatalError, DiagnosticId};
 use lint;
 
 use std::iter;
@@ -1092,11 +1092,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                                         trait_str: &str,
                                         name: &str) {
         struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type")
-            .span_label(span, "ambiguous associated type")
-            .note(&format!("specify the type using the syntax `<{} as {}>::{}`",
-                           type_str, trait_str, name))
-            .emit();
-
+            .span_suggestion_with_applicability(
+                span,
+                "use fully-qualified syntax",
+                format!("<{} as {}>::{}", type_str, trait_str, name),
+                Applicability::HasPlaceholders
+            ).emit();
     }
 
     // Search for a bound on a type parameter which includes the associated item
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 285fed9544d..e0ee26cba08 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -73,7 +73,7 @@ enum PointerKind<'tcx> {
     /// No metadata attached, ie pointer to sized type or foreign type
     Thin,
     /// A trait object
-    Vtable(Option<DefId>),
+    Vtable(DefId),
     /// Slice
     Length,
     /// The unsize info of this projection
@@ -105,7 +105,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         Ok(match t.sty {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
             ty::Dynamic(ref tty, ..) =>
-                Some(PointerKind::Vtable(tty.principal().map(|p| p.def_id()))),
+                Some(PointerKind::Vtable(tty.principal().def_id())),
             ty::Adt(def, substs) if def.is_struct() => {
                 match def.non_enum_variant().fields.last() {
                     None => Some(PointerKind::Thin),
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 202789d1d8a..940fa4d3916 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -198,9 +198,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         self.deduce_sig_from_projection(None, &pb)
                     })
                     .next();
-                let kind = object_type
-                    .principal()
-                    .and_then(|p| self.tcx.lang_items().fn_trait_kind(p.def_id()));
+                let kind = self.tcx.lang_items().fn_trait_kind(object_type.principal().def_id());
                 (sig, kind)
             }
             ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 4e5488b432d..75f5bf74c6a 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -290,7 +290,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             .include_raw_pointers()
             .filter_map(|(ty, _)|
                 match ty.sty {
-                    ty::Dynamic(ref data, ..) => data.principal().map(|p| closure(self, ty, p)),
+                    ty::Dynamic(ref data, ..) => Some(closure(self, ty, data.principal())),
                     _ => None,
                 }
             )
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index ec4483204f0..ae02cd64c38 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -452,10 +452,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         match self_ty.sty {
             ty::Dynamic(ref data, ..) => {
-                if let Some(p) = data.principal() {
-                    self.assemble_inherent_candidates_from_object(self_ty, p);
-                    self.assemble_inherent_impl_candidates_for_type(p.def_id());
-                }
+                let p = data.principal();
+                self.assemble_inherent_candidates_from_object(self_ty, p);
+                self.assemble_inherent_impl_candidates_for_type(p.def_id());
             }
             ty::Adt(def, _) => {
                 self.assemble_inherent_impl_candidates_for_type(def.did);
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 28b9dcb9bfd..2006796a100 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -663,8 +663,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 ty::Adt(def, _) => def.did.is_local(),
                 ty::Foreign(did) => did.is_local(),
 
-                ty::Dynamic(ref tr, ..) => tr.principal()
-                    .map_or(false, |p| p.def_id().is_local()),
+                ty::Dynamic(ref tr, ..) => tr.principal().def_id().is_local(),
 
                 ty::Param(_) => true,
 
diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs
index 1955a709dbf..ec979dea4fd 100644
--- a/src/librustc_typeck/coherence/inherent_impls.rs
+++ b/src/librustc_typeck/coherence/inherent_impls.rs
@@ -108,8 +108,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
             ty::Foreign(did) => {
                 self.check_def_id(item, did);
             }
-            ty::Dynamic(ref data, ..) if data.principal().is_some() => {
-                self.check_def_id(item, data.principal().unwrap().def_id());
+            ty::Dynamic(ref data, ..) => {
+                self.check_def_id(item, data.principal().def_id());
             }
             ty::Char => {
                 self.check_primitive_impl(def_id,
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 616ca97a7a7..9b17654d469 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -181,13 +181,12 @@ fn check_impl_overlap<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeI
         // This is something like impl Trait1 for Trait2. Illegal
         // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
 
-        if data.principal().map_or(true, |p| !tcx.is_object_safe(p.def_id())) {
+        if !tcx.is_object_safe(data.principal().def_id()) {
             // This is an error, but it will be reported by wfcheck.  Ignore it here.
             // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
         } else {
             let mut supertrait_def_ids =
-                traits::supertrait_def_ids(tcx,
-                                           data.principal().unwrap().def_id());
+                traits::supertrait_def_ids(tcx, data.principal().def_id());
             if supertrait_def_ids.any(|d| d == trait_def_id) {
                 let sp = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
                 struct_span_err!(tcx.sess,
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
index 254146c0ef3..132da8f5cea 100644
--- a/src/librustc_typeck/outlives/implicit_infer.rs
+++ b/src/librustc_typeck/outlives/implicit_infer.rs
@@ -203,28 +203,27 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 debug!("Dynamic");
                 debug!("field_ty = {}", &field_ty);
                 debug!("ty in field = {}", &ty);
-                if let Some(ex_trait_ref) = obj.principal() {
-                    // Here, we are passing the type `usize` as a
-                    // placeholder value with the function
-                    // `with_self_ty`, since there is no concrete type
-                    // `Self` for a `dyn Trait` at this
-                    // stage. Therefore when checking explicit
-                    // predicates in `check_explicit_predicates` we
-                    // need to ignore checking the explicit_map for
-                    // Self type.
-                    let substs = ex_trait_ref
-                        .with_self_ty(tcx, tcx.types.usize)
-                        .skip_binder()
-                        .substs;
-                    check_explicit_predicates(
-                        tcx,
-                        &ex_trait_ref.skip_binder().def_id,
-                        substs,
-                        required_predicates,
-                        explicit_map,
-                        IgnoreSelfTy(true),
-                    );
-                }
+                let ex_trait_ref = obj.principal();
+                // Here, we are passing the type `usize` as a
+                // placeholder value with the function
+                // `with_self_ty`, since there is no concrete type
+                // `Self` for a `dyn Trait` at this
+                // stage. Therefore when checking explicit
+                // predicates in `check_explicit_predicates` we
+                // need to ignore checking the explicit_map for
+                // Self type.
+                let substs = ex_trait_ref
+                    .with_self_ty(tcx, tcx.types.usize)
+                    .skip_binder()
+                    .substs;
+                check_explicit_predicates(
+                    tcx,
+                    &ex_trait_ref.skip_binder().def_id,
+                    substs,
+                    required_predicates,
+                    explicit_map,
+                    IgnoreSelfTy(true),
+                );
             }
 
             ty::Projection(obj) => {
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 32a591777db..3e523c0c7f5 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -311,11 +311,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 let contra = self.contravariant(variance);
                 self.add_constraints_from_region(current, r, contra);
 
-                if let Some(p) = data.principal() {
-                    let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err);
-                    self.add_constraints_from_trait_ref(
-                        current, *poly_trait_ref.skip_binder(), variance);
-                }
+                let poly_trait_ref = data
+                    .principal()
+                    .with_self_ty(self.tcx(), self.tcx().types.err);
+                self.add_constraints_from_trait_ref(
+                    current, *poly_trait_ref.skip_binder(), variance);
 
                 for projection in data.projection_bounds() {
                     self.add_constraints_from_ty(
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 845bfad7807..8bac007b748 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -9,6 +9,6 @@ path = "lib.rs"
 
 [dependencies]
 pulldown-cmark = { version = "0.1.2", default-features = false }
-minifier = "0.0.19"
+minifier = "0.0.20"
 tempfile = "3"
 parking_lot = "0.6.4"
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ddabef96c7c..2ba1f103971 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2632,47 +2632,44 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 }
             }
             ty::Dynamic(ref obj, ref reg) => {
-                if let Some(principal) = obj.principal() {
-                    let did = principal.def_id();
+                let principal = obj.principal();
+                let did = principal.def_id();
+                inline::record_extern_fqn(cx, did, TypeKind::Trait);
+
+                let mut typarams = vec![];
+                reg.clean(cx).map(|b| typarams.push(GenericBound::Outlives(b)));
+                for did in obj.auto_traits() {
+                    let empty = cx.tcx.intern_substs(&[]);
+                    let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
+                        Some(did), false, vec![], empty);
                     inline::record_extern_fqn(cx, did, TypeKind::Trait);
+                    let bound = GenericBound::TraitBound(PolyTrait {
+                        trait_: ResolvedPath {
+                            path,
+                            typarams: None,
+                            did,
+                            is_generic: false,
+                        },
+                        generic_params: Vec::new(),
+                    }, hir::TraitBoundModifier::None);
+                    typarams.push(bound);
+                }
 
-                    let mut typarams = vec![];
-                    reg.clean(cx).map(|b| typarams.push(GenericBound::Outlives(b)));
-                    for did in obj.auto_traits() {
-                        let empty = cx.tcx.intern_substs(&[]);
-                        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
-                            Some(did), false, vec![], empty);
-                        inline::record_extern_fqn(cx, did, TypeKind::Trait);
-                        let bound = GenericBound::TraitBound(PolyTrait {
-                            trait_: ResolvedPath {
-                                path,
-                                typarams: None,
-                                did,
-                                is_generic: false,
-                            },
-                            generic_params: Vec::new(),
-                        }, hir::TraitBoundModifier::None);
-                        typarams.push(bound);
-                    }
-
-                    let mut bindings = vec![];
-                    for pb in obj.projection_bounds() {
-                        bindings.push(TypeBinding {
-                            name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx),
-                            ty: pb.skip_binder().ty.clean(cx)
-                        });
-                    }
+                let mut bindings = vec![];
+                for pb in obj.projection_bounds() {
+                    bindings.push(TypeBinding {
+                        name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx),
+                        ty: pb.skip_binder().ty.clean(cx)
+                    });
+                }
 
-                    let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
-                        false, bindings, principal.skip_binder().substs);
-                    ResolvedPath {
-                        path,
-                        typarams: Some(typarams),
-                        did,
-                        is_generic: false,
-                    }
-                } else {
-                    Never
+                let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
+                    false, bindings, principal.skip_binder().substs);
+                ResolvedPath {
+                    path,
+                    typarams: Some(typarams),
+                    did,
+                    is_generic: false,
                 }
             }
             ty::Tuple(ref t) => Tuple(t.clean(cx)),
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 5df4862290e..87b4527a2a7 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -44,9 +44,21 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>,
     }
     write_header(class, &mut out).unwrap();
 
-    let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm, None),
-                                         sess.source_map());
+    let lexer = match lexer::StringReader::new_without_err(&sess, fm, None, "Output from rustc:") {
+        Ok(l) => l,
+        Err(_) => {
+            let first_line = src.lines().next().unwrap_or_else(|| "");
+            let mut err = sess.span_diagnostic
+                              .struct_warn(&format!("Invalid doc comment starting with: `{}`\n\
+                                                     (Ignoring this codeblock)",
+                                                    first_line));
+            err.emit();
+            return String::new();
+        }
+    };
+    let mut classifier = Classifier::new(lexer, sess.source_map());
     if classifier.write_source(&mut out).is_err() {
+        classifier.lexer.emit_fatal_errors();
         return format!("<pre>{}</pre>", src);
     }
 
@@ -162,11 +174,10 @@ impl<'a> Classifier<'a> {
         match self.lexer.try_next_token() {
             Ok(tas) => Ok(tas),
             Err(_) => {
-                self.lexer.emit_fatal_errors();
-                self.lexer.sess.span_diagnostic
-                    .struct_warn("Backing out of syntax highlighting")
-                    .note("You probably did not intend to render this as a rust code-block")
-                    .emit();
+                let mut err = self.lexer.sess.span_diagnostic
+                                  .struct_warn("Backing out of syntax highlighting");
+                err.note("You probably did not intend to render this as a rust code-block");
+                err.emit();
                 Err(io::Error::new(io::ErrorKind::Other, ""))
             }
         }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 1c61e73fae0..23f1e15de3c 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -4098,12 +4098,13 @@ impl<'a> fmt::Display for Sidebar<'a> {
                         </div>",
                        version)?;
             }
+        }
 
+        write!(fmt, "<div class=\"sidebar-elems\">")?;
+        if it.is_crate() {
             write!(fmt, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
                    it.name.as_ref().expect("crates always have a name"))?;
         }
-
-        write!(fmt, "<div class=\"sidebar-elems\">")?;
         match it.inner {
             clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?,
             clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?,
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 58ac46d2271..91ff03a327d 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -908,10 +908,9 @@ span.since {
 		padding-top: 0px;
 	}
 
-	.sidebar {
+	body > .sidebar {
 		height: 45px;
 		min-height: 40px;
-		width: calc(100% + 30px);
 		margin: 0;
 		margin-left: -15px;
 		padding: 0 15px;
@@ -1013,6 +1012,10 @@ span.since {
 	.anchor {
 		display: none !important;
 	}
+
+	h1.fqn {
+		overflow: initial;
+	}
 }
 
 @media print {
@@ -1112,6 +1115,18 @@ h4 > .important-traits {
 	top: 2px;
 }
 
+#all-types {
+	text-align: center;
+	border: 1px solid;
+	margin: 0 10px;
+	margin-bottom: 10px;
+	display: block;
+	border-radius: 7px;
+}
+#all-types > p {
+	margin: 5px 0;
+}
+
 @media (max-width: 700px) {
 	h4 > .important-traits {
 		position: absolute;
@@ -1135,6 +1150,9 @@ h4 > .important-traits {
 		background-color: rgba(0,0,0,0);
 		height: 100%;
 	}
+	.sidebar {
+		width: calc(100% + 30px);
+	}
 
 	.show-it {
 		display: block;
@@ -1180,6 +1198,10 @@ h4 > .important-traits {
 	.impl > .collapse-toggle {
 		left: -10px;
 	}
+
+	#all-types {
+		margin: 10px;
+	}
 }
 
 
@@ -1383,17 +1405,6 @@ kbd {
 #main > ul > li {
 	list-style: none;
 }
-#all-types {
-	text-align: center;
-	border: 1px solid;
-	margin: 0 10px;
-	margin-bottom: 10px;
-	display: block;
-	border-radius: 7px;
-}
-#all-types > p {
-	margin: 5px 0;
-}
 
 .non-exhaustive {
 	margin-bottom: 1em;
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index bcdd1b4b088..cd1e3438fc3 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -48,4 +48,13 @@ jemalloc = ["alloc_jemalloc"]
 force_alloc_system = []
 panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
+
+# An off-by-default feature which enables a linux-syscall-like ABI for libstd to
+# interoperate with the host environment. Currently not well documented and
+# requires rebuilding the standard library to use it.
 wasm_syscall = []
+
+# An off-by-default features to enable libstd to assume that wasm-bindgen is in
+# the environment for hooking up some thread-related information like the
+# current thread id and accessing/getting the current thread's TCB
+wasm-bindgen-threads = []
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index f14d55cb2d3..017949291bc 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -726,7 +726,7 @@ impl OpenOptions {
     /// If a file is opened with both read and append access, beware that after
     /// opening, and after every write, the position for reading may be set at the
     /// end of the file. So, before writing, save the current position (using
-    /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read.
+    /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read.
     ///
     /// ## Note
     ///
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index 48a9b2f4a93..5c87035d8e9 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -79,7 +79,7 @@ pub use core::panic::{PanicInfo, Location};
 ///
 /// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow
 /// witnessing a broken invariant through the use of `catch_unwind` (catching a
-/// panic). This trait is a marker trait, so it is automatically implemented for
+/// panic). This trait is an auto trait, so it is automatically implemented for
 /// many types, and it is also structurally composed (e.g. a struct is unwind
 /// safe if all of its components are unwind safe).
 ///
diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
index 8d54728a75f..3b432d05132 100644
--- a/src/libstd/primitive_docs.rs
+++ b/src/libstd/primitive_docs.rs
@@ -908,11 +908,36 @@ mod prim_usize { }
 /// `&mut T` references can be freely coerced into `&T` references with the same referent type, and
 /// references with longer lifetimes can be freely coerced into references with shorter ones.
 ///
+/// Reference equality by address, instead of comparing the values pointed to, is accomplished via
+/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while
+/// [`PartialEq`] compares values.
+///
+/// [`ptr::eq`]: ptr/fn.eq.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+///
+/// ```
+/// use std::ptr;
+///
+/// let five = 5;
+/// let other_five = 5;
+/// let five_ref = &five;
+/// let same_five_ref = &five;
+/// let other_five_ref = &other_five;
+///
+/// assert!(five_ref == same_five_ref);
+/// assert!(five_ref == other_five_ref);
+///
+/// assert!(ptr::eq(five_ref, same_five_ref));
+/// assert!(!ptr::eq(five_ref, other_five_ref));
+/// ```
+///
 /// For more information on how to use references, see [the book's section on "References and
 /// Borrowing"][book-refs].
 ///
 /// [book-refs]: ../book/second-edition/ch04-02-references-and-borrowing.html
 ///
+/// # Trait implementations
+///
 /// The following traits are implemented for all `&T`, regardless of the type of its referent:
 ///
 /// * [`Copy`]
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 17cb614ba11..98845e457b2 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -329,7 +329,7 @@ impl Once {
     /// assert!(handle.join().is_err());
     /// assert_eq!(INIT.is_completed(), false);
     /// ```
-    #[unstable(feature = "once_is_completed", issue = "42")]
+    #[unstable(feature = "once_is_completed", issue = "54890")]
     #[inline]
     pub fn is_completed(&self) -> bool {
         // An `Acquire` load is enough because that makes all the initialization
diff --git a/src/libstd/sys/wasm/mutex_atomics.rs b/src/libstd/sys/wasm/mutex_atomics.rs
index ced6c17ef96..762e807096f 100644
--- a/src/libstd/sys/wasm/mutex_atomics.rs
+++ b/src/libstd/sys/wasm/mutex_atomics.rs
@@ -11,7 +11,8 @@
 use arch::wasm32::atomic;
 use cell::UnsafeCell;
 use mem;
-use sync::atomic::{AtomicUsize, AtomicU64, Ordering::SeqCst};
+use sync::atomic::{AtomicUsize, AtomicU32, Ordering::SeqCst};
+use sys::thread;
 
 pub struct Mutex {
     locked: AtomicUsize,
@@ -70,7 +71,7 @@ impl Mutex {
 }
 
 pub struct ReentrantMutex {
-    owner: AtomicU64,
+    owner: AtomicU32,
     recursions: UnsafeCell<u32>,
 }
 
@@ -91,7 +92,7 @@ unsafe impl Sync for ReentrantMutex {}
 impl ReentrantMutex {
     pub unsafe fn uninitialized() -> ReentrantMutex {
         ReentrantMutex {
-            owner: AtomicU64::new(0),
+            owner: AtomicU32::new(0),
             recursions: UnsafeCell::new(0),
         }
     }
@@ -101,20 +102,20 @@ impl ReentrantMutex {
     }
 
     pub unsafe fn lock(&self) {
-        let me = thread_id();
+        let me = thread::my_id();
         while let Err(owner) = self._try_lock(me) {
-            let val = atomic::wait_i64(self.ptr(), owner as i64, -1);
+            let val = atomic::wait_i32(self.ptr(), owner as i32, -1);
             debug_assert!(val == 0 || val == 1);
         }
     }
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        self._try_lock(thread_id()).is_ok()
+        self._try_lock(thread::my_id()).is_ok()
     }
 
     #[inline]
-    unsafe fn _try_lock(&self, id: u64) -> Result<(), u64> {
+    unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
         let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
         match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
             // we transitioned from unlocked to locked
@@ -153,11 +154,7 @@ impl ReentrantMutex {
     }
 
     #[inline]
-    fn ptr(&self) -> *mut i64 {
-        &self.owner as *const AtomicU64 as *mut i64
+    fn ptr(&self) -> *mut i32 {
+        &self.owner as *const AtomicU32 as *mut i32
     }
 }
-
-fn thread_id() -> u64 {
-    panic!("thread ids not implemented on wasm with atomics yet")
-}
diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs
index bef6c1f3490..4ad89c42b92 100644
--- a/src/libstd/sys/wasm/thread.rs
+++ b/src/libstd/sys/wasm/thread.rs
@@ -69,3 +69,49 @@ pub mod guard {
     pub unsafe fn init() -> Option<Guard> { None }
     pub unsafe fn deinit() {}
 }
+
+cfg_if! {
+    if #[cfg(all(target_feature = "atomics", feature = "wasm-bindgen-threads"))] {
+        #[link(wasm_import_module = "__wbindgen_thread_xform__")]
+        extern {
+            fn __wbindgen_current_id() -> u32;
+            fn __wbindgen_tcb_get() -> u32;
+            fn __wbindgen_tcb_set(ptr: u32);
+        }
+        pub fn my_id() -> u32 {
+            unsafe { __wbindgen_current_id() }
+        }
+
+        // These are currently only ever used in `thread_local_atomics.rs`, if
+        // you'd like to use them be sure to update that and make sure everyone
+        // agrees what's what.
+        pub fn tcb_get() -> *mut u8 {
+            use mem;
+            assert_eq!(mem::size_of::<*mut u8>(), mem::size_of::<u32>());
+            unsafe { __wbindgen_tcb_get() as *mut u8 }
+        }
+
+        pub fn tcb_set(ptr: *mut u8) {
+            unsafe { __wbindgen_tcb_set(ptr as u32); }
+        }
+
+        // FIXME: still need something for hooking exiting a thread to free
+        // data...
+
+    } else if #[cfg(target_feature = "atomics")] {
+        pub fn my_id() -> u32 {
+            panic!("thread ids not implemented on wasm with atomics yet")
+        }
+
+        pub fn tcb_get() -> *mut u8 {
+            panic!("thread local data not implemented on wasm with atomics yet")
+        }
+
+        pub fn tcb_set(ptr: *mut u8) {
+            panic!("thread local data not implemented on wasm with atomics yet")
+        }
+    } else {
+        // stubbed out because no functions actually access these intrinsics
+        // unless atomics are enabled
+    }
+}
diff --git a/src/libstd/sys/wasm/thread_local_atomics.rs b/src/libstd/sys/wasm/thread_local_atomics.rs
index 1394013b4a3..acfe60719f2 100644
--- a/src/libstd/sys/wasm/thread_local_atomics.rs
+++ b/src/libstd/sys/wasm/thread_local_atomics.rs
@@ -8,22 +8,61 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use sys::thread;
+use sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+const MAX_KEYS: usize = 128;
+static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
+
+struct ThreadControlBlock {
+    keys: [*mut u8; MAX_KEYS],
+}
+
+impl ThreadControlBlock {
+    fn new() -> ThreadControlBlock {
+        ThreadControlBlock {
+            keys: [0 as *mut u8; MAX_KEYS],
+        }
+    }
+
+    fn get() -> *mut ThreadControlBlock {
+        let ptr = thread::tcb_get();
+        if !ptr.is_null() {
+            return ptr as *mut ThreadControlBlock
+        }
+        let tcb = Box::into_raw(Box::new(ThreadControlBlock::new()));
+        thread::tcb_set(tcb as *mut u8);
+        tcb
+    }
+}
+
 pub type Key = usize;
 
-pub unsafe fn create(_dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
-    panic!("TLS on wasm with atomics not implemented yet");
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+    drop(dtor); // FIXME: need to figure out how to hook thread exit to run this
+    let key = NEXT_KEY.fetch_add(1, SeqCst);
+    if key >= MAX_KEYS {
+        NEXT_KEY.store(MAX_KEYS, SeqCst);
+        panic!("cannot allocate space for more TLS keys");
+    }
+    // offset by 1 so we never hand out 0. This is currently required by
+    // `sys_common/thread_local.rs` where it can't cope with keys of value 0
+    // because it messes up the atomic management.
+    return key + 1
 }
 
-pub unsafe fn set(_key: Key, _value: *mut u8) {
-    panic!("TLS on wasm with atomics not implemented yet");
+pub unsafe fn set(key: Key, value: *mut u8) {
+    (*ThreadControlBlock::get()).keys[key - 1] = value;
 }
 
-pub unsafe fn get(_key: Key) -> *mut u8 {
-    panic!("TLS on wasm with atomics not implemented yet");
+pub unsafe fn get(key: Key) -> *mut u8 {
+    (*ThreadControlBlock::get()).keys[key - 1]
 }
 
 pub unsafe fn destroy(_key: Key) {
-    panic!("TLS on wasm with atomics not implemented yet");
+    // FIXME: should implement this somehow, this isn't typically called but it
+    // can be called if two threads race to initialize a TLS slot and one ends
+    // up not being needed.
 }
 
 #[inline]
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index a170abb2628..59f100fad1b 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -172,16 +172,22 @@ macro_rules! __thread_local_inner {
                 &'static $crate::cell::UnsafeCell<
                     $crate::option::Option<$t>>>
             {
-                #[cfg(target_arch = "wasm32")]
+                #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
                 static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
                     $crate::thread::__StaticLocalKeyInner::new();
 
                 #[thread_local]
-                #[cfg(all(target_thread_local, not(target_arch = "wasm32")))]
+                #[cfg(all(
+                    target_thread_local,
+                    not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+                ))]
                 static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
                     $crate::thread::__FastLocalKeyInner::new();
 
-                #[cfg(all(not(target_thread_local), not(target_arch = "wasm32")))]
+                #[cfg(all(
+                    not(target_thread_local),
+                    not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
+                ))]
                 static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
                     $crate::thread::__OsLocalKeyInner::new();
 
@@ -302,7 +308,7 @@ impl<T: 'static> LocalKey<T> {
 /// On some platforms like wasm32 there's no threads, so no need to generate
 /// thread locals and we can instead just use plain statics!
 #[doc(hidden)]
-#[cfg(target_arch = "wasm32")]
+#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
 pub mod statik {
     use cell::UnsafeCell;
     use fmt;
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index c8d54a63946..796b2bd3eed 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -203,7 +203,7 @@ pub use self::local::{LocalKey, AccessError};
 // where available, but both are needed.
 
 #[unstable(feature = "libstd_thread_internals", issue = "0")]
-#[cfg(target_arch = "wasm32")]
+#[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
 #[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner;
 #[unstable(feature = "libstd_thread_internals", issue = "0")]
 #[cfg(target_thread_local)]
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index a9ce2365577..e611eb86dc1 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -9,7 +9,14 @@
 // except according to those terms.
 
 use attr::HasAttrs;
-use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
+use feature_gate::{
+    feature_err,
+    EXPLAIN_STMT_ATTR_SYNTAX,
+    Features,
+    get_features,
+    GateIssue,
+    emit_feature_err,
+};
 use {fold, attr};
 use ast;
 use source_map::Spanned;
@@ -73,49 +80,103 @@ impl<'a> StripUnconfigured<'a> {
         if self.in_cfg(node.attrs()) { Some(node) } else { None }
     }
 
+    /// Parse and expand all `cfg_attr` attributes into a list of attributes
+    /// that are within each `cfg_attr` that has a true configuration predicate.
+    ///
+    /// Gives compiler warnigns if any `cfg_attr` does not contain any
+    /// attributes and is in the original source code. Gives compiler errors if
+    /// the syntax of any `cfg_attr` is incorrect.
     pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T {
         node.map_attrs(|attrs| {
-            attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
+            attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect()
         })
     }
 
-    fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
+    /// Parse and expand a single `cfg_attr` attribute into a list of attributes
+    /// when the configuration predicate is true, or otherwise expand into an
+    /// empty list of attributes.
+    ///
+    /// Gives a compiler warning when the `cfg_attr` contains no attribtes and
+    /// is in the original source file. Gives a compiler error if the syntax of
+    /// the attribute is incorrect
+    fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
         if !attr.check_name("cfg_attr") {
-            return Some(attr);
+            return vec![attr];
         }
 
-        let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| {
+        let gate_cfg_attr_multi = if let Some(ref features) = self.features {
+            !features.cfg_attr_multi
+        } else {
+            false
+        };
+        let cfg_attr_span = attr.span;
+
+        let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
             parser.expect(&token::OpenDelim(token::Paren))?;
-            let cfg = parser.parse_meta_item()?;
+
+            let cfg_predicate = parser.parse_meta_item()?;
             parser.expect(&token::Comma)?;
-            let lo = parser.span.lo();
-            let (path, tokens) = parser.parse_meta_item_unrestricted()?;
-            parser.eat(&token::Comma); // Optional trailing comma
+
+            // Presumably, the majority of the time there will only be one attr.
+            let mut expanded_attrs = Vec::with_capacity(1);
+
+            while !parser.check(&token::CloseDelim(token::Paren)) {
+                let lo = parser.span.lo();
+                let (path, tokens) = parser.parse_meta_item_unrestricted()?;
+                expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo)));
+                parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
+            }
+
             parser.expect(&token::CloseDelim(token::Paren))?;
-            Ok((cfg, path, tokens, parser.prev_span.with_lo(lo)))
+            Ok((cfg_predicate, expanded_attrs))
         }) {
             Ok(result) => result,
             Err(mut e) => {
                 e.emit();
-                return None;
+                return Vec::new();
             }
         };
 
-        if attr::cfg_matches(&cfg, self.sess, self.features) {
-            self.process_cfg_attr(ast::Attribute {
+        // Check feature gate and lint on zero attributes in source. Even if the feature is gated,
+        // we still compute as if it wasn't, since the emitted error will stop compilation futher
+        // along the compilation.
+        match (expanded_attrs.len(), gate_cfg_attr_multi) {
+            (0, false) => {
+                // FIXME: Emit unused attribute lint here.
+            },
+            (1, _) => {},
+            (_, true) => {
+                emit_feature_err(
+                    self.sess,
+                    "cfg_attr_multi",
+                    cfg_attr_span,
+                    GateIssue::Language,
+                    "cfg_attr with zero or more than one attributes is experimental",
+                );
+            },
+            (_, false) => {}
+        }
+
+        if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
+            // We call `process_cfg_attr` recursively in case there's a
+            // `cfg_attr` inside of another `cfg_attr`. E.g.
+            //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
+            expanded_attrs.into_iter()
+            .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute {
                 id: attr::mk_attr_id(),
                 style: attr.style,
                 path,
                 tokens,
                 is_sugared_doc: false,
                 span,
-            })
+            }))
+            .collect()
         } else {
-            None
+            Vec::new()
         }
     }
 
-    // Determine if a node with the given attributes should be included in this configuration.
+    /// Determine if a node with the given attributes should be included in this configuration.
     pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
         attrs.iter().all(|attr| {
             if !is_cfg(attr) {
@@ -165,7 +226,7 @@ impl<'a> StripUnconfigured<'a> {
         })
     }
 
-    // Visit attributes on expression and statements (but not attributes on items in blocks).
+    /// Visit attributes on expression and statements (but not attributes on items in blocks).
     fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
         // flag the offending attributes
         for attr in attrs.iter() {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 24ee2464055..84122688c83 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -433,9 +433,6 @@ declare_features! (
     // #[doc(alias = "...")]
     (active, doc_alias, "1.27.0", Some(50146), None),
 
-    // Scoped lints
-    (active, tool_lints, "1.28.0", Some(44690), None),
-
     // Allows irrefutable patterns in if-let and while-let statements (RFC 2086)
     (active, irrefutable_let_patterns, "1.27.0", Some(44495), None),
 
@@ -499,6 +496,12 @@ declare_features! (
 
     // Allows `impl Trait` in bindings (`let`, `const`, `static`)
     (active, impl_trait_in_bindings, "1.30.0", Some(34511), None),
+
+    // #[cfg_attr(predicate, multiple, attributes, here)]
+    (active, cfg_attr_multi, "1.31.0", Some(54881), None),
+
+    // Allows `const _: TYPE = VALUE`
+    (active, underscore_const_names, "1.31.0", Some(54912), None),
 );
 
 declare_features! (
@@ -679,6 +682,8 @@ declare_features! (
     (accepted, pattern_parentheses, "1.31.0", Some(51087), None),
     // Allows the definition of `const fn` functions.
     (accepted, min_const_fn, "1.31.0", Some(53555), None),
+    // Scoped lints
+    (accepted, tool_lints, "1.31.0", Some(44690), None),
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
@@ -1581,6 +1586,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
+            ast::ItemKind::Const(_,_) => {
+                if i.ident.name == "_" {
+                    gate_feature_post!(&self, underscore_const_names, i.span,
+                                        "naming constants with `_` is unstable");
+                }
+            }
+
             ast::ItemKind::ForeignMod(ref foreign_module) => {
                 self.check_abi(foreign_module.abi, i.span);
             }
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index aa47d5bf669..a814c88ee78 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -238,6 +238,19 @@ impl<'a> StringReader<'a> {
         sr
     }
 
+    pub fn new_without_err(sess: &'a ParseSess,
+                           source_file: Lrc<syntax_pos::SourceFile>,
+                           override_span: Option<Span>,
+                           prepend_error_text: &str) -> Result<Self, ()> {
+        let mut sr = StringReader::new_raw(sess, source_file, override_span);
+        if sr.advance_token().is_err() {
+            eprintln!("{}", prepend_error_text);
+            sr.emit_fatal_errors();
+            return Err(());
+        }
+        Ok(sr)
+    }
+
     pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
         let begin = sess.source_map().lookup_byte_offset(span.lo());
         let end = sess.source_map().lookup_byte_offset(span.hi());
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d653ed819fd..c7089a295fc 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -678,7 +678,7 @@ impl<'a> Parser<'a> {
     /// Expect next token to be edible or inedible token.  If edible,
     /// then consume it; if inedible, then return without consuming
     /// anything.  Signal a fatal error if next token is unexpected.
-    fn expect_one_of(&mut self,
+    pub fn expect_one_of(&mut self,
                          edible: &[token::Token],
                          inedible: &[token::Token]) -> PResult<'a,  ()>{
         fn tokens_to_string(tokens: &[TokenType]) -> String {
@@ -772,6 +772,11 @@ impl<'a> Parser<'a> {
                     //   |                   expected one of 8 possible tokens here
                     err.span_label(self.span, label_exp);
                 }
+                _ if self.prev_span == syntax_pos::DUMMY_SP => {
+                    // Account for macro context where the previous span might not be
+                    // available to avoid incorrect output (#54841).
+                    err.span_label(self.span, "unexpected token");
+                }
                 _ => {
                     err.span_label(sp, label_exp);
                     err.span_label(self.span, "unexpected token");
@@ -1430,6 +1435,23 @@ impl<'a> Parser<'a> {
                     attrs.extend(inner_attrs.iter().cloned());
                     Some(body)
                 }
+                token::Interpolated(ref nt) => {
+                    match &nt.0 {
+                        token::NtBlock(..) => {
+                            *at_end = true;
+                            let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+                            attrs.extend(inner_attrs.iter().cloned());
+                            Some(body)
+                        }
+                        _ => {
+                            let token_str = self.this_token_to_string();
+                            let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
+                                                              token_str));
+                            err.span_label(self.span, "expected `;` or `{`");
+                            return Err(err);
+                        }
+                    }
+                }
                 _ => {
                     let token_str = self.this_token_to_string();
                     let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
@@ -3866,6 +3888,9 @@ impl<'a> Parser<'a> {
             // check that a comma comes after every field
             if !ate_comma {
                 let err = self.struct_span_err(self.prev_span, "expected `,`");
+                if let Some(mut delayed) = delayed_err {
+                    delayed.emit();
+                }
                 return Err(err);
             }
             ate_comma = false;
@@ -6321,7 +6346,13 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
-        let id = self.parse_ident()?;
+        let id = match self.token {
+                token::Ident(ident, false) if ident.name == keywords::Underscore.name() => {
+                    self.bump(); // `_`
+                    ident.gensym()
+                    },
+                _ => self.parse_ident()?,
+            };
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
         self.expect(&token::Eq)?;
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index f1ab1d4ddfa..2b1bf1c0290 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -178,6 +178,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::SanitizeAddress;
   case SanitizeMemory:
     return Attribute::SanitizeMemory;
+  case NonLazyBind:
+    return Attribute::NonLazyBind;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index 1070068b998..b6fa9a2fa95 100644
--- a/src/rustllvm/rustllvm.h
+++ b/src/rustllvm/rustllvm.h
@@ -97,6 +97,7 @@ enum LLVMRustAttribute {
   SanitizeThread = 20,
   SanitizeAddress = 21,
   SanitizeMemory = 22,
+  NonLazyBind = 23,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/src/stage0.txt b/src/stage0.txt
index f0967d1ba8a..6e931a84bac 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-09-23
+date: 2018-10-13
 rustc: beta
 cargo: beta
 
diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs
index aab5f1bfb4f..2cf8ce00bfb 100644
--- a/src/test/codegen/naked-functions.rs
+++ b/src/test/codegen/naked-functions.rs
@@ -15,7 +15,7 @@
 #![crate_type = "lib"]
 #![feature(naked_functions)]
 
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
 // CHECK-NEXT: define void @naked_empty()
 #[no_mangle]
 #[naked]
@@ -24,7 +24,7 @@ pub fn naked_empty() {
     // CHECK-NEXT: ret void
 }
 
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
 #[no_mangle]
 #[naked]
 // CHECK-NEXT: define void @naked_with_args(i{{[0-9]+}})
@@ -35,7 +35,7 @@ pub fn naked_with_args(a: isize) {
     // CHECK: ret void
 }
 
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
 // CHECK-NEXT: define i{{[0-9]+}} @naked_with_return()
 #[no_mangle]
 #[naked]
@@ -45,7 +45,7 @@ pub fn naked_with_return() -> isize {
     0
 }
 
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
 // CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
 #[no_mangle]
 #[naked]
@@ -57,7 +57,7 @@ pub fn naked_with_args_and_return(a: isize) -> isize {
     a
 }
 
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
 // CHECK-NEXT: define void @naked_recursive()
 #[no_mangle]
 #[naked]
diff --git a/src/test/codegen/no-plt.rs b/src/test/codegen/no-plt.rs
new file mode 100644
index 00000000000..8f302e57902
--- /dev/null
+++ b/src/test/codegen/no-plt.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: -C relocation-model=pic -Z plt=no
+
+#![crate_type = "lib"]
+
+// We need a function which is normally called through the PLT.
+extern "C" {
+    // CHECK: Function Attrs: nounwind nonlazybind
+    fn getenv(name: *const u8) -> *mut u8;
+}
+
+// Ensure the function gets referenced.
+pub unsafe fn call_through_plt() -> *mut u8 {
+    getenv(b"\0".as_ptr())
+}
+
+// Ensure intrinsics also skip the PLT
+// CHECK: !"RtLibUseGOT"
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index b474e1a0d6c..1abe63afa80 100644
--- a/src/test/mir-opt/basic_assignment.rs
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -55,8 +55,8 @@ fn main() {
 //        StorageDead(_3);
 //        StorageLive(_4);
 //        _4 = std::option::Option<std::boxed::Box<u32>>::None;
-//        AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
 //        FakeRead(ForLet, _4);
+//        AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
 //        StorageLive(_5);
 //        StorageLive(_6);
 //        _6 = move _4;
diff --git a/src/test/mir-opt/inline-trait-method.rs b/src/test/mir-opt/inline-trait-method.rs
new file mode 100644
index 00000000000..0f79f43ee2d
--- /dev/null
+++ b/src/test/mir-opt/inline-trait-method.rs
@@ -0,0 +1,31 @@
+// compile-flags: -Z span_free_formats
+
+fn main() {
+    println!("{}", test(&()));
+}
+
+fn test(x: &dyn X) -> u32 {
+    x.y()
+}
+
+trait X {
+    fn y(&self) -> u32 {
+        1
+    }
+}
+
+impl X for () {
+    fn y(&self) -> u32 {
+        2
+    }
+}
+
+// END RUST SOURCE
+// START rustc.test.Inline.after.mir
+// ...
+// bb0: {
+// ...
+//     _0 = const X::y(move _2) -> bb1;
+// }
+// ...
+// END rustc.test.Inline.after.mir
diff --git a/src/test/run-pass/macros/macro-as-fn-body.rs b/src/test/run-pass/macros/macro-as-fn-body.rs
new file mode 100644
index 00000000000..8c3c9fdc66d
--- /dev/null
+++ b/src/test/run-pass/macros/macro-as-fn-body.rs
@@ -0,0 +1,42 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// run-pass
+//
+// Description - ensure Interpolated blocks can act as valid function bodies
+// Covered cases: free functions, struct methods, and default trait functions
+
+macro_rules! def_fn {
+    ($body:block) => {
+        fn bar() $body
+    }
+}
+
+trait Foo {
+    def_fn!({ println!("foo"); });
+}
+
+struct Baz {}
+
+impl Foo for Baz {}
+
+struct Qux {}
+
+impl Qux {
+    def_fn!({ println!("qux"); });
+}
+
+def_fn!({ println!("quux"); });
+
+pub fn main() {
+    Baz::bar();
+    Qux::bar();
+    bar();
+}
diff --git a/src/test/run-pass/resolve-pseudo-shadowing.rs b/src/test/run-pass/resolve-pseudo-shadowing.rs
index 071279ae7d8..bf6e686bb7b 100644
--- a/src/test/run-pass/resolve-pseudo-shadowing.rs
+++ b/src/test/run-pass/resolve-pseudo-shadowing.rs
@@ -12,7 +12,7 @@
 
 fn check<Clone>(_c: Clone) {
     fn check2() {
-        <() as std::clone::Clone>::clone(&());
+        let _ = <() as std::clone::Clone>::clone(&());
     }
     check2();
 }
diff --git a/src/test/run-pass/tool_lints.rs b/src/test/run-pass/tool_lints.rs
index 24ec43b12f6..2705c03598a 100644
--- a/src/test/run-pass/tool_lints.rs
+++ b/src/test/run-pass/tool_lints.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(tool_lints)]
+
 #![deny(unknown_lints)]
 
 #[allow(clippy::almost_swapped)]
diff --git a/src/test/run-pass/tool_lints_2018_preview.rs b/src/test/run-pass/tool_lints_2018_preview.rs
index 6cd57eaa195..57df3e072a8 100644
--- a/src/test/run-pass/tool_lints_2018_preview.rs
+++ b/src/test/run-pass/tool_lints_2018_preview.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(tool_lints)]
+
 #![feature(rust_2018_preview)]
 #![deny(unknown_lints)]
 
diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs
new file mode 100644
index 00000000000..8c790d7d07e
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-syntax.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.
+
+// compile-pass
+// compile-flags: --error-format=human
+
+/// ```
+/// \__________pkt->size___________/          \_result->size_/ \__pkt->size__/
+/// ```
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr
new file mode 100644
index 00000000000..b5661332e8d
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-syntax.stderr
@@ -0,0 +1,10 @@
+Output from rustc:
+error: unknown start of token: /
+ --> <stdin>:1:1
+  |
+1 | /__________pkt->size___________/          /_result->size_/ /__pkt->size__/
+  | ^
+
+warning: Invalid doc comment starting with: `/__________pkt->size___________/          /_result->size_/ /__pkt->size__/`
+(Ignoring this codeblock)
+
diff --git a/src/test/rustdoc/inline_cross/issue-31948-1.rs b/src/test/rustdoc/inline_cross/issue-31948-1.rs
index e953b66fce1..677aa529f9f 100644
--- a/src/test/rustdoc/inline_cross/issue-31948-1.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948-1.rs
@@ -22,13 +22,13 @@ extern crate rustdoc_nonreachable_impls;
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
 // @has issue_31948_1/trait.Bark.html
-// FIXME(33025): has - '//code' 'for Foo'
+// @has - '//code' 'for Foo'
 // @has - '//code' 'for Wobble'
 // @!has - '//code' 'for Wibble'
 pub use rustdoc_nonreachable_impls::Bark;
 
 // @has issue_31948_1/trait.Woof.html
-// FIXME(33025): has - '//code' 'for Foo'
+// @has - '//code' 'for Foo'
 // @has - '//code' 'for Wobble'
 // @!has - '//code' 'for Wibble'
 pub use rustdoc_nonreachable_impls::Woof;
diff --git a/src/test/rustdoc/inline_cross/issue-31948-2.rs b/src/test/rustdoc/inline_cross/issue-31948-2.rs
index 0423fa1de3b..7b42ed378ef 100644
--- a/src/test/rustdoc/inline_cross/issue-31948-2.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948-2.rs
@@ -22,7 +22,7 @@ extern crate rustdoc_nonreachable_impls;
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
 // @has issue_31948_2/trait.Qux.html
-// FIXME(33025): has - '//code' 'for Foo'
+// @has - '//code' 'for Foo'
 // @has - '//code' 'for Wobble'
 pub use rustdoc_nonreachable_impls::hidden::Qux;
 
diff --git a/src/test/ui-fulldeps/lint_tool_test.rs b/src/test/ui-fulldeps/lint_tool_test.rs
index ebe10b3714f..11b70d1d780 100644
--- a/src/test/ui-fulldeps/lint_tool_test.rs
+++ b/src/test/ui-fulldeps/lint_tool_test.rs
@@ -11,8 +11,8 @@
 // aux-build:lint_tool_test.rs
 // ignore-stage1
 // compile-flags: --cfg foo
+
 #![feature(plugin)]
-#![feature(tool_lints)]
 #![plugin(lint_tool_test)]
 #![allow(dead_code)]
 #![cfg_attr(foo, warn(test_lint))]
diff --git a/src/test/ui/asm/asm-out-assign-imm.nll.stderr b/src/test/ui/asm/asm-out-assign-imm.nll.stderr
index 7fefb6672c7..40a36dd895f 100644
--- a/src/test/ui/asm/asm-out-assign-imm.nll.stderr
+++ b/src/test/ui/asm/asm-out-assign-imm.nll.stderr
@@ -1,5 +1,5 @@
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/asm-out-assign-imm.rs:34:9
+  --> $DIR/asm-out-assign-imm.rs:34:34
    |
 LL |     let x: isize;
    |         - help: make this binding mutable: `mut x`
@@ -7,7 +7,7 @@ LL |     x = 1;
    |     ----- first assignment to `x`
 ...
 LL |         asm!("mov $1, $0" : "=r"(x) : "r"(5));
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                                  ^ cannot assign twice to immutable variable
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/asm/asm-out-assign-imm.stderr b/src/test/ui/asm/asm-out-assign-imm.stderr
index 83cb8092e16..51933cac396 100644
--- a/src/test/ui/asm/asm-out-assign-imm.stderr
+++ b/src/test/ui/asm/asm-out-assign-imm.stderr
@@ -1,11 +1,11 @@
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/asm-out-assign-imm.rs:34:9
+  --> $DIR/asm-out-assign-imm.rs:34:34
    |
 LL |     x = 1;
    |     ----- first assignment to `x`
 ...
 LL |         asm!("mov $1, $0" : "=r"(x) : "r"(5));
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                                  ^ cannot assign twice to immutable variable
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr
index c45873ffd53..755e83daf47 100644
--- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -2,25 +2,19 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:16:36
    |
 LL | fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
-   |                                    ^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<Type as Get>::Value`
+   |                                    ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:25:10
    |
 LL | type X = std::ops::Deref::Target;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<Type as std::ops::Deref>::Target`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as std::ops::Deref>::Target`
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:21:23
    |
 LL |     fn grab(&self) -> Grab::Value;
-   |                       ^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<Type as Grab>::Value`
+   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Grab>::Value`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr b/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr
new file mode 100644
index 00000000000..1156c773b8c
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr
@@ -0,0 +1,24 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/associated-types-subtyping-1.rs:36:13
+   |
+LL | fn method2<'a,'b,T>(x: &'a T, y: &'b T)
+   |            -- -- lifetime `'b` defined here
+   |            |
+   |            lifetime `'a` defined here
+...
+LL |     let _c: <T as Trait<'b>>::Type = a; //~ ERROR E0623
+   |             ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/associated-types-subtyping-1.rs:44:12
+   |
+LL | fn method3<'a,'b,T>(x: &'a T, y: &'b T)
+   |            -- -- lifetime `'b` defined here
+   |            |
+   |            lifetime `'a` defined here
+...
+LL |     let b: <T as Trait<'b>>::Type = make_any();
+   |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/associated-types/associated-types-subtyping-1.rs b/src/test/ui/associated-types/associated-types-subtyping-1.rs
index c3acffff240..479cb359a78 100644
--- a/src/test/ui/associated-types/associated-types-subtyping-1.rs
+++ b/src/test/ui/associated-types/associated-types-subtyping-1.rs
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-compare-mode-nll
-
 #![allow(unused_variables)]
 
+fn make_any<T>() -> T {  loop {} }
+
 trait Trait<'a> {
     type Type;
 
@@ -22,8 +22,8 @@ fn method1<'a,'b,T>(x: &'a T, y: &'b T)
     where T : for<'z> Trait<'z>, 'a : 'b
 {
     // Note that &'static T <: &'a T.
-    let a: <T as Trait<'a>>::Type = loop { };
-    let b: <T as Trait<'b>>::Type = loop { };
+    let a: <T as Trait<'a>>::Type = make_any();
+    let b: <T as Trait<'b>>::Type = make_any();
     let _c: <T as Trait<'a>>::Type = a;
 }
 
@@ -31,8 +31,8 @@ fn method2<'a,'b,T>(x: &'a T, y: &'b T)
     where T : for<'z> Trait<'z>, 'a : 'b
 {
     // Note that &'static T <: &'a T.
-    let a: <T as Trait<'a>>::Type = loop { };
-    let b: <T as Trait<'b>>::Type = loop { };
+    let a: <T as Trait<'a>>::Type = make_any();
+    let b: <T as Trait<'b>>::Type = make_any();
     let _c: <T as Trait<'b>>::Type = a; //~ ERROR E0623
 }
 
@@ -40,8 +40,8 @@ fn method3<'a,'b,T>(x: &'a T, y: &'b T)
     where T : for<'z> Trait<'z>, 'a : 'b
 {
     // Note that &'static T <: &'a T.
-    let a: <T as Trait<'a>>::Type = loop { };
-    let b: <T as Trait<'b>>::Type = loop { };
+    let a: <T as Trait<'a>>::Type = make_any();
+    let b: <T as Trait<'b>>::Type = make_any();
     let _c: <T as Trait<'a>>::Type = b; //~ ERROR E0623
 }
 
@@ -49,8 +49,8 @@ fn method4<'a,'b,T>(x: &'a T, y: &'b T)
     where T : for<'z> Trait<'z>, 'a : 'b
 {
     // Note that &'static T <: &'a T.
-    let a: <T as Trait<'a>>::Type = loop { };
-    let b: <T as Trait<'b>>::Type = loop { };
+    let a: <T as Trait<'a>>::Type = make_any();
+    let b: <T as Trait<'b>>::Type = make_any();
     let _c: <T as Trait<'b>>::Type = b;
 }
 
diff --git a/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr b/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr
index b0f0535b9f6..0cec1975db8 100644
--- a/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr
@@ -22,7 +22,7 @@ LL |         let z = y;
    |                 - borrow later used here
 
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:54:13
+  --> $DIR/borrowck-asm.rs:54:31
    |
 LL |         let x = 3;
    |             -
@@ -31,10 +31,10 @@ LL |         let x = 3;
    |             help: make this binding mutable: `mut x`
 LL |         unsafe {
 LL |             asm!("nop" : "=r"(x));  //[ast]~ ERROR cannot assign twice
-   |             ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                               ^ cannot assign twice to immutable variable
 
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:70:13
+  --> $DIR/borrowck-asm.rs:70:31
    |
 LL |         let x = 3;
    |             -
@@ -43,22 +43,22 @@ LL |         let x = 3;
    |             help: make this binding mutable: `mut x`
 LL |         unsafe {
 LL |             asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign twice
-   |             ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                               ^ cannot assign twice to immutable variable
 
 error[E0381]: use of possibly uninitialized variable: `x`
-  --> $DIR/borrowck-asm.rs:78:13
+  --> $DIR/borrowck-asm.rs:78:32
    |
 LL |             asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `x`
+   |                                ^ use of possibly uninitialized `x`
 
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/borrowck-asm.rs:87:13
+  --> $DIR/borrowck-asm.rs:87:31
    |
 LL |         let y = &*x;
    |                 --- borrow of `x` occurs here
 LL |         unsafe {
 LL |             asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign to `x` because it is borrowed
-   |             ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+   |                               ^ assignment to borrowed `x` occurs here
 ...
 LL |         let z = y;
    |                 - borrow later used here
diff --git a/src/test/ui/borrowck/borrowck-asm.ast.stderr b/src/test/ui/borrowck/borrowck-asm.ast.stderr
index e2e54aa9b8a..5856a1b0790 100644
--- a/src/test/ui/borrowck/borrowck-asm.ast.stderr
+++ b/src/test/ui/borrowck/borrowck-asm.ast.stderr
@@ -19,31 +19,31 @@ LL |             asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use
    |                                ^ use of borrowed `x`
 
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:54:13
+  --> $DIR/borrowck-asm.rs:54:31
    |
 LL |         let x = 3;
    |             - first assignment to `x`
 LL |         unsafe {
 LL |             asm!("nop" : "=r"(x));  //[ast]~ ERROR cannot assign twice
-   |             ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                               ^ cannot assign twice to immutable variable
 
 error[E0506]: cannot assign to `a` because it is borrowed
-  --> $DIR/borrowck-asm.rs:60:13
+  --> $DIR/borrowck-asm.rs:60:31
    |
 LL |         let b = &*a;
    |                  -- borrow of `a` occurs here
 LL |         unsafe {
 LL |             asm!("nop" : "=r"(a));  //[ast]~ ERROR cannot assign to `a` because it is borrowed
-   |             ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here
+   |                               ^ assignment to borrowed `a` occurs here
 
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:70:13
+  --> $DIR/borrowck-asm.rs:70:31
    |
 LL |         let x = 3;
    |             - first assignment to `x`
 LL |         unsafe {
 LL |             asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign twice
-   |             ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                               ^ cannot assign twice to immutable variable
 
 error[E0381]: use of possibly uninitialized variable: `x`
   --> $DIR/borrowck-asm.rs:78:32
@@ -52,13 +52,13 @@ LL |             asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitia
    |                                ^ use of possibly uninitialized `x`
 
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/borrowck-asm.rs:87:13
+  --> $DIR/borrowck-asm.rs:87:31
    |
 LL |         let y = &*x;
    |                  -- borrow of `x` occurs here
 LL |         unsafe {
 LL |             asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign to `x` because it is borrowed
-   |             ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+   |                               ^ assignment to borrowed `x` occurs here
 
 error[E0382]: use of moved value: `x`
   --> $DIR/borrowck-asm.rs:96:40
diff --git a/src/test/ui/borrowck/borrowck-asm.mir.stderr b/src/test/ui/borrowck/borrowck-asm.mir.stderr
index b0f0535b9f6..0cec1975db8 100644
--- a/src/test/ui/borrowck/borrowck-asm.mir.stderr
+++ b/src/test/ui/borrowck/borrowck-asm.mir.stderr
@@ -22,7 +22,7 @@ LL |         let z = y;
    |                 - borrow later used here
 
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:54:13
+  --> $DIR/borrowck-asm.rs:54:31
    |
 LL |         let x = 3;
    |             -
@@ -31,10 +31,10 @@ LL |         let x = 3;
    |             help: make this binding mutable: `mut x`
 LL |         unsafe {
 LL |             asm!("nop" : "=r"(x));  //[ast]~ ERROR cannot assign twice
-   |             ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                               ^ cannot assign twice to immutable variable
 
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:70:13
+  --> $DIR/borrowck-asm.rs:70:31
    |
 LL |         let x = 3;
    |             -
@@ -43,22 +43,22 @@ LL |         let x = 3;
    |             help: make this binding mutable: `mut x`
 LL |         unsafe {
 LL |             asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign twice
-   |             ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |                               ^ cannot assign twice to immutable variable
 
 error[E0381]: use of possibly uninitialized variable: `x`
-  --> $DIR/borrowck-asm.rs:78:13
+  --> $DIR/borrowck-asm.rs:78:32
    |
 LL |             asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `x`
+   |                                ^ use of possibly uninitialized `x`
 
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/borrowck-asm.rs:87:13
+  --> $DIR/borrowck-asm.rs:87:31
    |
 LL |         let y = &*x;
    |                 --- borrow of `x` occurs here
 LL |         unsafe {
 LL |             asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign to `x` because it is borrowed
-   |             ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+   |                               ^ assignment to borrowed `x` occurs here
 ...
 LL |         let z = y;
    |                 - borrow later used here
diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr
index ac6cfac2a16..5721c52ba21 100644
--- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr
@@ -20,24 +20,22 @@ LL |                    //[mir]~^ ERROR cannot borrow `x` as mutable more than o
 LL |                    *y = 1;
    |                    ------ first borrow later used here
 
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
   --> $DIR/borrowck-describe-lvalue.rs:305:16
    |
 LL |              || {
-   |              --
-   |              ||
-   |              |return type of closure is [closure@$DIR/borrowck-describe-lvalue.rs:305:16: 311:18 x:&'2 mut i32]
-   |              lifetime `'1` represents this closure's body
-LL | /                || { //[mir]~ ERROR unsatisfied lifetime constraints
+   |               - inferred to be a `FnMut` closure
+LL | /                || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body
 LL | |                    let y = &mut x;
 LL | |                    &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
 LL | |                    //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
 LL | |                    *y = 1;
 LL | |                    drop(y);
 LL | |                 }
-   | |_________________^ returning this value requires that `'1` must outlive `'2`
+   | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
    |
-   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
 
 error[E0503]: cannot use `f.x` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:53:9
diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr
index ac6cfac2a16..5721c52ba21 100644
--- a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr
+++ b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr
@@ -20,24 +20,22 @@ LL |                    //[mir]~^ ERROR cannot borrow `x` as mutable more than o
 LL |                    *y = 1;
    |                    ------ first borrow later used here
 
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
   --> $DIR/borrowck-describe-lvalue.rs:305:16
    |
 LL |              || {
-   |              --
-   |              ||
-   |              |return type of closure is [closure@$DIR/borrowck-describe-lvalue.rs:305:16: 311:18 x:&'2 mut i32]
-   |              lifetime `'1` represents this closure's body
-LL | /                || { //[mir]~ ERROR unsatisfied lifetime constraints
+   |               - inferred to be a `FnMut` closure
+LL | /                || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body
 LL | |                    let y = &mut x;
 LL | |                    &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
 LL | |                    //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
 LL | |                    *y = 1;
 LL | |                    drop(y);
 LL | |                 }
-   | |_________________^ returning this value requires that `'1` must outlive `'2`
+   | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
    |
-   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
 
 error[E0503]: cannot use `f.x` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:53:9
diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.rs b/src/test/ui/borrowck/borrowck-describe-lvalue.rs
index 2ef08e75cfd..649de888ab0 100644
--- a/src/test/ui/borrowck/borrowck-describe-lvalue.rs
+++ b/src/test/ui/borrowck/borrowck-describe-lvalue.rs
@@ -302,7 +302,7 @@ fn main() {
         // FIXME(#49824) -- the free region error below should probably not be there
         let mut x = 0;
            || {
-               || { //[mir]~ ERROR unsatisfied lifetime constraints
+               || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body
                    let y = &mut x;
                    &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
                    //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr
index f823a6f08d7..c3a2180b9f0 100644
--- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr
@@ -1,10 +1,10 @@
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
   --> $DIR/borrowck-move-from-unsafe-ptr.rs:13:13
    |
 LL |     let y = *x; //~ ERROR cannot move out of dereference of raw pointer
    |             ^^
    |             |
-   |             cannot move out of borrowed content
+   |             cannot move out of dereference of raw pointer
    |             help: consider removing the `*`: `x`
 
 error: aborting due to previous error
diff --git a/src/test/ui/cfg-attr-trailing-comma.rs b/src/test/ui/cfg-attr-trailing-comma.rs
deleted file mode 100644
index 21e00544ca0..00000000000
--- a/src/test/ui/cfg-attr-trailing-comma.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// compile-flags: --cfg TRUE
-
-#[cfg_attr(TRUE, inline,)] // OK
-fn f() {}
-
-#[cfg_attr(FALSE, inline,)] // OK
-fn g() {}
-
-#[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,`
-fn h() {}
-
-#[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,`
-fn i() {}
diff --git a/src/test/ui/cfg-attr-trailing-comma.stderr b/src/test/ui/cfg-attr-trailing-comma.stderr
deleted file mode 100644
index 76a470417e9..00000000000
--- a/src/test/ui/cfg-attr-trailing-comma.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: expected `)`, found `,`
-  --> $DIR/cfg-attr-trailing-comma.rs:9:25
-   |
-LL | #[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,`
-   |                         ^ expected `)`
-
-error: expected `)`, found `,`
-  --> $DIR/cfg-attr-trailing-comma.rs:12:26
-   |
-LL | #[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,`
-   |                          ^ expected `)`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs
index c5ba5beeca7..ba7d4ff0d9b 100644
--- a/src/test/ui/chalkify/lower_trait.rs
+++ b/src/test/ui/chalkify/lower_trait.rs
@@ -10,11 +10,12 @@
 
 #![feature(rustc_attrs)]
 
+trait Bar { }
+
 #[rustc_dump_program_clauses] //~ ERROR program clause dump
-trait Foo<S, T, U> {
-    fn s(_: S) -> S;
-    fn t(_: T) -> T;
-    fn u(_: U) -> U;
+trait Foo<S, T: ?Sized> {
+    #[rustc_dump_program_clauses] //~ ERROR program clause dump
+    type Assoc: Bar + ?Sized;
 }
 
 fn main() {
diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr
index c4e768415d6..dc2375277e7 100644
--- a/src/test/ui/chalkify/lower_trait.stderr
+++ b/src/test/ui/chalkify/lower_trait.stderr
@@ -1,14 +1,23 @@
 error: program clause dump
-  --> $DIR/lower_trait.rs:13:1
+  --> $DIR/lower_trait.rs:15:1
    |
 LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
-   = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
-   = note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
-   = note: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
-   = note: WellFormed(Self: Foo<S, T, U>) :- Implemented(Self: Foo<S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(U: std::marker::Sized).
+   = note: FromEnv(<Self as Foo<S, T>>::Assoc: Bar) :- FromEnv(Self: Foo<S, T>).
+   = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T>).
+   = note: Implemented(Self: Foo<S, T>) :- FromEnv(Self: Foo<S, T>).
+   = note: WellFormed(Self: Foo<S, T>) :- Implemented(Self: Foo<S, T>), WellFormed(S: std::marker::Sized), WellFormed(<Self as Foo<S, T>>::Assoc: Bar).
 
-error: aborting due to previous error
+error: program clause dump
+  --> $DIR/lower_trait.rs:17:5
+   |
+LL |     #[rustc_dump_program_clauses] //~ ERROR program clause dump
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: FromEnv(Self: Foo<S, T>) :- FromEnv(Unnormalized(<Self as Foo<S, T>>::Assoc)).
+   = note: ProjectionEq(<Self as Foo<S, T>>::Assoc == Unnormalized(<Self as Foo<S, T>>::Assoc)).
+   = note: WellFormed(Unnormalized(<Self as Foo<S, T>>::Assoc)) :- Implemented(Self: Foo<S, T>).
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/closure-expected-type/README.md b/src/test/ui/closure-expected-type/README.md
deleted file mode 100644
index 9995b00a9a7..00000000000
--- a/src/test/ui/closure-expected-type/README.md
+++ /dev/null
@@ -1 +0,0 @@
-See `src/test/run-pass/closure-expected-type`.
diff --git a/src/test/ui/closure-expected-type/issue-24421.rs b/src/test/ui/closure-expected-type/issue-24421.rs
new file mode 100644
index 00000000000..b3c50a74a32
--- /dev/null
+++ b/src/test/ui/closure-expected-type/issue-24421.rs
@@ -0,0 +1,20 @@
+// 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
+
+fn test<F: Fn(&u64, &u64)>(f: F) {}
+
+fn main() {
+    test(|x,      y     | {});
+    test(|x:&u64, y:&u64| {});
+    test(|x:&u64, y     | {});
+    test(|x,      y:&u64| {});
+}
diff --git a/src/test/ui/auxiliary/namespaced_enums.rs b/src/test/ui/conditional-compilation/auxiliary/namespaced_enums.rs
index 3bf39b788db..3bf39b788db 100644
--- a/src/test/ui/auxiliary/namespaced_enums.rs
+++ b/src/test/ui/conditional-compilation/auxiliary/namespaced_enums.rs
diff --git a/src/test/ui/cfg-arg-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs
index 36dd78dd2b1..36dd78dd2b1 100644
--- a/src/test/ui/cfg-arg-invalid-1.rs
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs
diff --git a/src/test/ui/cfg-arg-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-2.rs
index 48d656a4a28..48d656a4a28 100644
--- a/src/test/ui/cfg-arg-invalid-2.rs
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-2.rs
diff --git a/src/test/ui/cfg-arg-invalid-3.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-3.rs
index 96ac7828c5c..96ac7828c5c 100644
--- a/src/test/ui/cfg-arg-invalid-3.rs
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-3.rs
diff --git a/src/test/ui/cfg-arg-invalid-4.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-4.rs
index e7dfa17b4b6..e7dfa17b4b6 100644
--- a/src/test/ui/cfg-arg-invalid-4.rs
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-4.rs
diff --git a/src/test/ui/cfg-arg-invalid-5.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-5.rs
index a939f451038..a939f451038 100644
--- a/src/test/ui/cfg-arg-invalid-5.rs
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-5.rs
diff --git a/src/test/ui/cfg-attr-cfg-2.rs b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.rs
index 58a62d45ea5..58a62d45ea5 100644
--- a/src/test/ui/cfg-attr-cfg-2.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.rs
diff --git a/src/test/ui/cfg-attr-cfg-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
index db3c7acff15..db3c7acff15 100644
--- a/src/test/ui/cfg-attr-cfg-2.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
diff --git a/src/test/ui/cfg-attr-crate-2.rs b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs
index a79c7663861..a79c7663861 100644
--- a/src/test/ui/cfg-attr-crate-2.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs
diff --git a/src/test/ui/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr
index 7b66c8f5e40..a730473f663 100644
--- a/src/test/ui/cfg-attr-crate-2.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr
@@ -2,7 +2,7 @@ error[E0658]: no_core is experimental (see issue #29639)
   --> $DIR/cfg-attr-crate-2.rs:15:21
    |
 LL | #![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental
-   |                     ^^^^^^^^
+   |                     ^^^^^^^
    |
    = help: add #![feature(no_core)] to the crate attributes to enable
 
diff --git a/src/test/ui/cfg-attr-invalid-predicate.rs b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.rs
index 09fe6cec49c..09fe6cec49c 100644
--- a/src/test/ui/cfg-attr-invalid-predicate.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.rs
diff --git a/src/test/ui/cfg-attr-invalid-predicate.stderr b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr
index 5a89f9766d1..5a89f9766d1 100644
--- a/src/test/ui/cfg-attr-invalid-predicate.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr
diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs
new file mode 100644
index 00000000000..84bd33fc0e7
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs
@@ -0,0 +1,20 @@
+// Test that cfg_attr doesn't emit any attributes when the
+// configuation variable is false. This mirrors `cfg-attr-multi-true.rs`
+
+// compile-pass
+
+#![warn(unused_must_use)]
+#![feature(cfg_attr_multi)]
+
+#[cfg_attr(any(), deprecated, must_use)]
+struct Struct {}
+
+impl Struct {
+    fn new() -> Struct {
+        Struct {}
+    }
+}
+
+fn main() {
+    Struct::new();
+}
diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs
new file mode 100644
index 00000000000..d4c3186a6eb
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// compile-flags: --cfg broken
+
+#![feature(cfg_attr_multi)]
+#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental
+
+fn main() { }
diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr
new file mode 100644
index 00000000000..bf68d92cc0b
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr
@@ -0,0 +1,11 @@
+error[E0658]: no_core is experimental (see issue #29639)
+  --> $DIR/cfg-attr-multi-invalid-1.rs:14:21
+   |
+LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental
+   |                     ^^^^^^^
+   |
+   = help: add #![feature(no_core)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs
new file mode 100644
index 00000000000..bee6b7d4886
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// compile-flags: --cfg broken
+
+#![feature(cfg_attr_multi)]
+#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental
+
+fn main() { }
diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr
new file mode 100644
index 00000000000..5c72a400e0b
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr
@@ -0,0 +1,11 @@
+error[E0658]: no_core is experimental (see issue #29639)
+  --> $DIR/cfg-attr-multi-invalid-2.rs:14:29
+   |
+LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental
+   |                             ^^^^^^^
+   |
+   = help: add #![feature(no_core)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs
new file mode 100644
index 00000000000..a31dde00c7c
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs
@@ -0,0 +1,22 @@
+// Test that cfg_attr with multiple attributes actually emits both attributes.
+// This is done by emitting two attributes that cause new warnings, and then
+// triggering those warnings.
+
+// compile-pass
+
+#![warn(unused_must_use)]
+#![feature(cfg_attr_multi)]
+
+#[cfg_attr(all(), deprecated, must_use)]
+struct MustUseDeprecated {}
+
+impl MustUseDeprecated { //~ warning: use of deprecated item
+    fn new() -> MustUseDeprecated { //~ warning: use of deprecated item
+        MustUseDeprecated {} //~ warning: use of deprecated item
+    }
+}
+
+fn main() {
+    MustUseDeprecated::new(); //~ warning: use of deprecated item
+    //| warning: unused `MustUseDeprecated` which must be used
+}
diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr
new file mode 100644
index 00000000000..37cb3de06c0
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr
@@ -0,0 +1,38 @@
+warning: use of deprecated item 'MustUseDeprecated'
+  --> $DIR/cfg-attr-multi-true.rs:13:6
+   |
+LL | impl MustUseDeprecated { //~ warning: use of deprecated item
+   |      ^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(deprecated)] on by default
+
+warning: use of deprecated item 'MustUseDeprecated'
+  --> $DIR/cfg-attr-multi-true.rs:20:5
+   |
+LL |     MustUseDeprecated::new(); //~ warning: use of deprecated item
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+warning: use of deprecated item 'MustUseDeprecated'
+  --> $DIR/cfg-attr-multi-true.rs:14:17
+   |
+LL |     fn new() -> MustUseDeprecated { //~ warning: use of deprecated item
+   |                 ^^^^^^^^^^^^^^^^^
+
+warning: use of deprecated item 'MustUseDeprecated'
+  --> $DIR/cfg-attr-multi-true.rs:15:9
+   |
+LL |         MustUseDeprecated {} //~ warning: use of deprecated item
+   |         ^^^^^^^^^^^^^^^^^
+
+warning: unused `MustUseDeprecated` which must be used
+  --> $DIR/cfg-attr-multi-true.rs:20:5
+   |
+LL |     MustUseDeprecated::new(); //~ warning: use of deprecated item
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/cfg-attr-multi-true.rs:7:9
+   |
+LL | #![warn(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.rs b/src/test/ui/conditional-compilation/cfg-attr-parse.rs
new file mode 100644
index 00000000000..eec0e8faca8
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-parse.rs
@@ -0,0 +1,45 @@
+// Parse `cfg_attr` with varying numbers of attributes and trailing commas
+
+#![feature(cfg_attr_multi)]
+
+// Completely empty `cfg_attr` input
+#[cfg_attr()] //~ error: expected identifier, found `)`
+struct NoConfigurationPredicate;
+
+// Zero attributes, zero trailing comma (comma manatory here)
+#[cfg_attr(all())] //~ error: expected `,`, found `)`
+struct A0C0;
+
+// Zero attributes, one trailing comma
+#[cfg_attr(all(),)] // Ok
+struct A0C1;
+
+// Zero attributes, two trailing commas
+#[cfg_attr(all(),,)] //~ ERROR expected identifier
+struct A0C2;
+
+// One attribute, no trailing comma
+#[cfg_attr(all(), must_use)] // Ok
+struct A1C0;
+
+// One attribute, one trailing comma
+#[cfg_attr(all(), must_use,)] // Ok
+struct A1C1;
+
+// One attribute, two trailing commas
+#[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier
+struct A1C2;
+
+// Two attributes, no trailing comma
+#[cfg_attr(all(), must_use, deprecated)] // Ok
+struct A2C0;
+
+// Two attributes, one trailing comma
+#[cfg_attr(all(), must_use, deprecated,)] // Ok
+struct A2C1;
+
+// Two attributes, two trailing commas
+#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier
+struct A2C2;
+
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
new file mode 100644
index 00000000000..553406b6dd8
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
@@ -0,0 +1,32 @@
+error: expected identifier, found `)`
+  --> $DIR/cfg-attr-parse.rs:6:12
+   |
+LL | #[cfg_attr()] //~ error: expected identifier, found `)`
+   |            ^ expected identifier
+
+error: expected `,`, found `)`
+  --> $DIR/cfg-attr-parse.rs:10:17
+   |
+LL | #[cfg_attr(all())] //~ error: expected `,`, found `)`
+   |                 ^ expected `,`
+
+error: expected identifier, found `,`
+  --> $DIR/cfg-attr-parse.rs:18:18
+   |
+LL | #[cfg_attr(all(),,)] //~ ERROR expected identifier
+   |                  ^ expected identifier
+
+error: expected identifier, found `,`
+  --> $DIR/cfg-attr-parse.rs:30:28
+   |
+LL | #[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier
+   |                            ^ expected identifier
+
+error: expected identifier, found `,`
+  --> $DIR/cfg-attr-parse.rs:42:40
+   |
+LL | #[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier
+   |                                        ^ expected identifier
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/cfg-attr-syntax-validation.rs b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index 06a22eff25c..06a22eff25c 100644
--- a/src/test/ui/cfg-attr-syntax-validation.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs
diff --git a/src/test/ui/cfg-attr-syntax-validation.stderr b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 7773fdb8cf9..7773fdb8cf9 100644
--- a/src/test/ui/cfg-attr-syntax-validation.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
diff --git a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
index afcb896b43c..afcb896b43c 100644
--- a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
diff --git a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
index 0f51c7d68c6..0f51c7d68c6 100644
--- a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
diff --git a/src/test/ui/cfg-empty-codemap.rs b/src/test/ui/conditional-compilation/cfg-empty-codemap.rs
index 5cf8135ca6b..5cf8135ca6b 100644
--- a/src/test/ui/cfg-empty-codemap.rs
+++ b/src/test/ui/conditional-compilation/cfg-empty-codemap.rs
diff --git a/src/test/ui/cfg-in-crate-1.rs b/src/test/ui/conditional-compilation/cfg-in-crate-1.rs
index bbccf2bcd0f..bbccf2bcd0f 100644
--- a/src/test/ui/cfg-in-crate-1.rs
+++ b/src/test/ui/conditional-compilation/cfg-in-crate-1.rs
diff --git a/src/test/ui/cfg-in-crate-1.stderr b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
index c6d42c732c9..c6d42c732c9 100644
--- a/src/test/ui/cfg-in-crate-1.stderr
+++ b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
diff --git a/src/test/ui/cfg-non-opt-expr.rs b/src/test/ui/conditional-compilation/cfg-non-opt-expr.rs
index 55eca7f45a5..55eca7f45a5 100644
--- a/src/test/ui/cfg-non-opt-expr.rs
+++ b/src/test/ui/conditional-compilation/cfg-non-opt-expr.rs
diff --git a/src/test/ui/cfg-non-opt-expr.stderr b/src/test/ui/conditional-compilation/cfg-non-opt-expr.stderr
index 1892cee113e..1892cee113e 100644
--- a/src/test/ui/cfg-non-opt-expr.stderr
+++ b/src/test/ui/conditional-compilation/cfg-non-opt-expr.stderr
diff --git a/src/test/ui/cfg_attr_path.rs b/src/test/ui/conditional-compilation/cfg_attr_path.rs
index 7d799850a65..7d799850a65 100644
--- a/src/test/ui/cfg_attr_path.rs
+++ b/src/test/ui/conditional-compilation/cfg_attr_path.rs
diff --git a/src/test/ui/cfg_attr_path.stderr b/src/test/ui/conditional-compilation/cfg_attr_path.stderr
index 67e59d054d5..67e59d054d5 100644
--- a/src/test/ui/cfg_attr_path.stderr
+++ b/src/test/ui/conditional-compilation/cfg_attr_path.stderr
diff --git a/src/test/ui/consts/const-eval/ub-ref.rs b/src/test/ui/consts/const-eval/ub-ref.rs
index 7ee13f20dd2..584dc069169 100644
--- a/src/test/ui/consts/const-eval/ub-ref.rs
+++ b/src/test/ui/consts/const-eval/ub-ref.rs
@@ -21,6 +21,9 @@ const NULL: &u16 = unsafe { mem::transmute(0usize) };
 const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
 //~^ ERROR this constant likely exhibits undefined behavior
 
+const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+//~^ ERROR this constant likely exhibits undefined behavior
+
 const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
 //~^ ERROR this constant likely exhibits undefined behavior
 
diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr
index 9907c780d2c..8bcb6d190b8 100644
--- a/src/test/ui/consts/const-eval/ub-ref.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref.stderr
@@ -25,11 +25,19 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
 error[E0080]: this constant likely exhibits undefined behavior
   --> $DIR/ub-ref.rs:24:1
    |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+  --> $DIR/ub-ref.rs:27:1
+   |
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-upvars.rs b/src/test/ui/consts/const-eval/ub-upvars.rs
new file mode 100644
index 00000000000..309211d19d4
--- /dev/null
+++ b/src/test/ui/consts/const-eval/ub-upvars.rs
@@ -0,0 +1,21 @@
+// 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.
+
+#![feature(const_transmute,const_let)]
+
+use std::mem;
+
+const BAD_UPVAR: &FnOnce() = &{ //~ ERROR this constant likely exhibits undefined behavior
+    let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
+    let another_var = 13;
+    move || { let _ = bad_ref; let _ = another_var; }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/ub-upvars.stderr b/src/test/ui/consts/const-eval/ub-upvars.stderr
new file mode 100644
index 00000000000..3ae140d6e1c
--- /dev/null
+++ b/src/test/ui/consts/const-eval/ub-upvars.stderr
@@ -0,0 +1,15 @@
+error[E0080]: this constant likely exhibits undefined behavior
+  --> $DIR/ub-upvars.rs:15:1
+   |
+LL | / const BAD_UPVAR: &FnOnce() = &{ //~ ERROR this constant likely exhibits undefined behavior
+LL | |     let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
+LL | |     let another_var = 13;
+LL | |     move || { let _ = bad_ref; let _ = another_var; }
+LL | | };
+   | |__^ type validation failed: encountered 0 at .<deref>.<closure-var(bad_ref)>, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/issue-54224.rs b/src/test/ui/consts/issue-54224.rs
new file mode 100644
index 00000000000..b5a8fe8819c
--- /dev/null
+++ b/src/test/ui/consts/issue-54224.rs
@@ -0,0 +1,14 @@
+#![feature(nll)]
+
+const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed
+
+use std::borrow::Cow;
+
+pub const X: [u8; 3] = *b"ABC";
+pub const Y: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[X]);
+
+
+pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]);
+//~^ ERROR temporary value dropped while borrowed
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-54224.stderr b/src/test/ui/consts/issue-54224.stderr
new file mode 100644
index 00000000000..39879254cf8
--- /dev/null
+++ b/src/test/ui/consts/issue-54224.stderr
@@ -0,0 +1,23 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-54224.rs:3:39
+   |
+LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed
+   |                                       ^^^^^^^^^- temporary value is freed at the end of this statement
+   |                                       |
+   |                                       creates a temporary which is freed while still in use
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-54224.rs:11:57
+   |
+LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]);
+   |                                                         ^^^^^^^^^- temporary value is freed at the end of this statement
+   |                                                         |
+   |                                                         creates a temporary which is freed while still in use
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
index 33792d4f5b3..5de9f5866ff 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
@@ -44,33 +44,25 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:11:10
    |
 LL | type A = [u8; 4]::AssocTy;
-   |          ^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<[u8; _] as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8; _] as Trait>::AssocTy`
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:15:10
    |
 LL | type B = [u8]::AssocTy;
-   |          ^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<[u8] as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8] as Trait>::AssocTy`
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:19:10
    |
 LL | type C = (u8)::AssocTy;
-   |          ^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<u8 as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:23:10
    |
 LL | type D = (u8, u8)::AssocTy;
-   |          ^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<(u8, u8) as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/bad-assoc-ty.rs:27:10
@@ -82,25 +74,19 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:31:19
    |
 LL | type F = &'static (u8)::AssocTy;
-   |                   ^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<u8 as Trait>::AssocTy`
+   |                   ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:37:10
    |
 LL | type G = 'static + (Send)::AssocTy;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<(dyn std::marker::Send + 'static) as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::marker::Send + 'static) as Trait>::AssocTy`
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:43:10
    |
 LL | type H = Fn(u8) -> (u8)::Output;
-   |          ^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<(dyn std::ops::Fn(u8) -> u8 + 'static) as Trait>::Output`
+   |          ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::ops::Fn(u8) -> u8 + 'static) as Trait>::Output`
 
 error: aborting due to 15 previous errors
 
diff --git a/src/test/ui/error-codes/E0152.rs b/src/test/ui/error-codes/E0152.rs
index 8fbad7b3ff3..96a4d51bd24 100644
--- a/src/test/ui/error-codes/E0152.rs
+++ b/src/test/ui/error-codes/E0152.rs
@@ -10,7 +10,7 @@
 
 #![feature(lang_items)]
 
-#[lang = "panic_impl"]
+#[lang = "arc"]
 struct Foo; //~ ERROR E0152
 
 fn main() {
diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr
index c7f5f362efb..a0530f24de6 100644
--- a/src/test/ui/error-codes/E0152.stderr
+++ b/src/test/ui/error-codes/E0152.stderr
@@ -1,10 +1,10 @@
-error[E0152]: duplicate lang item found: `panic_impl`.
+error[E0152]: duplicate lang item found: `arc`.
   --> $DIR/E0152.rs:14:1
    |
 LL | struct Foo; //~ ERROR E0152
    | ^^^^^^^^^^^
    |
-   = note: first defined in crate `std`.
+   = note: first defined in crate `alloc`.
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0223.stderr b/src/test/ui/error-codes/E0223.stderr
index f65e744c625..87736c10774 100644
--- a/src/test/ui/error-codes/E0223.stderr
+++ b/src/test/ui/error-codes/E0223.stderr
@@ -2,9 +2,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/E0223.rs:14:14
    |
 LL |     let foo: MyTrait::X;
-   |              ^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<Type as MyTrait>::X`
+   |              ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as MyTrait>::X`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0718.rs b/src/test/ui/error-codes/E0718.rs
new file mode 100644
index 00000000000..ce74e35ac6b
--- /dev/null
+++ b/src/test/ui/error-codes/E0718.rs
@@ -0,0 +1,17 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(lang_items)]
+
+// Arc is expected to be a struct, so this will error.
+#[lang = "arc"]
+static X: u32 = 42;
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0718.stderr b/src/test/ui/error-codes/E0718.stderr
new file mode 100644
index 00000000000..8ce721d30a1
--- /dev/null
+++ b/src/test/ui/error-codes/E0718.stderr
@@ -0,0 +1,9 @@
+error[E0718]: `arc` language item must be applied to a struct
+  --> $DIR/E0718.rs:14:1
+   |
+LL | #[lang = "arc"]
+   | ^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static item
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0718`.
diff --git a/src/test/ui/feature-gate-underscore_const_names.rs b/src/test/ui/feature-gate-underscore_const_names.rs
new file mode 100644
index 00000000000..b283e286514
--- /dev/null
+++ b/src/test/ui/feature-gate-underscore_const_names.rs
@@ -0,0 +1,24 @@
+// Copyright 2012-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.
+#![feature(const_let)]
+
+trait Trt {}
+struct Str {}
+
+impl Trt for Str {}
+
+const _ : () = {
+    use std::marker::PhantomData;
+    struct ImplementsTrait<T: Trt>(PhantomData<T>);
+    let _ = ImplementsTrait::<Str>(PhantomData);
+    ()
+};
+
+fn main() {}
diff --git a/src/test/ui/feature-gate-underscore_const_names.stderr b/src/test/ui/feature-gate-underscore_const_names.stderr
new file mode 100644
index 00000000000..ab90ef8f11f
--- /dev/null
+++ b/src/test/ui/feature-gate-underscore_const_names.stderr
@@ -0,0 +1,16 @@
+error[E0658]: naming constants with `_` is unstable (see issue #54912)
+  --> $DIR/feature-gate-underscore_const_names.rs:17:1
+   |
+LL | / const _ : () = {
+LL | |     use std::marker::PhantomData;
+LL | |     struct ImplementsTrait<T: Trt>(PhantomData<T>);
+LL | |     let _ = ImplementsTrait::<Str>(PhantomData);
+LL | |     ()
+LL | | };
+   | |__^
+   |
+   = help: add #![feature(underscore_const_names)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs
new file mode 100644
index 00000000000..9515380bc28
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs
@@ -0,0 +1,5 @@
+// gate-test-cfg_attr_multi
+
+#![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))]
+//~^ ERROR cfg_attr with zero or more than one attributes is experimental
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr
new file mode 100644
index 00000000000..088e6df1a1a
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr
@@ -0,0 +1,11 @@
+error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881)
+  --> $DIR/feature-gate-cfg-attr-multi-1.rs:3:1
+   |
+LL | #![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(cfg_attr_multi)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs
new file mode 100644
index 00000000000..cf02432274b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs
@@ -0,0 +1,3 @@
+#![cfg_attr(all(),)]
+//~^ ERROR cfg_attr with zero or more than one attributes is experimental
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr
new file mode 100644
index 00000000000..a01876114dd
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr
@@ -0,0 +1,11 @@
+error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881)
+  --> $DIR/feature-gate-cfg-attr-multi-2.rs:1:1
+   |
+LL | #![cfg_attr(all(),)]
+   | ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(cfg_attr_multi)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs
new file mode 100644
index 00000000000..e4737926e7a
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs
@@ -0,0 +1,7 @@
+// Test that settingt the featute gate while using its functionality doesn't error.
+
+// compile-pass
+
+#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")]
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs
new file mode 100644
index 00000000000..df740541f55
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs
@@ -0,0 +1,9 @@
+// Test that settingt the featute gate while using its functionality doesn't error.
+// Specifically, if there's a cfg-attr *before* the feature gate.
+
+// compile-pass
+
+#![cfg_attr(all(),)]
+#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")]
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr b/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr
deleted file mode 100644
index 33ee79cd201..00000000000
--- a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: scoped lint `clippy::assign_ops` is experimental (see issue #44690)
-  --> $DIR/feature-gate-tool_lints-fail.rs:11:8
-   |
-LL | #[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental
-   |        ^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(tool_lints)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints.stderr b/src/test/ui/feature-gates/feature-gate-tool_lints.stderr
deleted file mode 100644
index 8019b1e6a28..00000000000
--- a/src/test/ui/feature-gates/feature-gate-tool_lints.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: scoped lint `clippy::decimal_literal_representation` is experimental (see issue #44690)
-  --> $DIR/feature-gate-tool_lints.rs:11:8
-   |
-LL | #[warn(clippy::decimal_literal_representation)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(tool_lints)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fn_must_use.rs b/src/test/ui/fn_must_use.rs
index def23046db2..e3e20bc89b4 100644
--- a/src/test/ui/fn_must_use.rs
+++ b/src/test/ui/fn_must_use.rs
@@ -22,6 +22,11 @@ impl MyStruct {
     fn need_to_use_this_method_value(&self) -> usize {
         self.n
     }
+
+    #[must_use]
+    fn need_to_use_this_associated_function_value() -> isize {
+        -1
+    }
 }
 
 trait EvenNature {
@@ -66,6 +71,9 @@ fn main() {
     m.is_even(); // trait method!
     //~^ WARN unused return value
 
+    MyStruct::need_to_use_this_associated_function_value();
+    //~^ WARN unused return value
+
     m.replace(3); // won't warn (annotation needs to be in trait definition)
 
     // comparison methods are `must_use`
diff --git a/src/test/ui/fn_must_use.stderr b/src/test/ui/fn_must_use.stderr
index b5bad22f3dc..1bce8abbbf0 100644
--- a/src/test/ui/fn_must_use.stderr
+++ b/src/test/ui/fn_must_use.stderr
@@ -1,5 +1,5 @@
 warning: unused return value of `need_to_use_this_value` which must be used
-  --> $DIR/fn_must_use.rs:60:5
+  --> $DIR/fn_must_use.rs:65:5
    |
 LL |     need_to_use_this_value(); //~ WARN unused return value
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,39 +12,45 @@ LL | #![warn(unused_must_use)]
    = note: it's important
 
 warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used
-  --> $DIR/fn_must_use.rs:65:5
+  --> $DIR/fn_must_use.rs:70:5
    |
 LL |     m.need_to_use_this_method_value(); //~ WARN unused return value
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused return value of `EvenNature::is_even` which must be used
-  --> $DIR/fn_must_use.rs:66:5
+  --> $DIR/fn_must_use.rs:71:5
    |
 LL |     m.is_even(); // trait method!
    |     ^^^^^^^^^^^^
    |
    = note: no side effects
 
+warning: unused return value of `MyStruct::need_to_use_this_associated_function_value` which must be used
+  --> $DIR/fn_must_use.rs:74:5
+   |
+LL |     MyStruct::need_to_use_this_associated_function_value();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 warning: unused return value of `std::cmp::PartialEq::eq` which must be used
-  --> $DIR/fn_must_use.rs:72:5
+  --> $DIR/fn_must_use.rs:80:5
    |
 LL |     2.eq(&3); //~ WARN unused return value
    |     ^^^^^^^^^
 
 warning: unused return value of `std::cmp::PartialEq::eq` which must be used
-  --> $DIR/fn_must_use.rs:73:5
+  --> $DIR/fn_must_use.rs:81:5
    |
 LL |     m.eq(&n); //~ WARN unused return value
    |     ^^^^^^^^^
 
 warning: unused comparison which must be used
-  --> $DIR/fn_must_use.rs:76:5
+  --> $DIR/fn_must_use.rs:84:5
    |
 LL |     2 == 3; //~ WARN unused comparison
    |     ^^^^^^
 
 warning: unused comparison which must be used
-  --> $DIR/fn_must_use.rs:77:5
+  --> $DIR/fn_must_use.rs:85:5
    |
 LL |     m == n; //~ WARN unused comparison
    |     ^^^^^^
diff --git a/src/test/ui/impl-trait/impl_trait_projections.stderr b/src/test/ui/impl-trait/impl_trait_projections.stderr
index f6d58984ece..a6daf898e30 100644
--- a/src/test/ui/impl-trait/impl_trait_projections.stderr
+++ b/src/test/ui/impl-trait/impl_trait_projections.stderr
@@ -26,9 +26,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/impl_trait_projections.rs:21:50
    |
 LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<impl std::iter::Iterator as Trait>::Item`
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<impl std::iter::Iterator as Trait>::Item`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/inline-asm-bad-operand.rs b/src/test/ui/inline-asm-bad-operand.rs
new file mode 100644
index 00000000000..37021f38cac
--- /dev/null
+++ b/src/test/ui/inline-asm-bad-operand.rs
@@ -0,0 +1,57 @@
+// 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.
+
+// Test that the compiler will catch passing invalid values to inline assembly
+// operands.
+
+#![feature(asm)]
+
+#[repr(C)]
+struct MyPtr(usize);
+
+fn main() {
+    issue_37433();
+    issue_37437();
+    issue_40187();
+    issue_54067();
+}
+
+fn issue_37433() {
+    unsafe {
+        asm!("" :: "r"("")); //~ ERROR E0669
+    }
+
+    unsafe {
+        let target = MyPtr(0);
+        asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
+    }
+}
+
+fn issue_37437() {
+    let hello: &str = "hello";
+    // this should fail...
+    unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
+    // but this should succeed.
+    unsafe { asm!("" :: "r"(hello.as_ptr())) };
+}
+
+fn issue_40187() {
+    let arr: [u8; 1] = [0; 1];
+    unsafe {
+        asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
+    }
+}
+
+fn issue_54067() {
+    let addr: Option<u32> = Some(123);
+    unsafe {
+        asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
+    }
+}
diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr
new file mode 100644
index 00000000000..6971215a95f
--- /dev/null
+++ b/src/test/ui/inline-asm-bad-operand.stderr
@@ -0,0 +1,33 @@
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:28:9
+   |
+LL |         asm!("" :: "r"("")); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:33:9
+   |
+LL |         asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:40:14
+   |
+LL |     unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
+   |              ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:48:9
+   |
+LL |         asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:55:9
+   |
+LL |         asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0669`.
diff --git a/src/test/ui/issues/issue-20801.nll.stderr b/src/test/ui/issues/issue-20801.nll.stderr
index 3a6784eed67..362778b26c8 100644
--- a/src/test/ui/issues/issue-20801.nll.stderr
+++ b/src/test/ui/issues/issue-20801.nll.stderr
@@ -16,22 +16,22 @@ LL |     let b = unsafe { *imm_ref() };
    |                      cannot move out of borrowed content
    |                      help: consider removing the `*`: `imm_ref()`
 
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
   --> $DIR/issue-20801.rs:42:22
    |
 LL |     let c = unsafe { *mut_ptr() };
    |                      ^^^^^^^^^^
    |                      |
-   |                      cannot move out of borrowed content
+   |                      cannot move out of dereference of raw pointer
    |                      help: consider removing the `*`: `mut_ptr()`
 
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
   --> $DIR/issue-20801.rs:45:22
    |
 LL |     let d = unsafe { *const_ptr() };
    |                      ^^^^^^^^^^^^
    |                      |
-   |                      cannot move out of borrowed content
+   |                      cannot move out of dereference of raw pointer
    |                      help: consider removing the `*`: `const_ptr()`
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/issues/issue-23073.stderr b/src/test/ui/issues/issue-23073.stderr
index 44b2128af0a..ef2430561ec 100644
--- a/src/test/ui/issues/issue-23073.stderr
+++ b/src/test/ui/issues/issue-23073.stderr
@@ -2,9 +2,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-23073.rs:16:17
    |
 LL |     type FooT = <<Self as Bar>::Foo>::T; //~ ERROR ambiguous associated type
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<<Self as Bar>::Foo as Trait>::T`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<Self as Bar>::Foo as Trait>::T`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-34209.stderr b/src/test/ui/issues/issue-34209.stderr
index 5c31acea5b6..0dfdd8b5886 100644
--- a/src/test/ui/issues/issue-34209.stderr
+++ b/src/test/ui/issues/issue-34209.stderr
@@ -2,9 +2,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-34209.rs:17:9
    |
 LL |         S::B{ } => { },
-   |         ^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<S as Trait>::B`
+   |         ^^^^ help: use fully-qualified syntax: `<S as Trait>::B`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-40510-1.nll.stderr b/src/test/ui/issues/issue-40510-1.nll.stderr
index 3a579c04de1..1aeb1a89ead 100644
--- a/src/test/ui/issues/issue-40510-1.nll.stderr
+++ b/src/test/ui/issues/issue-40510-1.nll.stderr
@@ -1,15 +1,13 @@
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
   --> $DIR/issue-40510-1.rs:18:9
    |
 LL |     || {
-   |     --
-   |     ||
-   |     |return type of closure is &'2 mut std::boxed::Box<()>
-   |     lifetime `'1` represents this closure's body
+   |      - inferred to be a `FnMut` closure
 LL |         &mut x
-   |         ^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |         ^^^^^^ returns a reference to a captured variable which escapes the closure body
    |
-   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-40510-3.nll.stderr b/src/test/ui/issues/issue-40510-3.nll.stderr
index 84ab2a8216d..c334e592fbc 100644
--- a/src/test/ui/issues/issue-40510-3.nll.stderr
+++ b/src/test/ui/issues/issue-40510-3.nll.stderr
@@ -1,17 +1,15 @@
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
   --> $DIR/issue-40510-3.rs:18:9
    |
 LL |       || {
-   |       --
-   |       ||
-   |       |return type of closure is [closure@$DIR/issue-40510-3.rs:18:9: 20:10 x:&'2 mut std::vec::Vec<()>]
-   |       lifetime `'1` represents this closure's body
+   |        - inferred to be a `FnMut` closure
 LL | /         || {
 LL | |             x.push(())
 LL | |         }
-   | |_________^ returning this value requires that `'1` must outlive `'2`
+   | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
    |
-   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-49824.nll.stderr b/src/test/ui/issues/issue-49824.nll.stderr
index df43158ec9c..2e0463fdd1d 100644
--- a/src/test/ui/issues/issue-49824.nll.stderr
+++ b/src/test/ui/issues/issue-49824.nll.stderr
@@ -1,17 +1,15 @@
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
   --> $DIR/issue-49824.rs:22:9
    |
 LL |       || {
-   |       --
-   |       ||
-   |       |return type of closure is [closure@$DIR/issue-49824.rs:22:9: 24:10 x:&'2 mut i32]
-   |       lifetime `'1` represents this closure's body
+   |        - inferred to be a `FnMut` closure
 LL | /         || {
 LL | |             let _y = &mut x;
 LL | |         }
-   | |_________^ returning this value requires that `'1` must outlive `'2`
+   | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
    |
-   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-52240.nll.stderr b/src/test/ui/issues/issue-52240.nll.stderr
new file mode 100644
index 00000000000..69b663b17d3
--- /dev/null
+++ b/src/test/ui/issues/issue-52240.nll.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/issue-52240.rs:9:27
+   |
+LL |     if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
+   |                           ^^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/issues/issue-52240.rs b/src/test/ui/issues/issue-52240.rs
new file mode 100644
index 00000000000..9ac7e9905da
--- /dev/null
+++ b/src/test/ui/issues/issue-52240.rs
@@ -0,0 +1,16 @@
+// issue-52240: Can turn immutable into mut with `ref mut`
+
+enum Foo {
+    Bar(i32),
+}
+
+fn main() {
+    let arr = vec!(Foo::Bar(0));
+    if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
+        //~^ ERROR cannot borrow field of immutable binding as mutable
+        *val = 9001;
+    }
+    match arr[0] {
+        Foo::Bar(ref s) => println!("{}", s)
+    }
+}
diff --git a/src/test/ui/issues/issue-52240.stderr b/src/test/ui/issues/issue-52240.stderr
new file mode 100644
index 00000000000..c2c2524816d
--- /dev/null
+++ b/src/test/ui/issues/issue-52240.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow field of immutable binding as mutable
+  --> $DIR/issue-52240.rs:9:27
+   |
+LL |     if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
+   |                           ^^^^^^^^^^^ cannot mutably borrow field of immutable binding
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/issues/issue-54966.rs b/src/test/ui/issues/issue-54966.rs
new file mode 100644
index 00000000000..0ed3c4b3ca9
--- /dev/null
+++ b/src/test/ui/issues/issue-54966.rs
@@ -0,0 +1,6 @@
+// issue-54966: ICE returning an unknown type with impl FnMut
+
+fn generate_duration() -> Oper<impl FnMut()> {}
+//~^ ERROR cannot find type `Oper` in this scope
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-54966.stderr b/src/test/ui/issues/issue-54966.stderr
new file mode 100644
index 00000000000..aa9a61cb592
--- /dev/null
+++ b/src/test/ui/issues/issue-54966.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Oper` in this scope
+  --> $DIR/issue-54966.rs:3:27
+   |
+LL | fn generate_duration() -> Oper<impl FnMut()> {}
+   |                           ^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/lint/must_use-unit.rs b/src/test/ui/lint/must_use-unit.rs
new file mode 100644
index 00000000000..92568252164
--- /dev/null
+++ b/src/test/ui/lint/must_use-unit.rs
@@ -0,0 +1,17 @@
+#![feature(never_type)]
+
+#![deny(unused_must_use)]
+
+#[must_use]
+fn foo() {}
+
+#[must_use]
+fn bar() -> ! {
+    unimplemented!()
+}
+
+fn main() {
+    foo(); //~ unused return value of `foo`
+
+    bar(); //~ unused return value of `bar`
+}
diff --git a/src/test/ui/lint/must_use-unit.stderr b/src/test/ui/lint/must_use-unit.stderr
new file mode 100644
index 00000000000..0a956f74611
--- /dev/null
+++ b/src/test/ui/lint/must_use-unit.stderr
@@ -0,0 +1,20 @@
+error: unused return value of `foo` which must be used
+  --> $DIR/must_use-unit.rs:14:5
+   |
+LL |     foo(); //~ unused return value of `foo`
+   |     ^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/must_use-unit.rs:3:9
+   |
+LL | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
+error: unused return value of `bar` which must be used
+  --> $DIR/must_use-unit.rs:16:5
+   |
+LL |     bar(); //~ unused return value of `bar`
+   |     ^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr
index aa1edb2cf89..e27056b412a 100644
--- a/src/test/ui/macros/issue-54441.stderr
+++ b/src/test/ui/macros/issue-54441.stderr
@@ -1,9 +1,6 @@
 error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found `let`
   --> $DIR/issue-54441.rs:5:9
    |
-LL | #![feature(macros_in_extern)]
-   | - expected one of `crate`, `fn`, `pub`, `static`, or `type` here
-...
 LL |         let //~ ERROR expected
    |         ^^^ unexpected token
 ...
diff --git a/src/test/ui/nll/issue-52663-trait-object.rs b/src/test/ui/nll/issue-52663-trait-object.rs
new file mode 100644
index 00000000000..65d73eeae67
--- /dev/null
+++ b/src/test/ui/nll/issue-52663-trait-object.rs
@@ -0,0 +1,27 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax)]
+#![feature(nll)]
+
+trait Foo { fn get(&self); }
+
+impl<A> Foo for A {
+    fn get(&self) { }
+}
+
+fn main() {
+    let _ = {
+        let tmp0 = 3;
+        let tmp1 = &tmp0;
+        box tmp1 as Box<Foo + '_>
+    };
+    //~^^^ ERROR `tmp0` does not live long enough
+}
diff --git a/src/test/ui/nll/issue-52663-trait-object.stderr b/src/test/ui/nll/issue-52663-trait-object.stderr
new file mode 100644
index 00000000000..035422f2458
--- /dev/null
+++ b/src/test/ui/nll/issue-52663-trait-object.stderr
@@ -0,0 +1,13 @@
+error[E0597]: `tmp0` does not live long enough
+  --> $DIR/issue-52663-trait-object.rs:23:20
+   |
+LL |         let tmp1 = &tmp0;
+   |                    ^^^^^ borrowed value does not live long enough
+LL |         box tmp1 as Box<Foo + '_>
+   |         ------------------------- borrow later captured here by trait object
+LL |     };
+   |     - `tmp0` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/issue-53040.rs b/src/test/ui/nll/issue-53040.rs
new file mode 100644
index 00000000000..2b6e67be6d9
--- /dev/null
+++ b/src/test/ui/nll/issue-53040.rs
@@ -0,0 +1,16 @@
+// 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.
+
+#![feature(nll)]
+
+fn main() {
+    let mut v: Vec<()> = Vec::new();
+    || &mut v;
+}
diff --git a/src/test/ui/nll/issue-53040.stderr b/src/test/ui/nll/issue-53040.stderr
new file mode 100644
index 00000000000..fac9969f193
--- /dev/null
+++ b/src/test/ui/nll/issue-53040.stderr
@@ -0,0 +1,13 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-53040.rs:15:8
+   |
+LL |     || &mut v;
+   |      - ^^^^^^ returns a reference to a captured variable which escapes the closure body
+   |      |
+   |      inferred to be a `FnMut` closure
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
index 9a83872b965..a4d47eed6fb 100644
--- a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
+++ b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
@@ -5,10 +5,10 @@ LL |     let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
    |                                                          ^^^^^^^^^
 
 error: higher-ranked subtype error
-  --> $DIR/hr-fn-aaa-as-aba.rs:32:9
+  --> $DIR/hr-fn-aaa-as-aba.rs:32:12
    |
 LL |     let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
-   |         ^
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr
index b01dc65fc5f..0b0848e9913 100644
--- a/src/test/ui/nll/user-annotations/patterns.stderr
+++ b/src/test/ui/nll/user-annotations/patterns.stderr
@@ -131,12 +131,12 @@ LL |     y //~ ERROR
    |     ^ returning this value requires that `'a` must outlive `'static`
 
 error: unsatisfied lifetime constraints
-  --> $DIR/patterns.rs:117:9
+  --> $DIR/patterns.rs:117:18
    |
 LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
    |                            -- lifetime `'a` defined here
 LL |     let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR
-   |         ^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                  ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs b/src/test/ui/panic-handler/panic-handler-wrong-location.rs
index c311eb7ed7a..04e02682bc1 100644
--- a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs
+++ b/src/test/ui/panic-handler/panic-handler-wrong-location.rs
@@ -8,5 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental
-fn main() {}
+// compile-flags:-C panic=abort
+
+#![no_std]
+#![no_main]
+
+#[panic_handler]
+#[no_mangle]
+static X: u32 = 42;
diff --git a/src/test/ui/panic-handler/panic-handler-wrong-location.stderr b/src/test/ui/panic-handler/panic-handler-wrong-location.stderr
new file mode 100644
index 00000000000..f761e26b86e
--- /dev/null
+++ b/src/test/ui/panic-handler/panic-handler-wrong-location.stderr
@@ -0,0 +1,11 @@
+error[E0718]: `panic_impl` language item must be applied to a function
+  --> $DIR/panic-handler-wrong-location.rs:16:1
+   |
+LL | #[panic_handler]
+   | ^^^^^^^^^^^^^^^^ attribute should be applied to a function, not a static item
+
+error: `#[panic_handler]` function required, but not found
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0718`.
diff --git a/src/test/ui/qualified/qualified-path-params-2.stderr b/src/test/ui/qualified/qualified-path-params-2.stderr
index 8b618cbf7ba..70aac779103 100644
--- a/src/test/ui/qualified/qualified-path-params-2.stderr
+++ b/src/test/ui/qualified/qualified-path-params-2.stderr
@@ -8,9 +8,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/qualified-path-params-2.rs:28:10
    |
 LL | type A = <S as Tr>::A::f<u8>;
-   |          ^^^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<<S as Tr>::A as Trait>::f`
+   |          ^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<S as Tr>::A as Trait>::f`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
index 53d3b2d5323..8fd195639fe 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
@@ -1,10 +1,10 @@
 error[E0621]: explicit lifetime required in the type of `v`
-  --> $DIR/region-object-lifetime-in-coercion.rs:18:9
+  --> $DIR/region-object-lifetime-in-coercion.rs:18:12
    |
 LL | fn a(v: &[u8]) -> Box<Foo + 'static> {
    |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
 LL |     let x: Box<Foo + 'static> = Box::new(v);
-   |         ^ lifetime `'static` required
+   |            ^^^^^^^^^^^^^^^^^^ lifetime `'static` required
 
 error[E0621]: explicit lifetime required in the type of `v`
   --> $DIR/region-object-lifetime-in-coercion.rs:24:5
diff --git a/src/test/ui/regions/regions-addr-of-self.nll.stderr b/src/test/ui/regions/regions-addr-of-self.nll.stderr
index 0e38abef668..1454c856f97 100644
--- a/src/test/ui/regions/regions-addr-of-self.nll.stderr
+++ b/src/test/ui/regions/regions-addr-of-self.nll.stderr
@@ -1,10 +1,10 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-addr-of-self.rs:17:13
+  --> $DIR/regions-addr-of-self.rs:17:16
    |
 LL |     pub fn chase_cat(&mut self) {
    |                      - let's call the lifetime of this reference `'1`
 LL |         let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer
-   |             ^ type annotation requires that `'1` must outlive `'static`
+   |                ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
index fd52494b499..0e48192eaff 100644
--- a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
+++ b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
@@ -1,33 +1,33 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-addr-of-upvar-self.rs:20:17
+  --> $DIR/regions-addr-of-upvar-self.rs:20:20
    |
 LL |         let _f = || {
    |                  -- lifetime `'1` represents this closure's body
 LL |             let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
-   |                 ^ type annotation requires that `'1` must outlive `'static`
+   |                    ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
    |
    = note: closure implements `FnMut`, so references to captured variables can't escape the closure
 
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-addr-of-upvar-self.rs:20:17
+  --> $DIR/regions-addr-of-upvar-self.rs:20:20
    |
 LL |     pub fn chase_cat(&mut self) {
    |                      --------- lifetime `'2` appears in the type of `self`
 LL |         let _f = || {
    |                  -- lifetime `'1` represents this closure's body
 LL |             let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
-   |                 ^ type annotation requires that `'1` must outlive `'2`
+   |                    ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'2`
    |
    = note: closure implements `FnMut`, so references to captured variables can't escape the closure
 
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-addr-of-upvar-self.rs:20:17
+  --> $DIR/regions-addr-of-upvar-self.rs:20:20
    |
 LL |     pub fn chase_cat(&mut self) {
    |                      - let's call the lifetime of this reference `'1`
 LL |         let _f = || {
 LL |             let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
-   |                 ^ type annotation requires that `'1` must outlive `'static`
+   |                    ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
 
 error[E0597]: `self` does not live long enough
   --> $DIR/regions-addr-of-upvar-self.rs:20:46
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr
new file mode 100644
index 00000000000..f711541fbd5
--- /dev/null
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr
@@ -0,0 +1,13 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:52:13
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
index 96eb65daaff..741feb1f9ea 100644
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-compare-mode-nll
-
 // Test that we are imposing the requirement that every associated
 // type of a bound that appears in the where clause on a struct must
 // outlive the location in which the type appears, even when the
@@ -49,7 +47,10 @@ fn with_assoc<'a,'b>() {
     // outlive 'a. In this case, that means TheType<'b>::TheAssocType,
     // which is &'b (), must outlive 'a.
 
-    let _: &'a WithAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
+    // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
+    // `_x` is changed to `_`
+    let _x: &'a WithAssoc<TheType<'b>> = loop { };
+    //~^ ERROR reference has a longer lifetime
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr
index 7b7881d6ea7..7959d1b6c23 100644
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr
@@ -1,16 +1,16 @@
 error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:52:12
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:52:13
    |
-LL |     let _: &'a WithAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 46:15
-  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:46:15
+note: the pointer is valid for the lifetime 'a as defined on the function body at 44:15
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:15
    |
 LL | fn with_assoc<'a,'b>() {
    |               ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 46:18
-  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:46:18
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 44:18
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:18
    |
 LL | fn with_assoc<'a,'b>() {
    |                  ^^
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr
new file mode 100644
index 00000000000..8d4f3d1e87f
--- /dev/null
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr
@@ -0,0 +1,33 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-free-region-ordering-caller.rs:18:12
+   |
+LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let z: Option<&'b &'a usize> = None;//~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-free-region-ordering-caller.rs:23:12
+   |
+LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let y: Paramd<'a> = Paramd { x: a };
+LL |     let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-free-region-ordering-caller.rs:27:12
+   |
+LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let z: Option<&'a &'b usize> = None;//~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.rs b/src/test/ui/regions/regions-free-region-ordering-caller.rs
index ee6cd6c4b15..66b16744cc7 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller.rs
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-compare-mode-nll
-
 // Test various ways to construct a pointer with a longer lifetime
 // than the thing it points at and ensure that they result in
 // errors. See also regions-free-region-ordering-callee.rs
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.stderr
index 96502b69c08..a3645995b5e 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.stderr
@@ -1,5 +1,5 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/regions-free-region-ordering-caller.rs:20:12
+  --> $DIR/regions-free-region-ordering-caller.rs:18:12
    |
 LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
    |                     ---------     ---------
@@ -9,7 +9,7 @@ LL |     let z: Option<&'b &'a usize> = None;//~ ERROR E0623
    |            ^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here
 
 error[E0623]: lifetime mismatch
-  --> $DIR/regions-free-region-ordering-caller.rs:25:12
+  --> $DIR/regions-free-region-ordering-caller.rs:23:12
    |
 LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
    |                     ---------     ---------
@@ -20,7 +20,7 @@ LL |     let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623
    |            ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here
 
 error[E0623]: lifetime mismatch
-  --> $DIR/regions-free-region-ordering-caller.rs:29:12
+  --> $DIR/regions-free-region-ordering-caller.rs:27:12
    |
 LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
    |                     ---------     --------- these two types are declared with different lifetimes...
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
index 75758206d6b..9747602f1ba 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
@@ -13,6 +13,22 @@ note: borrowed value must be valid for the lifetime 'a as defined on the functio
 LL | fn call1<'a>(x: &'a usize) {
    |          ^^
 
-error: aborting due to previous error
+error[E0597]: `y` does not live long enough
+  --> $DIR/regions-free-region-ordering-caller1.rs:19:27
+   |
+LL |     let z: &'a & usize = &(&y);
+   |                           ^^^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:10...
+  --> $DIR/regions-free-region-ordering-caller1.rs:15:10
+   |
+LL | fn call1<'a>(x: &'a usize) {
+   |          ^^
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0716`.
+Some errors occurred: E0597, E0716.
+For more information about an error, try `rustc --explain E0597`.
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
new file mode 100644
index 00000000000..2eb4ccf1c35
--- /dev/null
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
@@ -0,0 +1,11 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-implied-bounds-projection-gap-1.rs:26:5
+   |
+LL |     wf::<&'x T>();
+   |     ^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'x`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs
index 01de3ddcdf8..65594ab8f2e 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-compare-mode-nll
-
 // Illustrates the "projection gap": in this test, even though we know
 // that `T::Foo: 'x`, that does not tell us that `T: 'x`, because
 // there might be other ways for the caller of `func` to show that
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr
index e6efb4d5c6b..41ae515bb9a 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr
@@ -1,5 +1,5 @@
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-implied-bounds-projection-gap-1.rs:28:10
+  --> $DIR/regions-implied-bounds-projection-gap-1.rs:26:10
    |
 LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
    |             -- help: consider adding an explicit lifetime bound `T: 'x`...
@@ -8,7 +8,7 @@ LL |     wf::<&'x T>();
    |          ^^^^^
    |
 note: ...so that the reference type `&'x T` does not outlive the data it points at
-  --> $DIR/regions-implied-bounds-projection-gap-1.rs:28:10
+  --> $DIR/regions-implied-bounds-projection-gap-1.rs:26:10
    |
 LL |     wf::<&'x T>();
    |          ^^^^^
diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr
index 2f3c7166867..aba285d427b 100644
--- a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr
+++ b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr
@@ -1,5 +1,5 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-infer-contravariance-due-to-decl.rs:35:9
+  --> $DIR/regions-infer-contravariance-due-to-decl.rs:35:12
    |
 LL | fn use_<'short,'long>(c: Contravariant<'short>,
    |         ------ ----- lifetime `'long` defined here
@@ -7,7 +7,7 @@ LL | fn use_<'short,'long>(c: Contravariant<'short>,
    |         lifetime `'short` defined here
 ...
 LL |     let _: Contravariant<'long> = c; //~ ERROR E0623
-   |         ^ type annotation requires that `'short` must outlive `'long`
+   |            ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr
index 835438e9e5d..8bc6d565cf1 100644
--- a/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr
+++ b/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr
@@ -1,5 +1,5 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-infer-covariance-due-to-decl.rs:32:9
+  --> $DIR/regions-infer-covariance-due-to-decl.rs:32:12
    |
 LL | fn use_<'short,'long>(c: Covariant<'long>,
    |         ------ ----- lifetime `'long` defined here
@@ -7,7 +7,7 @@ LL | fn use_<'short,'long>(c: Covariant<'long>,
    |         lifetime `'short` defined here
 ...
 LL |     let _: Covariant<'short> = c; //~ ERROR E0623
-   |         ^ type annotation requires that `'short` must outlive `'long`
+   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr
new file mode 100644
index 00000000000..836f8c28a73
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr
@@ -0,0 +1,13 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-outlives-projection-container-wc.rs:46:13
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.rs b/src/test/ui/regions/regions-outlives-projection-container-wc.rs
index 79300d5176e..22ec58d1367 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.rs
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-compare-mode-nll
-
 // Test that we are imposing the requirement that every associated
 // type of a bound that appears in the where clause on a struct must
 // outlive the location in which the type appears, even when the
@@ -43,7 +41,9 @@ fn with_assoc<'a,'b>() {
     // outlive 'a. In this case, that means TheType<'b>::TheAssocType,
     // which is &'b (), must outlive 'a.
 
-    let _: &'a WithAssoc<TheType<'b>> = loop { };
+    // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
+    // `_x` is changed to `_`
+    let _x: &'a WithAssoc<TheType<'b>> = loop { };
     //~^ ERROR reference has a longer lifetime
 }
 
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr
index d0680ecbb99..e5bc52d7b66 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr
@@ -1,16 +1,16 @@
 error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container-wc.rs:46:12
+  --> $DIR/regions-outlives-projection-container-wc.rs:46:13
    |
-LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 40:15
-  --> $DIR/regions-outlives-projection-container-wc.rs:40:15
+note: the pointer is valid for the lifetime 'a as defined on the function body at 38:15
+  --> $DIR/regions-outlives-projection-container-wc.rs:38:15
    |
 LL | fn with_assoc<'a,'b>() {
    |               ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 40:18
-  --> $DIR/regions-outlives-projection-container-wc.rs:40:18
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 38:18
+  --> $DIR/regions-outlives-projection-container-wc.rs:38:18
    |
 LL | fn with_assoc<'a,'b>() {
    |                  ^^
diff --git a/src/test/ui/regions/regions-outlives-projection-container.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container.nll.stderr
new file mode 100644
index 00000000000..126f50577c8
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container.nll.stderr
@@ -0,0 +1,46 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-outlives-projection-container.rs:50:13
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-outlives-projection-container.rs:68:13
+   |
+LL | fn without_assoc<'a,'b>() {
+   |                  -- -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+...
+LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-outlives-projection-container.rs:77:5
+   |
+LL | fn call_with_assoc<'a,'b>() {
+   |                    -- -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+...
+LL |     call::<&'a WithAssoc<TheType<'b>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-outlives-projection-container.rs:84:5
+   |
+LL | fn call_without_assoc<'a,'b>() {
+   |                       -- -- lifetime `'b` defined here
+   |                       |
+   |                       lifetime `'a` defined here
+...
+LL |     call::<&'a WithoutAssoc<TheType<'b>>>(); //~ ERROR reference has a longer lifetime
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/regions/regions-outlives-projection-container.rs b/src/test/ui/regions/regions-outlives-projection-container.rs
index e4b7a0f82db..08fd7080e52 100644
--- a/src/test/ui/regions/regions-outlives-projection-container.rs
+++ b/src/test/ui/regions/regions-outlives-projection-container.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-compare-mode-nll
-
 // Test that we are imposing the requirement that every associated
 // type of a bound that appears in the where clause on a struct must
 // outlive the location in which the type appears. Issue #22246.
@@ -47,7 +45,10 @@ fn with_assoc<'a,'b>() {
     // outlive 'a. In this case, that means TheType<'b>::TheAssocType,
     // which is &'b (), must outlive 'a.
 
-    let _: &'a WithAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
+    // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
+    // `_x` is changed to `_`
+    let _x: &'a WithAssoc<TheType<'b>> = loop { };
+    //~^ ERROR reference has a longer lifetime
 }
 
 fn with_assoc1<'a,'b>() where 'b : 'a {
@@ -57,14 +58,15 @@ fn with_assoc1<'a,'b>() where 'b : 'a {
     // which is &'b (), must outlive 'a, so 'b : 'a must hold, and
     // that is in the where clauses, so we're fine.
 
-    let _: &'a WithAssoc<TheType<'b>> = loop { };
+    let _x: &'a WithAssoc<TheType<'b>> = loop { };
 }
 
 fn without_assoc<'a,'b>() {
     // Here there are no associated types but there is a requirement
     // that `'b:'a` holds because the `'b` appears in `TheType<'b>`.
 
-    let _: &'a WithoutAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
+    let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
+    //~^ ERROR reference has a longer lifetime
 }
 
 fn call_with_assoc<'a,'b>() {
diff --git a/src/test/ui/regions/regions-outlives-projection-container.stderr b/src/test/ui/regions/regions-outlives-projection-container.stderr
index 2a698f9bff5..2c37d943616 100644
--- a/src/test/ui/regions/regions-outlives-projection-container.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container.stderr
@@ -1,67 +1,67 @@
 error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:50:12
+  --> $DIR/regions-outlives-projection-container.rs:50:13
    |
-LL |     let _: &'a WithAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 44:15
-  --> $DIR/regions-outlives-projection-container.rs:44:15
+note: the pointer is valid for the lifetime 'a as defined on the function body at 42:15
+  --> $DIR/regions-outlives-projection-container.rs:42:15
    |
 LL | fn with_assoc<'a,'b>() {
    |               ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 44:18
-  --> $DIR/regions-outlives-projection-container.rs:44:18
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 42:18
+  --> $DIR/regions-outlives-projection-container.rs:42:18
    |
 LL | fn with_assoc<'a,'b>() {
    |                  ^^
 
 error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:67:12
+  --> $DIR/regions-outlives-projection-container.rs:68:13
    |
-LL |     let _: &'a WithoutAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 63:18
-  --> $DIR/regions-outlives-projection-container.rs:63:18
+note: the pointer is valid for the lifetime 'a as defined on the function body at 64:18
+  --> $DIR/regions-outlives-projection-container.rs:64:18
    |
 LL | fn without_assoc<'a,'b>() {
    |                  ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 63:21
-  --> $DIR/regions-outlives-projection-container.rs:63:21
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 64:21
+  --> $DIR/regions-outlives-projection-container.rs:64:21
    |
 LL | fn without_assoc<'a,'b>() {
    |                     ^^
 
 error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:75:12
+  --> $DIR/regions-outlives-projection-container.rs:77:12
    |
 LL |     call::<&'a WithAssoc<TheType<'b>>>();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 70:20
-  --> $DIR/regions-outlives-projection-container.rs:70:20
+note: the pointer is valid for the lifetime 'a as defined on the function body at 72:20
+  --> $DIR/regions-outlives-projection-container.rs:72:20
    |
 LL | fn call_with_assoc<'a,'b>() {
    |                    ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 70:23
-  --> $DIR/regions-outlives-projection-container.rs:70:23
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 72:23
+  --> $DIR/regions-outlives-projection-container.rs:72:23
    |
 LL | fn call_with_assoc<'a,'b>() {
    |                       ^^
 
 error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
-  --> $DIR/regions-outlives-projection-container.rs:82:12
+  --> $DIR/regions-outlives-projection-container.rs:84:12
    |
 LL |     call::<&'a WithoutAssoc<TheType<'b>>>(); //~ ERROR reference has a longer lifetime
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 79:23
-  --> $DIR/regions-outlives-projection-container.rs:79:23
+note: the pointer is valid for the lifetime 'a as defined on the function body at 81:23
+  --> $DIR/regions-outlives-projection-container.rs:81:23
    |
 LL | fn call_without_assoc<'a,'b>() {
    |                       ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 79:26
-  --> $DIR/regions-outlives-projection-container.rs:79:26
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 81:26
+  --> $DIR/regions-outlives-projection-container.rs:81:26
    |
 LL | fn call_without_assoc<'a,'b>() {
    |                          ^^
diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr
index 35c1da61ae2..300a5639822 100644
--- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr
+++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr
@@ -1,13 +1,13 @@
-error: unsatisfied lifetime constraints
+error: captured variable cannot escape `FnMut` closure body
   --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:17:24
    |
 LL |         let mut f = || &mut x; //~ ERROR cannot infer
-   |                     -- ^^^^^^ returning this value requires that `'1` must outlive `'2`
-   |                     ||
-   |                     |return type of closure is &'2 mut i32
-   |                     lifetime `'1` represents this closure's body
+   |                      - ^^^^^^ returns a reference to a captured variable which escapes the closure body
+   |                      |
+   |                      inferred to be a `FnMut` closure
    |
-   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr
index 706d00a8424..668b75f5733 100644
--- a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr
+++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr
@@ -1,5 +1,5 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:35:9
+  --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:35:12
    |
 LL | fn use_<'short,'long>(c: S<'long, 'short>,
    |         ------ ----- lifetime `'long` defined here
@@ -7,7 +7,7 @@ LL | fn use_<'short,'long>(c: S<'long, 'short>,
    |         lifetime `'short` defined here
 ...
 LL |     let _: S<'long, 'long> = c; //~ ERROR E0623
-   |         ^ type annotation requires that `'short` must outlive `'long`
+   |            ^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr
index 144aa67f905..5d787e6dab6 100644
--- a/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr
+++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr
@@ -1,5 +1,5 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-variance-contravariant-use-covariant.rs:33:9
+  --> $DIR/regions-variance-contravariant-use-covariant.rs:33:12
    |
 LL | fn use_<'short,'long>(c: Contravariant<'short>,
    |         ------ ----- lifetime `'long` defined here
@@ -7,7 +7,7 @@ LL | fn use_<'short,'long>(c: Contravariant<'short>,
    |         lifetime `'short` defined here
 ...
 LL |     let _: Contravariant<'long> = c; //~ ERROR E0623
-   |         ^ type annotation requires that `'short` must outlive `'long`
+   |            ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr
index c9789f8555e..3fb29009668 100644
--- a/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr
+++ b/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr
@@ -1,5 +1,5 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-variance-covariant-use-contravariant.rs:33:9
+  --> $DIR/regions-variance-covariant-use-contravariant.rs:33:12
    |
 LL | fn use_<'short,'long>(c: Covariant<'long>,
    |         ------ ----- lifetime `'long` defined here
@@ -7,7 +7,7 @@ LL | fn use_<'short,'long>(c: Covariant<'long>,
    |         lifetime `'short` defined here
 ...
 LL |     let _: Covariant<'short> = c; //~ ERROR E0623
-   |         ^ type annotation requires that `'short` must outlive `'long`
+   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
index 488b70b5f0f..fb59ec1ca10 100644
--- a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
+++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
@@ -1,5 +1,5 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-variance-invariant-use-contravariant.rs:30:9
+  --> $DIR/regions-variance-invariant-use-contravariant.rs:30:12
    |
 LL | fn use_<'short,'long>(c: Invariant<'long>,
    |         ------ ----- lifetime `'long` defined here
@@ -7,7 +7,7 @@ LL | fn use_<'short,'long>(c: Invariant<'long>,
    |         lifetime `'short` defined here
 ...
 LL |     let _: Invariant<'short> = c; //~ ERROR E0623
-   |         ^ type annotation requires that `'short` must outlive `'long`
+   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
index fa7cfc33dc0..daf6a79136a 100644
--- a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
+++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
@@ -1,11 +1,11 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-variance-invariant-use-covariant.rs:27:9
+  --> $DIR/regions-variance-invariant-use-covariant.rs:27:12
    |
 LL | fn use_<'b>(c: Invariant<'b>) {
    |         -- lifetime `'b` defined here
 ...
 LL |     let _: Invariant<'static> = c; //~ ERROR mismatched types
-   |         ^ type annotation requires that `'b` must outlive `'static`
+   |            ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints.rs b/src/test/ui/resolve/issue-54379.rs
index 3ef67982be9..24aa758ea6c 100644
--- a/src/test/ui/feature-gates/feature-gate-tool_lints.rs
+++ b/src/test/ui/resolve/issue-54379.rs
@@ -7,9 +7,15 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+struct MyStruct {
+    pub s1: Option<String>,
+}
 
-#[warn(clippy::decimal_literal_representation)]
-//~^ ERROR scoped lint `clippy::decimal_literal_representation` is experimental
 fn main() {
-    let a = 65_535;
+    let thing = MyStruct { s1: None };
+
+    match thing {
+        MyStruct { .., Some(_) } => {},
+        _ => {}
+    }
 }
diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr
new file mode 100644
index 00000000000..d1d693a3817
--- /dev/null
+++ b/src/test/ui/resolve/issue-54379.stderr
@@ -0,0 +1,24 @@
+error: expected `}`, found `,`
+  --> $DIR/issue-54379.rs:18:22
+   |
+LL |         MyStruct { .., Some(_) } => {},
+   |                    --^
+   |                    | |
+   |                    | expected `}`
+   |                    `..` must be at the end and cannot have a trailing comma
+
+error: expected `,`
+  --> $DIR/issue-54379.rs:18:24
+   |
+LL |         MyStruct { .., Some(_) } => {},
+   |                        ^^^^
+
+error[E0027]: pattern does not mention field `s1`
+  --> $DIR/issue-54379.rs:18:9
+   |
+LL |         MyStruct { .., Some(_) } => {},
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `s1`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/self/self-impl.stderr b/src/test/ui/self/self-impl.stderr
index a5a5135faad..b951b119436 100644
--- a/src/test/ui/self/self-impl.stderr
+++ b/src/test/ui/self/self-impl.stderr
@@ -2,17 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:33:16
    |
 LL |         let _: <Self>::Baz = true;
-   |                ^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<Bar as Trait>::Baz`
+   |                ^^^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
 
 error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:35:16
    |
 LL |         let _: Self::Baz = true;
-   |                ^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<Bar as Trait>::Baz`
+   |                ^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr
index f8e5e3914eb..11fa447b548 100644
--- a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr
+++ b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr
@@ -4,7 +4,7 @@ error[E0597]: `tmp0` does not live long enough
 LL |         let tmp1 = &tmp0;
    |                    ^^^^^ borrowed value does not live long enough
 LL |         repeater3(tmp1)
-   |         --------------- borrow later used here
+   |         --------------- borrow later captured here by trait object
 LL |     };
    |     - `tmp0` dropped here while still borrowed
 
diff --git a/src/test/ui/structs/struct-path-associated-type.stderr b/src/test/ui/structs/struct-path-associated-type.stderr
index 1364b2a6b0c..873e7bb7b83 100644
--- a/src/test/ui/structs/struct-path-associated-type.stderr
+++ b/src/test/ui/structs/struct-path-associated-type.stderr
@@ -32,9 +32,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:42:13
    |
 LL |     let s = S::A {}; //~ ERROR ambiguous associated type
-   |             ^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<S as Trait>::A`
+   |             ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
 
 error[E0109]: type parameters are not allowed on this type
   --> $DIR/struct-path-associated-type.rs:43:20
@@ -46,17 +44,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:43:13
    |
 LL |     let z = S::A::<u8> {}; //~ ERROR ambiguous associated type
-   |             ^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<S as Trait>::A`
+   |             ^^^^^^^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:46:9
    |
 LL |         S::A {} => {} //~ ERROR ambiguous associated type
-   |         ^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<S as Trait>::A`
+   |         ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/tool_lints-fail.rs b/src/test/ui/tool_lints-fail.rs
index ea1efab4cb6..4134fca1ce6 100644
--- a/src/test/ui/tool_lints-fail.rs
+++ b/src/test/ui/tool_lints-fail.rs
@@ -10,7 +10,7 @@
 
 // Don't allow tool_lints, which aren't scoped
 
-#![feature(tool_lints)]
+
 #![deny(unknown_lints)]
 
 #![deny(clippy)] //~ ERROR: unknown lint: `clippy`
diff --git a/src/test/ui/tool_lints.rs b/src/test/ui/tool_lints.rs
index 71f90b17c18..001f2f11e5c 100644
--- a/src/test/ui/tool_lints.rs
+++ b/src/test/ui/tool_lints.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(tool_lints)]
+
 
 #[warn(foo::bar)]
 //~^ ERROR an unknown tool name found in scoped lint: `foo::bar`
diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr
index a3747bcee5d..fc14ae91d7b 100644
--- a/src/test/ui/traits/trait-item-privacy.stderr
+++ b/src/test/ui/traits/trait-item-privacy.stderr
@@ -138,25 +138,19 @@ error[E0223]: ambiguous associated type
   --> $DIR/trait-item-privacy.rs:127:12
    |
 LL |     let _: S::A; //~ ERROR ambiguous associated type
-   |            ^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<S as Trait>::A`
+   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
 
 error[E0223]: ambiguous associated type
   --> $DIR/trait-item-privacy.rs:128:12
    |
 LL |     let _: S::B; //~ ERROR ambiguous associated type
-   |            ^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<S as Trait>::B`
+   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::B`
 
 error[E0223]: ambiguous associated type
   --> $DIR/trait-item-privacy.rs:129:12
    |
 LL |     let _: S::C; //~ ERROR ambiguous associated type
-   |            ^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<S as Trait>::C`
+   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
 
 error: associated type `A` is private
   --> $DIR/trait-item-privacy.rs:131:12
diff --git a/src/test/ui/try-block/try-block-bad-lifetime.stderr b/src/test/ui/try-block/try-block-bad-lifetime.stderr
index ebf56dc9835..061bc19cec9 100644
--- a/src/test/ui/try-block/try-block-bad-lifetime.stderr
+++ b/src/test/ui/try-block/try-block-bad-lifetime.stderr
@@ -2,7 +2,7 @@ error[E0597]: `my_string` does not live long enough
   --> $DIR/try-block-bad-lifetime.rs:25:33
    |
 LL |         let result: Result<(), &str> = try {
-   |             ------ borrow later used here
+   |             ------ borrow later stored here
 LL |             let my_string = String::from("");
 LL |             let my_str: & str = & my_string;
    |                                 ^^^^^^^^^^^ borrowed value does not live long enough
diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr
index 5de8fb158b7..77d887f1d68 100644
--- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr
+++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr
@@ -184,9 +184,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/ufcs-partially-resolved.rs:46:12
    |
 LL |     let _: <u8 as Tr>::Y::NN; //~ ERROR ambiguous associated type
-   |            ^^^^^^^^^^^^^^^^^ ambiguous associated type
-   |
-   = note: specify the type using the syntax `<<u8 as Tr>::Y as Trait>::NN`
+   |            ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN`
 
 error[E0599]: no associated item named `NN` found for type `<u8 as Tr>::Y` in the current scope
   --> $DIR/ufcs-partially-resolved.rs:48:5
diff --git a/src/test/ui/underscore_const_names.rs b/src/test/ui/underscore_const_names.rs
new file mode 100644
index 00000000000..8d31fd0b1e9
--- /dev/null
+++ b/src/test/ui/underscore_const_names.rs
@@ -0,0 +1,43 @@
+// Copyright 2012-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
+
+#![feature(const_let)]
+#![feature(underscore_const_names)]
+
+trait Trt {}
+struct Str {}
+impl Trt for Str {}
+
+macro_rules! check_impl {
+    ($struct:ident,$trait:ident) => {
+        const _ : () = {
+            use std::marker::PhantomData;
+            struct ImplementsTrait<T: $trait>(PhantomData<T>);
+            let _ = ImplementsTrait::<$struct>(PhantomData);
+            ()
+        };
+    }
+}
+
+#[deny(unused)]
+const _ : () = ();
+
+const _ : i32 = 42;
+const _ : Str = Str{};
+
+check_impl!(Str, Trt);
+check_impl!(Str, Trt);
+
+fn main() {
+  check_impl!(Str, Trt);
+  check_impl!(Str, Trt);
+}
diff --git a/src/test/ui/unknown-lint-tool-name.rs b/src/test/ui/unknown-lint-tool-name.rs
index 78b736edceb..a1d6c27e518 100644
--- a/src/test/ui/unknown-lint-tool-name.rs
+++ b/src/test/ui/unknown-lint-tool-name.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(tool_lints)]
+
 
 #![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`
 
diff --git a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
index 0172fcdc8f1..eb01c2bbb05 100644
--- a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
+++ b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
@@ -1,5 +1,5 @@
 error: unsatisfied lifetime constraints
-  --> $DIR/variance-cell-is-invariant.rs:24:9
+  --> $DIR/variance-cell-is-invariant.rs:24:12
    |
 LL | fn use_<'short,'long>(c: Foo<'short>,
    |         ------ ----- lifetime `'long` defined here
@@ -7,7 +7,7 @@ LL | fn use_<'short,'long>(c: Foo<'short>,
    |         lifetime `'short` defined here
 ...
 LL |     let _: Foo<'long> = c; //~ ERROR E0623
-   |         ^ type annotation requires that `'short` must outlive `'long`
+   |            ^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr
index 51aec2a949f..bfcb16c654f 100644
--- a/src/test/ui/wf/wf-static-method.nll.stderr
+++ b/src/test/ui/wf/wf-static-method.nll.stderr
@@ -10,6 +10,17 @@ LL |         u //~ ERROR E0312
    |         ^ returning this value requires that `'b` must outlive `'a`
 
 error: unsatisfied lifetime constraints
+  --> $DIR/wf-static-method.rs:36:18
+   |
+LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |         let me = Self::make_me(); //~ ERROR lifetime bound not satisfied
+   |                  ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+
+error: unsatisfied lifetime constraints
   --> $DIR/wf-static-method.rs:43:9
    |
 LL | impl<'a, 'b> Evil<'a, 'b> {
@@ -20,5 +31,25 @@ LL |     fn inherent_evil(u: &'b u32) -> &'a u32 {
 LL |         u //~ ERROR E0312
    |         ^ returning this value requires that `'b` must outlive `'a`
 
-error: aborting due to 2 previous errors
+error: unsatisfied lifetime constraints
+  --> $DIR/wf-static-method.rs:51:5
+   |
+LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |         --  -- lifetime `'b` defined here
+   |         |
+   |         lifetime `'a` defined here
+LL |     <()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime
+   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+
+error: unsatisfied lifetime constraints
+  --> $DIR/wf-static-method.rs:55:5
+   |
+LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     <IndirectEvil>::static_evil(b)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject ad6e5c0037d88602a1c95051e42b392ed5ffcbe
+Subproject 5dbac98885199bbd7c0f189d7405b5523434d1e
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject 32b1d1fc157f71ed2f10b60fe28abe087a74361
+Subproject 9d3373137b74a403281b293b19ab9346773af07
diff --git a/src/tools/miri b/src/tools/miri
-Subproject cc275c63a90d4bea394e76607b2e10611eb1be3
+Subproject 26f9d617c347185433b77c481a5c50c55d9b72c
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 15d4d4a5b0cf3c0155195f3322cc7a61148e556
+Subproject 440a9855b73b6bf9b5345cf3a79565566f6ef34