about summary refs log tree commit diff
path: root/tests/ui/borrowck
diff options
context:
space:
mode:
authorAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-05 09:13:28 +0100
committerAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-11 09:32:08 +0000
commitcf2dff2b1e3fa55fa5415d524200070d0d7aacfe (patch)
tree40a88d9a46aaf3e8870676eb2538378b75a263eb /tests/ui/borrowck
parentca855e6e42787ecd062d81d53336fe6788ef51a9 (diff)
downloadrust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.tar.gz
rust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.zip
Move /src/test to /tests
Diffstat (limited to 'tests/ui/borrowck')
-rw-r--r--tests/ui/borrowck/access-mode-in-closures.rs10
-rw-r--r--tests/ui/borrowck/access-mode-in-closures.stderr18
-rw-r--r--tests/ui/borrowck/anonymous-region-in-apit.rs12
-rw-r--r--tests/ui/borrowck/anonymous-region-in-apit.stderr16
-rw-r--r--tests/ui/borrowck/assign-never-type.rs14
-rw-r--r--tests/ui/borrowck/assign_mutable_fields.rs22
-rw-r--r--tests/ui/borrowck/assign_mutable_fields.stderr23
-rw-r--r--tests/ui/borrowck/async-reference-generality.rs35
-rw-r--r--tests/ui/borrowck/async-reference-generality.stderr27
-rw-r--r--tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs220
-rw-r--r--tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr217
-rw-r--r--tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs14
-rw-r--r--tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr14
-rw-r--r--tests/ui/borrowck/borrow-immutable-upvar-mutation.rs56
-rw-r--r--tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr87
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-borrowed.rs22
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-borrowed.stderr40
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs23
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-deref-mutability.rs17
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr25
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-mutability-ok.rs44
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-mutability.rs42
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-mutability.stderr63
-rw-r--r--tests/ui/borrowck/borrow-tuple-fields.rs43
-rw-r--r--tests/ui/borrowck/borrow-tuple-fields.stderr65
-rw-r--r--tests/ui/borrowck/borrowck-access-permissions.rs50
-rw-r--r--tests/ui/borrowck/borrowck-access-permissions.stderr64
-rw-r--r--tests/ui/borrowck/borrowck-and-init.rs6
-rw-r--r--tests/ui/borrowck/borrowck-and-init.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-anon-fields-struct.rs37
-rw-r--r--tests/ui/borrowck/borrowck-anon-fields-struct.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-anon-fields-tuple.rs35
-rw-r--r--tests/ui/borrowck/borrowck-anon-fields-tuple.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-anon-fields-variant.rs46
-rw-r--r--tests/ui/borrowck/borrowck-anon-fields-variant.stderr40
-rw-r--r--tests/ui/borrowck/borrowck-argument.rs34
-rw-r--r--tests/ui/borrowck/borrowck-argument.stderr47
-rw-r--r--tests/ui/borrowck/borrowck-assign-comp-idx.rs39
-rw-r--r--tests/ui/borrowck/borrowck-assign-comp-idx.stderr27
-rw-r--r--tests/ui/borrowck/borrowck-assign-comp.rs36
-rw-r--r--tests/ui/borrowck/borrowck-assign-comp.stderr35
-rw-r--r--tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.rs20
-rw-r--r--tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr25
-rw-r--r--tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs23
-rw-r--r--tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr26
-rw-r--r--tests/ui/borrowck/borrowck-assign-to-constants.rs6
-rw-r--r--tests/ui/borrowck/borrowck-assign-to-constants.stderr9
-rw-r--r--tests/ui/borrowck/borrowck-assign-to-subfield.rs23
-rw-r--r--tests/ui/borrowck/borrowck-assignment-to-static-mut.rs11
-rw-r--r--tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.rs16
-rw-r--r--tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-autoref-3261.rs24
-rw-r--r--tests/ui/borrowck/borrowck-autoref-3261.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-bad-nested-calls-free.rs35
-rw-r--r--tests/ui/borrowck/borrowck-bad-nested-calls-free.stderr23
-rw-r--r--tests/ui/borrowck/borrowck-bad-nested-calls-move.rs35
-rw-r--r--tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr23
-rw-r--r--tests/ui/borrowck/borrowck-binding-mutbl.rs16
-rw-r--r--tests/ui/borrowck/borrowck-block-unint.rs7
-rw-r--r--tests/ui/borrowck/borrowck-block-unint.stderr18
-rw-r--r--tests/ui/borrowck/borrowck-borrow-from-expr-block.rs17
-rw-r--r--tests/ui/borrowck/borrowck-borrow-from-owned-ptr.rs134
-rw-r--r--tests/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr119
-rw-r--r--tests/ui/borrowck/borrowck-borrow-from-stack-variable.rs131
-rw-r--r--tests/ui/borrowck/borrowck-borrow-from-stack-variable.stderr119
-rw-r--r--tests/ui/borrowck/borrowck-borrow-from-temporary.rs14
-rw-r--r--tests/ui/borrowck/borrowck-borrow-from-temporary.stderr11
-rw-r--r--tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs14
-rw-r--r--tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs24
-rw-r--r--tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr34
-rw-r--r--tests/ui/borrowck/borrowck-borrow-mut-object-twice.rs20
-rw-r--r--tests/ui/borrowck/borrowck-borrow-mut-object-twice.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs21
-rw-r--r--tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs103
-rw-r--r--tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr116
-rw-r--r--tests/ui/borrowck/borrowck-borrow-overloaded-deref.rs43
-rw-r--r--tests/ui/borrowck/borrowck-borrow-overloaded-deref.stderr60
-rw-r--r--tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs22
-rw-r--r--tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed14
-rw-r--r--tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs13
-rw-r--r--tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr20
-rw-r--r--tests/ui/borrowck/borrowck-box-sensitivity.rs148
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit-2.rs14
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit-2.stderr18
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit.rs14
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit.stderr18
-rw-r--r--tests/ui/borrowck/borrowck-closures-mut-and-imm.rs87
-rw-r--r--tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr116
-rw-r--r--tests/ui/borrowck/borrowck-closures-mut-of-imm.rs18
-rw-r--r--tests/ui/borrowck/borrowck-closures-mut-of-imm.stderr32
-rw-r--r--tests/ui/borrowck/borrowck-closures-mut-of-mut.rs20
-rw-r--r--tests/ui/borrowck/borrowck-closures-mut-of-mut.stderr18
-rw-r--r--tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs117
-rw-r--r--tests/ui/borrowck/borrowck-closures-slice-patterns.rs82
-rw-r--r--tests/ui/borrowck/borrowck-closures-slice-patterns.stderr114
-rw-r--r--tests/ui/borrowck/borrowck-closures-two-imm.rs41
-rw-r--r--tests/ui/borrowck/borrowck-closures-two-mut-fail.rs59
-rw-r--r--tests/ui/borrowck/borrowck-closures-two-mut-fail.stderr75
-rw-r--r--tests/ui/borrowck/borrowck-closures-two-mut.rs55
-rw-r--r--tests/ui/borrowck/borrowck-closures-two-mut.stderr75
-rw-r--r--tests/ui/borrowck/borrowck-closures-unique-imm.rs18
-rw-r--r--tests/ui/borrowck/borrowck-closures-unique-imm.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-closures-unique.rs54
-rw-r--r--tests/ui/borrowck/borrowck-closures-unique.stderr54
-rw-r--r--tests/ui/borrowck/borrowck-closures-use-after-free.rs23
-rw-r--r--tests/ui/borrowck/borrowck-closures-use-after-free.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-consume-unsize-vec.rs12
-rw-r--r--tests/ui/borrowck/borrowck-consume-unsize-vec.stderr25
-rw-r--r--tests/ui/borrowck/borrowck-consume-upcast-box.rs14
-rw-r--r--tests/ui/borrowck/borrowck-consume-upcast-box.stderr21
-rw-r--r--tests/ui/borrowck/borrowck-describe-lvalue.rs279
-rw-r--r--tests/ui/borrowck/borrowck-describe-lvalue.stderr372
-rw-r--r--tests/ui/borrowck/borrowck-drop-from-guard.rs20
-rw-r--r--tests/ui/borrowck/borrowck-drop-from-guard.stderr37
-rw-r--r--tests/ui/borrowck/borrowck-escaping-closure-error-1.rs15
-rw-r--r--tests/ui/borrowck/borrowck-escaping-closure-error-1.stderr21
-rw-r--r--tests/ui/borrowck/borrowck-escaping-closure-error-2.rs15
-rw-r--r--tests/ui/borrowck/borrowck-escaping-closure-error-2.stderr21
-rw-r--r--tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs264
-rw-r--r--tests/ui/borrowck/borrowck-field-sensitivity.rs116
-rw-r--r--tests/ui/borrowck/borrowck-field-sensitivity.stderr144
-rw-r--r--tests/ui/borrowck/borrowck-fixed-length-vecs.rs7
-rw-r--r--tests/ui/borrowck/borrowck-fn-in-const-a.rs12
-rw-r--r--tests/ui/borrowck/borrowck-fn-in-const-a.stderr9
-rw-r--r--tests/ui/borrowck/borrowck-fn-in-const-c.rs23
-rw-r--r--tests/ui/borrowck/borrowck-fn-in-const-c.stderr11
-rw-r--r--tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs24
-rw-r--r--tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr48
-rw-r--r--tests/ui/borrowck/borrowck-for-loop-head-linkage.rs10
-rw-r--r--tests/ui/borrowck/borrowck-for-loop-head-linkage.stderr27
-rw-r--r--tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs7
-rw-r--r--tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-freeze-frozen-mut.rs28
-rw-r--r--tests/ui/borrowck/borrowck-if-no-else.rs6
-rw-r--r--tests/ui/borrowck/borrowck-if-no-else.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-if-with-else.rs11
-rw-r--r--tests/ui/borrowck/borrowck-if-with-else.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs10
-rw-r--r--tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-in-static.rs12
-rw-r--r--tests/ui/borrowck/borrowck-in-static.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-init-in-called-fn-expr.rs7
-rw-r--r--tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fn-expr.rs7
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fn-expr.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fru.rs12
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fru.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-init-op-equal.rs8
-rw-r--r--tests/ui/borrowck/borrowck-init-op-equal.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-init-plus-equal.rs8
-rw-r--r--tests/ui/borrowck/borrowck-init-plus-equal.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-insert-during-each.rs26
-rw-r--r--tests/ui/borrowck/borrowck-insert-during-each.stderr34
-rw-r--r--tests/ui/borrowck/borrowck-issue-14498.rs110
-rw-r--r--tests/ui/borrowck/borrowck-issue-14498.stderr103
-rw-r--r--tests/ui/borrowck/borrowck-issue-2657-1.rs14
-rw-r--r--tests/ui/borrowck/borrowck-issue-2657-1.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-issue-2657-2.fixed12
-rw-r--r--tests/ui/borrowck/borrowck-issue-2657-2.rs12
-rw-r--r--tests/ui/borrowck/borrowck-issue-2657-2.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-issue-48962.rs26
-rw-r--r--tests/ui/borrowck/borrowck-issue-48962.stderr23
-rw-r--r--tests/ui/borrowck/borrowck-lend-args.rs21
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow-if.rs51
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow-if.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow-loop.rs132
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow-loop.stderr26
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow-match.rs18
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow-match.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow.rs39
-rw-r--r--tests/ui/borrowck/borrowck-lend-flow.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move-cc.rs35
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr31
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move.rs19
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs18
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-loan-in-overloaded-op.rs23
-rw-r--r--tests/ui/borrowck/borrowck-loan-in-overloaded-op.stderr18
-rw-r--r--tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.rs24
-rw-r--r--tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.rs46
-rw-r--r--tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr28
-rw-r--r--tests/ui/borrowck/borrowck-loan-rcvr.rs40
-rw-r--r--tests/ui/borrowck/borrowck-loan-rcvr.stderr27
-rw-r--r--tests/ui/borrowck/borrowck-loan-vec-content.rs24
-rw-r--r--tests/ui/borrowck/borrowck-loan-vec-content.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-local-borrow-outlives-fn.rs6
-rw-r--r--tests/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr9
-rw-r--r--tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs10
-rw-r--r--tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-local-borrow.rs9
-rw-r--r--tests/ui/borrowck/borrowck-macro-interaction-issue-6304.rs36
-rw-r--r--tests/ui/borrowck/borrowck-match-already-borrowed.rs26
-rw-r--r--tests/ui/borrowck/borrowck-match-already-borrowed.stderr50
-rw-r--r--tests/ui/borrowck/borrowck-match-binding-is-assignment.rs41
-rw-r--r--tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr58
-rw-r--r--tests/ui/borrowck/borrowck-move-by-capture-ok.rs7
-rw-r--r--tests/ui/borrowck/borrowck-move-by-capture.rs11
-rw-r--r--tests/ui/borrowck/borrowck-move-by-capture.stderr17
-rw-r--r--tests/ui/borrowck/borrowck-move-error-with-note.fixed56
-rw-r--r--tests/ui/borrowck/borrowck-move-error-with-note.rs56
-rw-r--r--tests/ui/borrowck/borrowck-move-error-with-note.stderr60
-rw-r--r--tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs17
-rw-r--r--tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-move-from-unsafe-ptr.rs7
-rw-r--r--tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-move-in-irrefut-pat.rs16
-rw-r--r--tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr48
-rw-r--r--tests/ui/borrowck/borrowck-move-moved-value-into-closure.rs12
-rw-r--r--tests/ui/borrowck/borrowck-move-moved-value-into-closure.stderr18
-rw-r--r--tests/ui/borrowck/borrowck-move-mut-base-ptr.rs19
-rw-r--r--tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-match.rs116
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-match.stderr153
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs115
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr138
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs67
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs150
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr213
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs115
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr138
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs67
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-use.rs97
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array-use.stderr199
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array.rs71
-rw-r--r--tests/ui/borrowck/borrowck-move-out-from-array.stderr143
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs6
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr19
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs6
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-static-item.rs16
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-static-item.stderr9
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.fixed24
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs24
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr49
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.fixed24
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs24
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr49
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-vec-tail.rs33
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-vec-tail.stderr21
-rw-r--r--tests/ui/borrowck/borrowck-move-subcomponent.rs17
-rw-r--r--tests/ui/borrowck/borrowck-move-subcomponent.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-multiple-borrows-interior-boxes.rs20
-rw-r--r--tests/ui/borrowck/borrowck-multiple-captures.rs61
-rw-r--r--tests/ui/borrowck/borrowck-multiple-captures.stderr122
-rw-r--r--tests/ui/borrowck/borrowck-mut-addr-of-imm-var.rs6
-rw-r--r--tests/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-mut-borrow-linear-errors.rs15
-rw-r--r--tests/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr35
-rw-r--r--tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs28
-rw-r--r--tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr26
-rw-r--r--tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.rs8
-rw-r--r--tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-mut-uniq.rs32
-rw-r--r--tests/ui/borrowck/borrowck-mut-vec-as-imm-slice.rs16
-rw-r--r--tests/ui/borrowck/borrowck-mutate-in-guard.rs34
-rw-r--r--tests/ui/borrowck/borrowck-mutate-in-guard.stderr37
-rw-r--r--tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs20
-rw-r--r--tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-object-lifetime.rs40
-rw-r--r--tests/ui/borrowck/borrowck-object-lifetime.stderr23
-rw-r--r--tests/ui/borrowck/borrowck-or-init.rs6
-rw-r--r--tests/ui/borrowck/borrowck-or-init.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-call.rs80
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-call.stderr36
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs36
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-autoderef.rs97
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr84
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs22
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-move-index.rs68
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr45
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-ref-index.rs59
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-index-ref-index.stderr35
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-1.rs39
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-1.stderr25
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-2.rs23
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-2.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-3.rs13
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-3.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-4.rs22
-rw-r--r--tests/ui/borrowck/borrowck-partial-reinit-4.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-pat-enum.rs39
-rw-r--r--tests/ui/borrowck/borrowck-pat-reassign-binding.rs15
-rw-r--r--tests/ui/borrowck/borrowck-pat-reassign-binding.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-pat-reassign-no-binding.rs14
-rw-r--r--tests/ui/borrowck/borrowck-reborrow-from-mut.rs99
-rw-r--r--tests/ui/borrowck/borrowck-reborrow-from-mut.stderr119
-rw-r--r--tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.rs22
-rw-r--r--tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-ref-mut-of-imm.rs10
-rw-r--r--tests/ui/borrowck/borrowck-ref-mut-of-imm.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-reinit.rs7
-rw-r--r--tests/ui/borrowck/borrowck-reinit.stderr19
-rw-r--r--tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs44
-rw-r--r--tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr40
-rw-r--r--tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs10
-rw-r--r--tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-return.rs6
-rw-r--r--tests/ui/borrowck/borrowck-return.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-rvalues-mutable.rs34
-rw-r--r--tests/ui/borrowck/borrowck-scope-of-deref-issue-4666.rs42
-rw-r--r--tests/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs64
-rw-r--r--tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs58
-rw-r--r--tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr86
-rw-r--r--tests/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs21
-rw-r--r--tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs59
-rw-r--r--tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs79
-rw-r--r--tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr117
-rw-r--r--tests/ui/borrowck/borrowck-static-item-in-fn.rs9
-rw-r--r--tests/ui/borrowck/borrowck-storage-dead.rs24
-rw-r--r--tests/ui/borrowck/borrowck-storage-dead.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-struct-update-with-dtor.rs21
-rw-r--r--tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr21
-rw-r--r--tests/ui/borrowck/borrowck-swap-mut-base-ptr.rs22
-rw-r--r--tests/ui/borrowck/borrowck-swap-mut-base-ptr.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs9
-rw-r--r--tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr11
-rw-r--r--tests/ui/borrowck/borrowck-trait-lifetime.rs18
-rw-r--r--tests/ui/borrowck/borrowck-unary-move.rs11
-rw-r--r--tests/ui/borrowck/borrowck-unary-move.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-unboxed-closures.rs17
-rw-r--r--tests/ui/borrowck/borrowck-unboxed-closures.stderr45
-rw-r--r--tests/ui/borrowck/borrowck-uninit-after-item.rs5
-rw-r--r--tests/ui/borrowck/borrowck-uninit-after-item.stderr17
-rw-r--r--tests/ui/borrowck/borrowck-uninit-field-access.rs30
-rw-r--r--tests/ui/borrowck/borrowck-uninit-field-access.stderr37
-rw-r--r--tests/ui/borrowck/borrowck-uninit-in-assignop.rs34
-rw-r--r--tests/ui/borrowck/borrowck-uninit-in-assignop.stderr133
-rw-r--r--tests/ui/borrowck/borrowck-uninit-ref-chain.rs33
-rw-r--r--tests/ui/borrowck/borrowck-uninit-ref-chain.stderr82
-rw-r--r--tests/ui/borrowck/borrowck-uninit.rs6
-rw-r--r--tests/ui/borrowck/borrowck-uninit.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-union-borrow-nested.rs31
-rw-r--r--tests/ui/borrowck/borrowck-union-borrow-nested.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-union-borrow.rs96
-rw-r--r--tests/ui/borrowck/borrowck-union-borrow.stderr131
-rw-r--r--tests/ui/borrowck/borrowck-union-move-assign.rs32
-rw-r--r--tests/ui/borrowck/borrowck-union-move-assign.stderr13
-rw-r--r--tests/ui/borrowck/borrowck-union-move.rs86
-rw-r--r--tests/ui/borrowck/borrowck-union-move.stderr63
-rw-r--r--tests/ui/borrowck/borrowck-union-uninitialized.rs18
-rw-r--r--tests/ui/borrowck/borrowck-union-uninitialized.stderr25
-rw-r--r--tests/ui/borrowck/borrowck-uniq-via-lend.rs61
-rw-r--r--tests/ui/borrowck/borrowck-uniq-via-lend.stderr23
-rw-r--r--tests/ui/borrowck/borrowck-uniq-via-ref.rs49
-rw-r--r--tests/ui/borrowck/borrowck-univariant-enum.rs25
-rw-r--r--tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs20
-rw-r--r--tests/ui/borrowck/borrowck-unused-mut-locals.rs47
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.rs9
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr29
-rw-r--r--tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs49
-rw-r--r--tests/ui/borrowck/borrowck-use-mut-borrow.rs86
-rw-r--r--tests/ui/borrowck/borrowck-use-mut-borrow.stderr95
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs10
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs8
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-element-loan.rs31
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-element-loan.stderr30
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs12
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-move-tail.rs11
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr14
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-nesting.rs94
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr125
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs14
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-while-break.rs12
-rw-r--r--tests/ui/borrowck/borrowck-while-break.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-while-cond.rs4
-rw-r--r--tests/ui/borrowck/borrowck-while-cond.stderr16
-rw-r--r--tests/ui/borrowck/borrowck-while.rs7
-rw-r--r--tests/ui/borrowck/borrowck-while.stderr13
-rw-r--r--tests/ui/borrowck/copy-suggestion-region-vid.rs17
-rw-r--r--tests/ui/borrowck/copy-suggestion-region-vid.stderr14
-rw-r--r--tests/ui/borrowck/disallow-possibly-uninitialized.rs22
-rw-r--r--tests/ui/borrowck/disallow-possibly-uninitialized.stderr43
-rw-r--r--tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs8
-rw-r--r--tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr18
-rw-r--r--tests/ui/borrowck/fsu-moves-and-copies.rs95
-rw-r--r--tests/ui/borrowck/immut-function-arguments.rs9
-rw-r--r--tests/ui/borrowck/immut-function-arguments.stderr25
-rw-r--r--tests/ui/borrowck/immutable-arg.rs6
-rw-r--r--tests/ui/borrowck/immutable-arg.stderr11
-rw-r--r--tests/ui/borrowck/index-mut-help-with-impl.rs10
-rw-r--r--tests/ui/borrowck/index-mut-help-with-impl.stderr9
-rw-r--r--tests/ui/borrowck/index-mut-help.rs13
-rw-r--r--tests/ui/borrowck/index-mut-help.stderr41
-rw-r--r--tests/ui/borrowck/issue-101119.rs16
-rw-r--r--tests/ui/borrowck/issue-101119.stderr15
-rw-r--r--tests/ui/borrowck/issue-102209.rs28
-rw-r--r--tests/ui/borrowck/issue-102209.stderr22
-rw-r--r--tests/ui/borrowck/issue-103095.rs30
-rw-r--r--tests/ui/borrowck/issue-103250.rs37
-rw-r--r--tests/ui/borrowck/issue-103250.stderr17
-rw-r--r--tests/ui/borrowck/issue-103624.rs31
-rw-r--r--tests/ui/borrowck/issue-103624.stderr35
-rw-r--r--tests/ui/borrowck/issue-104639-lifetime-order.rs10
-rw-r--r--tests/ui/borrowck/issue-10876.rs17
-rw-r--r--tests/ui/borrowck/issue-11493.fixed9
-rw-r--r--tests/ui/borrowck/issue-11493.rs8
-rw-r--r--tests/ui/borrowck/issue-11493.stderr19
-rw-r--r--tests/ui/borrowck/issue-17263.rs23
-rw-r--r--tests/ui/borrowck/issue-17545.rs10
-rw-r--r--tests/ui/borrowck/issue-17545.stderr16
-rw-r--r--tests/ui/borrowck/issue-17718-static-move.rs7
-rw-r--r--tests/ui/borrowck/issue-17718-static-move.stderr14
-rw-r--r--tests/ui/borrowck/issue-20801.rs37
-rw-r--r--tests/ui/borrowck/issue-20801.stderr51
-rw-r--r--tests/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs30
-rw-r--r--tests/ui/borrowck/issue-24267-flow-exit.rs19
-rw-r--r--tests/ui/borrowck/issue-24267-flow-exit.stderr33
-rw-r--r--tests/ui/borrowck/issue-25793.rs26
-rw-r--r--tests/ui/borrowck/issue-25793.stderr18
-rw-r--r--tests/ui/borrowck/issue-28934.rs25
-rw-r--r--tests/ui/borrowck/issue-29166.rs21
-rw-r--r--tests/ui/borrowck/issue-31287-drop-in-guard.rs15
-rw-r--r--tests/ui/borrowck/issue-31287-drop-in-guard.stderr35
-rw-r--r--tests/ui/borrowck/issue-33819.rs9
-rw-r--r--tests/ui/borrowck/issue-33819.stderr12
-rw-r--r--tests/ui/borrowck/issue-36082.fixed17
-rw-r--r--tests/ui/borrowck/issue-36082.rs16
-rw-r--r--tests/ui/borrowck/issue-36082.stderr20
-rw-r--r--tests/ui/borrowck/issue-41962.rs9
-rw-r--r--tests/ui/borrowck/issue-41962.stderr15
-rw-r--r--tests/ui/borrowck/issue-42344.rs8
-rw-r--r--tests/ui/borrowck/issue-42344.stderr9
-rw-r--r--tests/ui/borrowck/issue-45199.rs24
-rw-r--r--tests/ui/borrowck/issue-45199.stderr35
-rw-r--r--tests/ui/borrowck/issue-45983.rs12
-rw-r--r--tests/ui/borrowck/issue-45983.stderr13
-rw-r--r--tests/ui/borrowck/issue-46095.rs30
-rw-r--r--tests/ui/borrowck/issue-46471.rs7
-rw-r--r--tests/ui/borrowck/issue-46471.stderr9
-rw-r--r--tests/ui/borrowck/issue-47215-ice-from-drop-elab.rs20
-rw-r--r--tests/ui/borrowck/issue-47215-ice-from-drop-elab.stderr14
-rw-r--r--tests/ui/borrowck/issue-51117.rs15
-rw-r--r--tests/ui/borrowck/issue-51117.stderr13
-rw-r--r--tests/ui/borrowck/issue-51301.rs35
-rw-r--r--tests/ui/borrowck/issue-51301.stderr17
-rw-r--r--tests/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs21
-rw-r--r--tests/ui/borrowck/issue-51415.fixed12
-rw-r--r--tests/ui/borrowck/issue-51415.rs12
-rw-r--r--tests/ui/borrowck/issue-51415.stderr17
-rw-r--r--tests/ui/borrowck/issue-52713-bug.rs17
-rw-r--r--tests/ui/borrowck/issue-52713-bug.stderr14
-rw-r--r--tests/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs21
-rw-r--r--tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs7
-rw-r--r--tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr19
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs33
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr33
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs36
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr33
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs42
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr100
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-of-never-init.rs33
-rw-r--r--tests/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr33
-rw-r--r--tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs20
-rw-r--r--tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr15
-rw-r--r--tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs55
-rw-r--r--tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr54
-rw-r--r--tests/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs31
-rw-r--r--tests/ui/borrowck/issue-58776-borrowck-scans-children.rs11
-rw-r--r--tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr32
-rw-r--r--tests/ui/borrowck/issue-62007-assign-box.rs27
-rw-r--r--tests/ui/borrowck/issue-62007-assign-field.rs26
-rw-r--r--tests/ui/borrowck/issue-62107-match-arm-scopes.rs12
-rw-r--r--tests/ui/borrowck/issue-62107-match-arm-scopes.stderr16
-rw-r--r--tests/ui/borrowck/issue-64453.rs23
-rw-r--r--tests/ui/borrowck/issue-64453.stderr29
-rw-r--r--tests/ui/borrowck/issue-69789-iterator-mut-suggestion.rs11
-rw-r--r--tests/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr12
-rw-r--r--tests/ui/borrowck/issue-71546.rs17
-rw-r--r--tests/ui/borrowck/issue-7573.rs41
-rw-r--r--tests/ui/borrowck/issue-7573.stderr15
-rw-r--r--tests/ui/borrowck/issue-80772.rs21
-rw-r--r--tests/ui/borrowck/issue-81365-1.rs26
-rw-r--r--tests/ui/borrowck/issue-81365-1.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-10.rs26
-rw-r--r--tests/ui/borrowck/issue-81365-10.stderr13
-rw-r--r--tests/ui/borrowck/issue-81365-11.rs32
-rw-r--r--tests/ui/borrowck/issue-81365-11.stderr13
-rw-r--r--tests/ui/borrowck/issue-81365-2.rs30
-rw-r--r--tests/ui/borrowck/issue-81365-2.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-3.rs37
-rw-r--r--tests/ui/borrowck/issue-81365-3.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-4.rs38
-rw-r--r--tests/ui/borrowck/issue-81365-4.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-5.rs33
-rw-r--r--tests/ui/borrowck/issue-81365-5.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-6.rs23
-rw-r--r--tests/ui/borrowck/issue-81365-6.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-7.rs24
-rw-r--r--tests/ui/borrowck/issue-81365-7.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-8.rs26
-rw-r--r--tests/ui/borrowck/issue-81365-8.stderr20
-rw-r--r--tests/ui/borrowck/issue-81365-9.rs26
-rw-r--r--tests/ui/borrowck/issue-81365-9.stderr13
-rw-r--r--tests/ui/borrowck/issue-81899.rs15
-rw-r--r--tests/ui/borrowck/issue-81899.stderr27
-rw-r--r--tests/ui/borrowck/issue-82032.rs16
-rw-r--r--tests/ui/borrowck/issue-82032.stderr14
-rw-r--r--tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs24
-rw-r--r--tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr33
-rw-r--r--tests/ui/borrowck/issue-82462.rs21
-rw-r--r--tests/ui/borrowck/issue-82462.stderr22
-rw-r--r--tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs32
-rw-r--r--tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr12
-rw-r--r--tests/ui/borrowck/issue-83760.rs40
-rw-r--r--tests/ui/borrowck/issue-83760.stderr60
-rw-r--r--tests/ui/borrowck/issue-85581.rs15
-rw-r--r--tests/ui/borrowck/issue-85581.stderr17
-rw-r--r--tests/ui/borrowck/issue-85765.rs29
-rw-r--r--tests/ui/borrowck/issue-85765.stderr42
-rw-r--r--tests/ui/borrowck/issue-87456-point-to-closure.rs14
-rw-r--r--tests/ui/borrowck/issue-87456-point-to-closure.stderr20
-rw-r--r--tests/ui/borrowck/issue-88434-minimal-example.rs14
-rw-r--r--tests/ui/borrowck/issue-88434-minimal-example.stderr27
-rw-r--r--tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs14
-rw-r--r--tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr27
-rw-r--r--tests/ui/borrowck/issue-91206.rs16
-rw-r--r--tests/ui/borrowck/issue-91206.stderr12
-rw-r--r--tests/ui/borrowck/issue-92015.rs7
-rw-r--r--tests/ui/borrowck/issue-92015.stderr11
-rw-r--r--tests/ui/borrowck/issue-93078.rs15
-rw-r--r--tests/ui/borrowck/issue-93078.stderr12
-rw-r--r--tests/ui/borrowck/issue-93093.rs14
-rw-r--r--tests/ui/borrowck/issue-93093.stderr14
-rw-r--r--tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs14
-rw-r--r--tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr37
-rw-r--r--tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs49
-rw-r--r--tests/ui/borrowck/lazy-init.rs8
-rw-r--r--tests/ui/borrowck/many-mutable-borrows.rs18
-rw-r--r--tests/ui/borrowck/many-mutable-borrows.stderr33
-rw-r--r--tests/ui/borrowck/move-error-in-promoted-2.rs10
-rw-r--r--tests/ui/borrowck/move-error-in-promoted-2.stderr12
-rw-r--r--tests/ui/borrowck/move-error-in-promoted.rs17
-rw-r--r--tests/ui/borrowck/move-error-in-promoted.stderr12
-rw-r--r--tests/ui/borrowck/move-error-snippets-ext.rs7
-rw-r--r--tests/ui/borrowck/move-error-snippets.rs23
-rw-r--r--tests/ui/borrowck/move-error-snippets.stderr20
-rw-r--r--tests/ui/borrowck/move-from-union-field-issue-66500.rs28
-rw-r--r--tests/ui/borrowck/move-from-union-field-issue-66500.stderr27
-rw-r--r--tests/ui/borrowck/move-in-pattern-mut-in-loop.rs10
-rw-r--r--tests/ui/borrowck/move-in-pattern-mut-in-loop.stderr15
-rw-r--r--tests/ui/borrowck/move-in-pattern-mut.rs23
-rw-r--r--tests/ui/borrowck/move-in-pattern-mut.stderr33
-rw-r--r--tests/ui/borrowck/move-in-pattern.fixed24
-rw-r--r--tests/ui/borrowck/move-in-pattern.rs24
-rw-r--r--tests/ui/borrowck/move-in-pattern.stderr33
-rw-r--r--tests/ui/borrowck/move-in-static-initializer-issue-38520.rs16
-rw-r--r--tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr15
-rw-r--r--tests/ui/borrowck/mut-borrow-in-loop-2.fixed35
-rw-r--r--tests/ui/borrowck/mut-borrow-in-loop-2.rs35
-rw-r--r--tests/ui/borrowck/mut-borrow-in-loop-2.stderr25
-rw-r--r--tests/ui/borrowck/mut-borrow-in-loop.rs29
-rw-r--r--tests/ui/borrowck/mut-borrow-in-loop.stderr47
-rw-r--r--tests/ui/borrowck/mut-borrow-of-mut-ref.rs36
-rw-r--r--tests/ui/borrowck/mut-borrow-of-mut-ref.stderr59
-rw-r--r--tests/ui/borrowck/mut-borrow-outside-loop.rs22
-rw-r--r--tests/ui/borrowck/mut-borrow-outside-loop.stderr24
-rw-r--r--tests/ui/borrowck/mutability-errors.rs82
-rw-r--r--tests/ui/borrowck/mutability-errors.stderr361
-rw-r--r--tests/ui/borrowck/or-patterns.rs62
-rw-r--r--tests/ui/borrowck/or-patterns.stderr157
-rw-r--r--tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs31
-rw-r--r--tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr50
-rw-r--r--tests/ui/borrowck/reassignment_immutable_fields.rs20
-rw-r--r--tests/ui/borrowck/reassignment_immutable_fields.stderr23
-rw-r--r--tests/ui/borrowck/reassignment_immutable_fields_overlapping.rs16
-rw-r--r--tests/ui/borrowck/reassignment_immutable_fields_overlapping.stderr25
-rw-r--r--tests/ui/borrowck/reassignment_immutable_fields_twice.rs17
-rw-r--r--tests/ui/borrowck/reassignment_immutable_fields_twice.stderr25
-rw-r--r--tests/ui/borrowck/reborrow-sugg-move-then-borrow.rs26
-rw-r--r--tests/ui/borrowck/reborrow-sugg-move-then-borrow.stderr21
-rw-r--r--tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs54
-rw-r--r--tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr78
-rw-r--r--tests/ui/borrowck/regions-escape-bound-fn-2.rs13
-rw-r--r--tests/ui/borrowck/regions-escape-bound-fn-2.stderr13
-rw-r--r--tests/ui/borrowck/regions-escape-bound-fn.rs13
-rw-r--r--tests/ui/borrowck/regions-escape-bound-fn.stderr13
-rw-r--r--tests/ui/borrowck/regions-escape-unboxed-closure.rs7
-rw-r--r--tests/ui/borrowck/regions-escape-unboxed-closure.stderr13
-rw-r--r--tests/ui/borrowck/return-local-binding-from-desugaring.rs33
-rw-r--r--tests/ui/borrowck/return-local-binding-from-desugaring.stderr12
-rw-r--r--tests/ui/borrowck/slice-index-bounds-check-invalidation.rs82
-rw-r--r--tests/ui/borrowck/slice-index-bounds-check-invalidation.stderr35
-rw-r--r--tests/ui/borrowck/suggest-as-ref-on-mut-closure.rs16
-rw-r--r--tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr25
-rw-r--r--tests/ui/borrowck/suggest-assign-rvalue.rs57
-rw-r--r--tests/ui/borrowck/suggest-assign-rvalue.stderr138
-rw-r--r--tests/ui/borrowck/suggest-local-var-double-mut.rs27
-rw-r--r--tests/ui/borrowck/suggest-local-var-double-mut.stderr44
-rw-r--r--tests/ui/borrowck/suggest-local-var-for-vector.rs4
-rw-r--r--tests/ui/borrowck/suggest-local-var-for-vector.stderr24
-rw-r--r--tests/ui/borrowck/suggest-local-var-imm-and-mut.rs27
-rw-r--r--tests/ui/borrowck/suggest-local-var-imm-and-mut.stderr22
-rw-r--r--tests/ui/borrowck/suggest-storing-local-var-for-vector.rs4
-rw-r--r--tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr24
-rw-r--r--tests/ui/borrowck/two-phase-across-loop.rs22
-rw-r--r--tests/ui/borrowck/two-phase-across-loop.stderr12
-rw-r--r--tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr47
-rw-r--r--tests/ui/borrowck/two-phase-activation-sharing-interference.rs65
-rw-r--r--tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr27
-rw-r--r--tests/ui/borrowck/two-phase-allow-access-during-reservation.rs37
-rw-r--r--tests/ui/borrowck/two-phase-baseline.rs9
-rw-r--r--tests/ui/borrowck/two-phase-bin-ops.rs35
-rw-r--r--tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs19
-rw-r--r--tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr19
-rw-r--r--tests/ui/borrowck/two-phase-control-flow-split-before-activation.rs15
-rw-r--r--tests/ui/borrowck/two-phase-method-receivers.rs15
-rw-r--r--tests/ui/borrowck/two-phase-multi-mut.rs14
-rw-r--r--tests/ui/borrowck/two-phase-multi-mut.stderr23
-rw-r--r--tests/ui/borrowck/two-phase-multiple-activations.rs21
-rw-r--r--tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr93
-rw-r--r--tests/ui/borrowck/two-phase-nonrecv-autoref.rs166
-rw-r--r--tests/ui/borrowck/two-phase-reservation-sharing-interference-2.rs29
-rw-r--r--tests/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr25
-rw-r--r--tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr15
-rw-r--r--tests/ui/borrowck/two-phase-reservation-sharing-interference.rs45
-rw-r--r--tests/ui/borrowck/two-phase-sneaky.rs15
-rw-r--r--tests/ui/borrowck/two-phase-sneaky.stderr14
-rw-r--r--tests/ui/borrowck/two-phase-surprise-no-conflict.rs167
-rw-r--r--tests/ui/borrowck/two-phase-surprise-no-conflict.stderr161
-rw-r--r--tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed15
-rw-r--r--tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs15
-rw-r--r--tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr22
632 files changed, 21856 insertions, 0 deletions
diff --git a/tests/ui/borrowck/access-mode-in-closures.rs b/tests/ui/borrowck/access-mode-in-closures.rs
new file mode 100644
index 00000000000..9bd90e70aba
--- /dev/null
+++ b/tests/ui/borrowck/access-mode-in-closures.rs
@@ -0,0 +1,10 @@
+struct S(Vec<isize>);
+
+fn unpack<F>(_unpack: F) where F: FnOnce(&S) -> Vec<isize> {}
+
+fn main() {
+    let _foo = unpack(|s| {
+        // Test that `s` is moved here.
+        match *s { S(v) => v } //~ ERROR cannot move out
+    });
+}
diff --git a/tests/ui/borrowck/access-mode-in-closures.stderr b/tests/ui/borrowck/access-mode-in-closures.stderr
new file mode 100644
index 00000000000..abee72ba8cf
--- /dev/null
+++ b/tests/ui/borrowck/access-mode-in-closures.stderr
@@ -0,0 +1,18 @@
+error[E0507]: cannot move out of `s` which is behind a shared reference
+  --> $DIR/access-mode-in-closures.rs:8:15
+   |
+LL |         match *s { S(v) => v }
+   |               ^^     -
+   |                      |
+   |                      data moved here
+   |                      move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -         match *s { S(v) => v }
+LL +         match s { S(v) => v }
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/anonymous-region-in-apit.rs b/tests/ui/borrowck/anonymous-region-in-apit.rs
new file mode 100644
index 00000000000..7799a7cb151
--- /dev/null
+++ b/tests/ui/borrowck/anonymous-region-in-apit.rs
@@ -0,0 +1,12 @@
+#![feature(anonymous_lifetime_in_impl_trait)]
+
+trait Foo<T> {
+    fn bar(self, baz: T);
+}
+
+fn qux(foo: impl Foo<&str>) {
+    |baz: &str| foo.bar(baz);
+    //~^ ERROR borrowed data escapes outside of closure
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/anonymous-region-in-apit.stderr b/tests/ui/borrowck/anonymous-region-in-apit.stderr
new file mode 100644
index 00000000000..9e100f8ac3c
--- /dev/null
+++ b/tests/ui/borrowck/anonymous-region-in-apit.stderr
@@ -0,0 +1,16 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/anonymous-region-in-apit.rs:8:17
+   |
+LL | fn qux(foo: impl Foo<&str>) {
+   |        --- lifetime `'2` appears in the type of `foo`
+LL |     |baz: &str| foo.bar(baz);
+   |      ---  -     ^^^^^^^^^^^^
+   |      |    |     |
+   |      |    |     `baz` escapes the closure body here
+   |      |    |     argument requires that `'1` must outlive `'2`
+   |      |    let's call the lifetime of this reference `'1`
+   |      `baz` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/borrowck/assign-never-type.rs b/tests/ui/borrowck/assign-never-type.rs
new file mode 100644
index 00000000000..4f30ea14670
--- /dev/null
+++ b/tests/ui/borrowck/assign-never-type.rs
@@ -0,0 +1,14 @@
+// Regression test for issue 62165
+
+// check-pass
+
+#![feature(never_type)]
+
+pub fn main() {
+    loop {
+        match None {
+            None => return,
+            Some(val) => val,
+        };
+    };
+}
diff --git a/tests/ui/borrowck/assign_mutable_fields.rs b/tests/ui/borrowck/assign_mutable_fields.rs
new file mode 100644
index 00000000000..b60726d0c8b
--- /dev/null
+++ b/tests/ui/borrowck/assign_mutable_fields.rs
@@ -0,0 +1,22 @@
+// Currently, we do permit you to assign to individual fields of an
+// uninitialized var.
+// We hope to fix this at some point.
+//
+// FIXME(#54987)
+
+fn assign_both_fields_and_use() {
+    let mut x: (u32, u32);
+    x.0 = 1; //~ ERROR
+    x.1 = 22;
+    drop(x.0);
+    drop(x.1);
+}
+
+fn assign_both_fields_the_use_var() {
+    let mut x: (u32, u32);
+    x.0 = 1; //~ ERROR
+    x.1 = 22;
+    drop(x);
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/assign_mutable_fields.stderr b/tests/ui/borrowck/assign_mutable_fields.stderr
new file mode 100644
index 00000000000..1ed92865da5
--- /dev/null
+++ b/tests/ui/borrowck/assign_mutable_fields.stderr
@@ -0,0 +1,23 @@
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/assign_mutable_fields.rs:9:5
+   |
+LL |     let mut x: (u32, u32);
+   |         ----- binding declared here but left uninitialized
+LL |     x.0 = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/assign_mutable_fields.rs:17:5
+   |
+LL |     let mut x: (u32, u32);
+   |         ----- binding declared here but left uninitialized
+LL |     x.0 = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/async-reference-generality.rs b/tests/ui/borrowck/async-reference-generality.rs
new file mode 100644
index 00000000000..487d1ac81bf
--- /dev/null
+++ b/tests/ui/borrowck/async-reference-generality.rs
@@ -0,0 +1,35 @@
+// check-fail
+// known-bug: #99492
+// edition: 2021
+
+use std::marker::PhantomData;
+
+pub struct Struct<I, T>(PhantomData<fn() -> <Self as It>::Item>)
+where
+    Self: It;
+
+impl<I> It for Struct<I, I::Item>
+where
+    I: It,
+{
+    type Item = ();
+}
+
+pub trait It {
+    type Item;
+}
+
+fn f() -> impl Send {
+    async {
+        let _x = Struct::<Empty<&'static ()>, _>(PhantomData);
+        async {}.await;
+    }
+}
+
+pub struct Empty<T>(PhantomData<fn() -> T>);
+
+impl<T> It for Empty<T> {
+    type Item = T;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/async-reference-generality.stderr b/tests/ui/borrowck/async-reference-generality.stderr
new file mode 100644
index 00000000000..af720ad2931
--- /dev/null
+++ b/tests/ui/borrowck/async-reference-generality.stderr
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/async-reference-generality.rs:23:5
+   |
+LL | /     async {
+LL | |         let _x = Struct::<Empty<&'static ()>, _>(PhantomData);
+LL | |         async {}.await;
+LL | |     }
+   | |_____^ one type is more general than the other
+   |
+   = note: expected reference `&()`
+              found reference `&()`
+
+error[E0308]: mismatched types
+  --> $DIR/async-reference-generality.rs:23:5
+   |
+LL | /     async {
+LL | |         let _x = Struct::<Empty<&'static ()>, _>(PhantomData);
+LL | |         async {}.await;
+LL | |     }
+   | |_____^ one type is more general than the other
+   |
+   = note: expected reference `&()`
+              found reference `&()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
new file mode 100644
index 00000000000..baf31bd89f4
--- /dev/null
+++ b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
@@ -0,0 +1,220 @@
+// Tests using a combination of pattern features has the expected borrow checking behavior
+#![feature(box_patterns)]
+
+enum Test {
+    Foo,
+    Bar,
+    _Baz,
+}
+
+// bindings_after_at + slice_patterns
+
+fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
+    match x {
+        a @ [.., _] => (),
+        _ => (),
+    };
+
+    &x;
+    //~^ ERROR borrow of moved value
+}
+
+fn bindings_after_at_slice_patterns_borrows_binding_mut(mut x: [String; 4]) {
+    let r = match x {
+        ref mut foo @ [.., _] => Some(foo),
+        _ => None,
+    };
+
+    &x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn bindings_after_at_slice_patterns_borrows_slice_mut1(mut x: [String; 4]) {
+    let r = match x {
+        ref foo @ [.., ref mut bar] => (),
+        //~^ ERROR cannot borrow
+        _ => (),
+    };
+
+    drop(r);
+}
+
+fn bindings_after_at_slice_patterns_borrows_slice_mut2(mut x: [String; 4]) {
+    let r = match x {
+        [ref foo @ .., ref bar] => Some(foo),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn bindings_after_at_slice_patterns_borrows_both(mut x: [String; 4]) {
+    let r = match x {
+        ref foo @ [.., ref bar] => Some(foo),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+// bindings_after_at + or_patterns
+
+fn bindings_after_at_or_patterns_move(x: Option<Test>) {
+    match x {
+        foo @ Some(Test::Foo | Test::Bar) => (),
+        _ => (),
+    }
+
+    &x;
+    //~^ ERROR borrow of moved value
+}
+
+fn bindings_after_at_or_patterns_borrows(mut x: Option<Test>) {
+    let r = match x {
+        ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn bindings_after_at_or_patterns_borrows_mut(mut x: Option<Test>) {
+    let r = match x {
+        ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
+        _ => None,
+    };
+
+    &x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+// bindings_after_at + box_patterns
+
+fn bindings_after_at_box_patterns_borrows_both(mut x: Option<Box<String>>) {
+    let r = match x {
+        ref foo @ Some(box ref s) => Some(foo),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn bindings_after_at_box_patterns_borrows_mut(mut x: Option<Box<String>>) {
+    match x {
+        ref foo @ Some(box ref mut s) => (),
+        //~^ ERROR cannot borrow
+        _ => (),
+    };
+}
+
+// bindings_after_at + slice_patterns + or_patterns
+
+fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) {
+    match x {
+        a @ [.., Some(Test::Foo | Test::Bar)] => (),
+        _ => (),
+    };
+
+    &x;
+    //~^ ERROR borrow of moved value
+}
+
+fn bindings_after_at_slice_patterns_or_patterns_borrows_binding(mut x: [Option<Test>; 4]) {
+    let r = match x {
+        ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn bindings_after_at_slice_patterns_or_patterns_borrows_slice(mut x: [Option<Test>; 4]) {
+    let r = match x {
+        ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+// bindings_after_at + slice_patterns + box_patterns
+
+fn bindings_after_at_slice_patterns_box_patterns_borrows(mut x: [Option<Box<String>>; 4]) {
+    let r = match x {
+        [_, ref a @ Some(box ref b), ..] => Some(a),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+// bindings_after_at + slice_patterns + or_patterns + box_patterns
+
+fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows(
+    mut x: [Option<Box<Test>>; 4]
+) {
+    let r = match x {
+        [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows_mut(
+    mut x: [Option<Box<Test>>; 4]
+) {
+    let r = match x {
+        [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
+        _ => None,
+    };
+
+    &x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows_binding(
+    mut x: [Option<Box<Test>>; 4]
+) {
+    let r = match x {
+        ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
+        _ => None,
+    };
+
+    &mut x;
+    //~^ ERROR cannot borrow
+
+    drop(r);
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
new file mode 100644
index 00000000000..50eee1049db
--- /dev/null
+++ b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -0,0 +1,217 @@
+error: cannot borrow value as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:36:9
+   |
+LL |         ref foo @ [.., ref mut bar] => (),
+   |         -------^^^^^^^^-----------^
+   |         |              |
+   |         |              mutable borrow, by `bar`, occurs here
+   |         immutable borrow, by `foo`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9
+   |
+LL |         ref foo @ Some(box ref mut s) => (),
+   |         -------^^^^^^^^^^^^---------^
+   |         |                  |
+   |         |                  mutable borrow, by `s`, occurs here
+   |         immutable borrow, by `foo`, occurs here
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:18:5
+   |
+LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
+   |                                                  - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait
+LL |     match x {
+LL |         a @ [.., _] => (),
+   |         - value moved here
+...
+LL |     &x;
+   |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ [.., _] => (),
+   |         +++
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5
+   |
+LL |         ref mut foo @ [.., _] => Some(foo),
+   |         ----------- mutable borrow occurs here
+...
+LL |     &x;
+   |     ^^ immutable borrow occurs here
+...
+LL |     drop(r);
+   |          - mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:50:5
+   |
+LL |         [ref foo @ .., ref bar] => Some(foo),
+   |          ------- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:62:5
+   |
+LL |         ref foo @ [.., ref bar] => Some(foo),
+   |         ------- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:76:5
+   |
+LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
+   |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
+LL |     match x {
+LL |         foo @ Some(Test::Foo | Test::Bar) => (),
+   |         --- value moved here
+...
+LL |     &x;
+   |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref foo @ Some(Test::Foo | Test::Bar) => (),
+   |         +++
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5
+   |
+LL |         ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
+   |         ------- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:98:5
+   |
+LL |         ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
+   |         ----------- mutable borrow occurs here
+...
+LL |     &x;
+   |     ^^ immutable borrow occurs here
+...
+LL |     drop(r);
+   |          - mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:112:5
+   |
+LL |         ref foo @ Some(box ref s) => Some(foo),
+   |         ------- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:134:5
+   |
+LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) {
+   |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
+LL |     match x {
+LL |         a @ [.., Some(Test::Foo | Test::Bar)] => (),
+   |         - value moved here
+...
+LL |     &x;
+   |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ [.., Some(Test::Foo | Test::Bar)] => (),
+   |         +++
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5
+   |
+LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
+   |         ----- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:156:5
+   |
+LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
+   |                  ----- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:170:5
+   |
+LL |         [_, ref a @ Some(box ref b), ..] => Some(a),
+   |             ----- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:186:5
+   |
+LL |         [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
+   |             ----- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:200:5
+   |
+LL |         [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
+   |             --------- mutable borrow occurs here
+...
+LL |     &x;
+   |     ^^ immutable borrow occurs here
+...
+LL |     drop(r);
+   |          - mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:214:5
+   |
+LL |         ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
+   |         ----- immutable borrow occurs here
+...
+LL |     &mut x;
+   |     ^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error: aborting due to 17 previous errors
+
+Some errors have detailed explanations: E0382, E0502.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs
new file mode 100644
index 00000000000..57198cb95e7
--- /dev/null
+++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs
@@ -0,0 +1,14 @@
+#![feature(unboxed_closures)]
+
+// Tests that we can't assign to or mutably borrow upvars from `Fn`
+// closures (issue #17780)
+
+fn main() {}
+
+fn bar() -> impl Fn() -> usize {
+    let mut x = 0;
+    move || {
+        x += 1; //~ ERROR cannot assign
+        x
+    }
+}
diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr
new file mode 100644
index 00000000000..6235e0db0da
--- /dev/null
+++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr
@@ -0,0 +1,14 @@
+error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation-impl-trait.rs:11:9
+   |
+LL | fn bar() -> impl Fn() -> usize {
+   |    ---      ------------------ change this to return `FnMut` instead of `Fn`
+LL |     let mut x = 0;
+LL |     move || {
+   |     ------- in this closure
+LL |         x += 1;
+   |         ^^^^^^ cannot assign
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation.rs b/tests/ui/borrowck/borrow-immutable-upvar-mutation.rs
new file mode 100644
index 00000000000..a3350024e75
--- /dev/null
+++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation.rs
@@ -0,0 +1,56 @@
+#![feature(unboxed_closures, tuple_trait)]
+
+// Tests that we can't assign to or mutably borrow upvars from `Fn`
+// closures (issue #17780)
+
+fn set(x: &mut usize) {
+    *x = 5;
+}
+
+fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+    f
+}
+fn to_fn_mut<A: std::marker::Tuple, F: FnMut<A>>(f: F) -> F {
+    f
+}
+
+fn main() {
+    // By-ref captures
+    {
+        let mut x = 0;
+        let _f = to_fn(|| x = 42); //~ ERROR cannot assign
+
+        let mut y = 0;
+        let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
+
+        let mut z = 0;
+        let _h = to_fn_mut(|| {
+            set(&mut z);
+            to_fn(|| z = 42); //~ ERROR cannot assign
+        });
+    }
+
+    // By-value captures
+    {
+        let mut x = 0;
+        let _f = to_fn(move || x = 42); //~ ERROR cannot assign
+
+        let mut y = 0;
+        let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
+
+        let mut z = 0;
+        let _h = to_fn_mut(move || {
+            set(&mut z);
+            to_fn(move || z = 42);
+            //~^ ERROR cannot assign
+        });
+    }
+}
+
+fn foo() -> Box<dyn Fn() -> usize> {
+    let mut x = 0;
+    Box::new(move || {
+        x += 1; //~ ERROR cannot assign
+        x
+    })
+}
diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr
new file mode 100644
index 00000000000..a0eaf1f163b
--- /dev/null
+++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr
@@ -0,0 +1,87 @@
+error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation.rs:21:27
+   |
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
+...
+LL |         let _f = to_fn(|| x = 42);
+   |                  ----- -- ^^^^^^ cannot assign
+   |                  |     |
+   |                  |     in this closure
+   |                  expects `Fn` instead of `FnMut`
+
+error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation.rs:24:31
+   |
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
+...
+LL |         let _g = to_fn(|| set(&mut y));
+   |                  ----- --     ^^^^^^ cannot borrow as mutable
+   |                  |     |
+   |                  |     in this closure
+   |                  expects `Fn` instead of `FnMut`
+
+error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation.rs:29:22
+   |
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
+...
+LL |             to_fn(|| z = 42);
+   |             ----- -- ^^^^^^ cannot assign
+   |             |     |
+   |             |     in this closure
+   |             expects `Fn` instead of `FnMut`
+
+error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation.rs:36:32
+   |
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
+...
+LL |         let _f = to_fn(move || x = 42);
+   |                  ----- ------- ^^^^^^ cannot assign
+   |                  |     |
+   |                  |     in this closure
+   |                  expects `Fn` instead of `FnMut`
+
+error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation.rs:39:36
+   |
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
+...
+LL |         let _g = to_fn(move || set(&mut y));
+   |                  ----- -------     ^^^^^^ cannot borrow as mutable
+   |                  |     |
+   |                  |     in this closure
+   |                  expects `Fn` instead of `FnMut`
+
+error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation.rs:44:27
+   |
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
+...
+LL |             to_fn(move || z = 42);
+   |             ----- ------- ^^^^^^ cannot assign
+   |             |     |
+   |             |     in this closure
+   |             expects `Fn` instead of `FnMut`
+
+error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-immutable-upvar-mutation.rs:53:9
+   |
+LL | fn foo() -> Box<dyn Fn() -> usize> {
+   |    ---      ---------------------- change this to return `FnMut` instead of `Fn`
+LL |     let mut x = 0;
+LL |     Box::new(move || {
+   |              ------- in this closure
+LL |         x += 1;
+   |         ^^^^^^ cannot assign
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/borrow-raw-address-of-borrowed.rs b/tests/ui/borrowck/borrow-raw-address-of-borrowed.rs
new file mode 100644
index 00000000000..f25fd7f66b3
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-borrowed.rs
@@ -0,0 +1,22 @@
+#![feature(raw_ref_op)]
+
+fn address_of_shared() {
+    let mut x = 0;
+    let y = &x;
+
+    let q = &raw mut x;                 //~ ERROR cannot borrow
+
+    drop(y);
+}
+
+fn address_of_mutably_borrowed() {
+    let mut x = 0;
+    let y = &mut x;
+
+    let p = &raw const x;               //~ ERROR cannot borrow
+    let q = &raw mut x;                 //~ ERROR cannot borrow
+
+    drop(y);
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrow-raw-address-of-borrowed.stderr b/tests/ui/borrowck/borrow-raw-address-of-borrowed.stderr
new file mode 100644
index 00000000000..6f7b7e08070
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-borrowed.stderr
@@ -0,0 +1,40 @@
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-raw-address-of-borrowed.rs:7:13
+   |
+LL |     let y = &x;
+   |             -- immutable borrow occurs here
+LL |
+LL |     let q = &raw mut x;
+   |             ^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |     drop(y);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-raw-address-of-borrowed.rs:16:13
+   |
+LL |     let y = &mut x;
+   |             ------ mutable borrow occurs here
+LL |
+LL |     let p = &raw const x;
+   |             ^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |     drop(y);
+   |          - mutable borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrow-raw-address-of-borrowed.rs:17:13
+   |
+LL |     let y = &mut x;
+   |             ------ first mutable borrow occurs here
+...
+LL |     let q = &raw mut x;
+   |             ^^^^^^^^^^ second mutable borrow occurs here
+LL |
+LL |     drop(y);
+   |          - first borrow later used here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0499, E0502.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs
new file mode 100644
index 00000000000..e381384fe65
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![feature(raw_ref_op)]
+
+fn raw_reborrow() {
+    let x = &0;
+    let y = &mut 0;
+
+    let p = &raw const *x;
+    let r = &raw const *y;
+    let s = &raw mut *y;
+}
+
+unsafe fn raw_reborrow_of_raw() {
+    let x = &0 as *const i32;
+    let y = &mut 0 as *mut i32;
+
+    let p = &raw const *x;
+    let r = &raw const *y;
+    let s = &raw mut *y;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.rs b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.rs
new file mode 100644
index 00000000000..712873528b5
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.rs
@@ -0,0 +1,17 @@
+// Check that `&raw mut` cannot be used to turn a `&T` into a `*mut T`.
+
+#![feature(raw_ref_op)]
+
+fn raw_reborrow() {
+    let x = &0;
+
+    let q = &raw mut *x;                //~ ERROR cannot borrow
+}
+
+unsafe fn raw_reborrow_of_raw() {
+    let x = &0 as *const i32;
+
+    let q = &raw mut *x;                //~ ERROR cannot borrow
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
new file mode 100644
index 00000000000..4cc1d821d0a
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
@@ -0,0 +1,25 @@
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
+  --> $DIR/borrow-raw-address-of-deref-mutability.rs:8:13
+   |
+LL |     let q = &raw mut *x;
+   |             ^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let x = &mut 0;
+   |             ~~~~~~
+
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
+  --> $DIR/borrow-raw-address-of-deref-mutability.rs:14:13
+   |
+LL |     let q = &raw mut *x;
+   |             ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL |     let x = &mut 0 as *const i32;
+   |             ~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability-ok.rs b/tests/ui/borrowck/borrow-raw-address-of-mutability-ok.rs
new file mode 100644
index 00000000000..e1cf2dc5386
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-mutability-ok.rs
@@ -0,0 +1,44 @@
+// check-pass
+
+#![feature(raw_ref_op)]
+
+fn mutable_address_of() {
+    let mut x = 0;
+    let y = &raw mut x;
+}
+
+fn mutable_address_of_closure() {
+    let mut x = 0;
+    let mut f = || {
+        let y = &raw mut x;
+    };
+    f();
+}
+
+fn const_address_of_closure() {
+    let x = 0;
+    let f = || {
+        let y = &raw const x;
+    };
+    f();
+}
+
+fn make_fn<F: Fn()>(f: F) -> F { f }
+
+fn const_address_of_fn_closure() {
+    let x = 0;
+    let f = make_fn(|| {
+        let y = &raw const x;
+    });
+    f();
+}
+
+fn const_address_of_fn_closure_move() {
+    let x = 0;
+    let f = make_fn(move || {
+        let y = &raw const x;
+    });
+    f();
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability.rs b/tests/ui/borrowck/borrow-raw-address-of-mutability.rs
new file mode 100644
index 00000000000..320c54b806a
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-mutability.rs
@@ -0,0 +1,42 @@
+#![feature(raw_ref_op)]
+
+fn mutable_address_of() {
+    let x = 0;
+    let y = &raw mut x;                 //~ ERROR cannot borrow
+}
+
+fn mutable_address_of_closure() {
+    let x = 0;
+    let mut f = || {
+        let y = &raw mut x;             //~ ERROR cannot borrow
+    };
+    f();
+}
+
+fn mutable_address_of_imm_closure() {
+    let mut x = 0;
+    let f = || {
+        let y = &raw mut x;
+    };
+    f();                                //~ ERROR cannot borrow
+}
+
+fn make_fn<F: Fn()>(f: F) -> F { f }
+
+fn mutable_address_of_fn_closure() {
+    let mut x = 0;
+    let f = make_fn(|| {
+        let y = &raw mut x;             //~ ERROR cannot borrow
+    });
+    f();
+}
+
+fn mutable_address_of_fn_closure_move() {
+    let mut x = 0;
+    let f = make_fn(move || {
+        let y = &raw mut x;             //~ ERROR cannot borrow
+    });
+    f();
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr
new file mode 100644
index 00000000000..a7748209187
--- /dev/null
+++ b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr
@@ -0,0 +1,63 @@
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-raw-address-of-mutability.rs:5:13
+   |
+LL |     let y = &raw mut x;
+   |             ^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
+
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-raw-address-of-mutability.rs:11:17
+   |
+LL |     let x = 0;
+   |         - help: consider changing this to be mutable: `mut x`
+LL |     let mut f = || {
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-raw-address-of-mutability.rs:21:5
+   |
+LL |         let y = &raw mut x;
+   |                          - calling `f` requires mutable binding due to mutable borrow of `x`
+LL |     };
+LL |     f();
+   |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut f = || {
+   |         +++
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-raw-address-of-mutability.rs:29:17
+   |
+LL | fn make_fn<F: Fn()>(f: F) -> F { f }
+   |                        - change this to accept `FnMut` instead of `Fn`
+...
+LL |     let f = make_fn(|| {
+   |             ------- -- in this closure
+   |             |
+   |             expects `Fn` instead of `FnMut`
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-raw-address-of-mutability.rs:37:17
+   |
+LL | fn make_fn<F: Fn()>(f: F) -> F { f }
+   |                        - change this to accept `FnMut` instead of `Fn`
+...
+LL |     let f = make_fn(move || {
+   |             ------- ------- in this closure
+   |             |
+   |             expects `Fn` instead of `FnMut`
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrow-tuple-fields.rs b/tests/ui/borrowck/borrow-tuple-fields.rs
new file mode 100644
index 00000000000..c628fa49ede
--- /dev/null
+++ b/tests/ui/borrowck/borrow-tuple-fields.rs
@@ -0,0 +1,43 @@
+struct Foo(Box<isize>, isize);
+
+struct Bar(isize, isize);
+
+
+
+
+
+fn main() {
+    let x: (Box<_>, _) = (Box::new(1), 2);
+    let r = &x.0;
+    let y = x; //~ ERROR cannot move out of `x` because it is borrowed
+
+    r.use_ref();
+
+    let mut x = (1, 2);
+    let a = &x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
+    a.use_ref();
+
+    let mut x = (1, 2);
+    let a = &mut x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
+    a.use_ref();
+
+    let x = Foo(Box::new(1), 2);
+    let r = &x.0;
+    let y = x; //~ ERROR cannot move out of `x` because it is borrowed
+    r.use_ref();
+
+    let mut x = Bar(1, 2);
+    let a = &x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
+    a.use_ref();
+
+    let mut x = Bar(1, 2);
+    let a = &mut x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
+    a.use_mut();
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrow-tuple-fields.stderr b/tests/ui/borrowck/borrow-tuple-fields.stderr
new file mode 100644
index 00000000000..befa751a600
--- /dev/null
+++ b/tests/ui/borrowck/borrow-tuple-fields.stderr
@@ -0,0 +1,65 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/borrow-tuple-fields.rs:12:13
+   |
+LL |     let r = &x.0;
+   |             ---- borrow of `x.0` occurs here
+LL |     let y = x;
+   |             ^ move out of `x` occurs here
+LL |
+LL |     r.use_ref();
+   |     ----------- borrow later used here
+
+error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-tuple-fields.rs:18:13
+   |
+LL |     let a = &x.0;
+   |             ---- immutable borrow occurs here
+LL |     let b = &mut x.0;
+   |             ^^^^^^^^ mutable borrow occurs here
+LL |     a.use_ref();
+   |     ----------- immutable borrow later used here
+
+error[E0499]: cannot borrow `x.0` as mutable more than once at a time
+  --> $DIR/borrow-tuple-fields.rs:23:13
+   |
+LL |     let a = &mut x.0;
+   |             -------- first mutable borrow occurs here
+LL |     let b = &mut x.0;
+   |             ^^^^^^^^ second mutable borrow occurs here
+LL |     a.use_ref();
+   |     ----------- first borrow later used here
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/borrow-tuple-fields.rs:28:13
+   |
+LL |     let r = &x.0;
+   |             ---- borrow of `x.0` occurs here
+LL |     let y = x;
+   |             ^ move out of `x` occurs here
+LL |     r.use_ref();
+   |     ----------- borrow later used here
+
+error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-tuple-fields.rs:33:13
+   |
+LL |     let a = &x.0;
+   |             ---- immutable borrow occurs here
+LL |     let b = &mut x.0;
+   |             ^^^^^^^^ mutable borrow occurs here
+LL |     a.use_ref();
+   |     ----------- immutable borrow later used here
+
+error[E0499]: cannot borrow `x.0` as mutable more than once at a time
+  --> $DIR/borrow-tuple-fields.rs:38:13
+   |
+LL |     let a = &mut x.0;
+   |             -------- first mutable borrow occurs here
+LL |     let b = &mut x.0;
+   |             ^^^^^^^^ second mutable borrow occurs here
+LL |     a.use_mut();
+   |     ----------- first borrow later used here
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0505.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs
new file mode 100644
index 00000000000..469ad508b0e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-access-permissions.rs
@@ -0,0 +1,50 @@
+static static_x : i32 = 1;
+static mut static_x_mut : i32 = 1;
+
+fn main() {
+    let x = 1;
+    let mut x_mut = 1;
+
+    { // borrow of local
+        let _y1 = &mut x; //~ ERROR [E0596]
+        let _y2 = &mut x_mut; // No error
+    }
+
+    { // borrow of static
+        let _y1 = &mut static_x; //~ ERROR [E0596]
+        unsafe { let _y2 = &mut static_x_mut; } // No error
+    }
+
+    { // borrow of deref to box
+        let box_x = Box::new(1);
+        let mut box_x_mut = Box::new(1);
+
+        let _y1 = &mut *box_x; //~ ERROR [E0596]
+        let _y2 = &mut *box_x_mut; // No error
+    }
+
+    { // borrow of deref to reference
+        let ref_x = &x;
+        let ref_x_mut = &mut x_mut;
+
+        let _y1 = &mut *ref_x; //~ ERROR [E0596]
+        let _y2 = &mut *ref_x_mut; // No error
+    }
+
+    { // borrow of deref to pointer
+        let ptr_x : *const _ = &x;
+        let ptr_mut_x : *mut _ = &mut x_mut;
+
+        unsafe {
+            let _y1 = &mut *ptr_x; //~ ERROR [E0596]
+            let _y2 = &mut *ptr_mut_x; // No error
+        }
+    }
+
+    { // borrowing mutably through an immutable reference
+        struct Foo<'a> { f: &'a mut i32, g: &'a i32 };
+        let mut foo = Foo { f: &mut x_mut, g: &x };
+        let foo_ref = &foo;
+        let _y = &mut *foo_ref.f; //~ ERROR [E0596]
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr
new file mode 100644
index 00000000000..26f3e2bbdb7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-access-permissions.stderr
@@ -0,0 +1,64 @@
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-access-permissions.rs:9:19
+   |
+LL |         let _y1 = &mut x;
+   |                   ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 1;
+   |         +++
+
+error[E0596]: cannot borrow immutable static item `static_x` as mutable
+  --> $DIR/borrowck-access-permissions.rs:14:19
+   |
+LL |         let _y1 = &mut static_x;
+   |                   ^^^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable
+  --> $DIR/borrowck-access-permissions.rs:22:19
+   |
+LL |         let _y1 = &mut *box_x;
+   |                   ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut box_x = Box::new(1);
+   |             +++
+
+error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference
+  --> $DIR/borrowck-access-permissions.rs:30:19
+   |
+LL |         let _y1 = &mut *ref_x;
+   |                   ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |         let ref_x = &mut x;
+   |                     ~~~~~~
+
+error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer
+  --> $DIR/borrowck-access-permissions.rs:39:23
+   |
+LL |             let _y1 = &mut *ptr_x;
+   |                       ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL |         let ptr_x : *const _ = &mut x;
+   |                                ~~~~~~
+
+error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference
+  --> $DIR/borrowck-access-permissions.rs:48:18
+   |
+LL |         let _y = &mut *foo_ref.f;
+   |                  ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |         let foo_ref = &mut foo;
+   |                       ~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrowck-and-init.rs b/tests/ui/borrowck/borrowck-and-init.rs
new file mode 100644
index 00000000000..eeb4f05d60c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-and-init.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let i: isize;
+
+    println!("{}", false && { i = 5; true });
+    println!("{}", i); //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-and-init.stderr b/tests/ui/borrowck/borrowck-and-init.stderr
new file mode 100644
index 00000000000..5abf07a3118
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-and-init.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `i` is possibly-uninitialized
+  --> $DIR/borrowck-and-init.rs:5:20
+   |
+LL |     let i: isize;
+   |         - binding declared here but left uninitialized
+LL |
+LL |     println!("{}", false && { i = 5; true });
+   |                               ----- binding initialized here in some conditions
+LL |     println!("{}", i);
+   |                    ^ `i` used here but it is possibly-uninitialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-anon-fields-struct.rs b/tests/ui/borrowck/borrowck-anon-fields-struct.rs
new file mode 100644
index 00000000000..a05dfe62b28
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-anon-fields-struct.rs
@@ -0,0 +1,37 @@
+// Tests that we are able to distinguish when loans borrow different
+// anonymous fields of a tuple vs the same anonymous field.
+
+struct Y(usize, usize);
+
+fn distinct_variant() {
+    let mut y = Y(1, 2);
+
+    let a = match y {
+        Y(ref mut a, _) => a
+    };
+
+    let b = match y {
+        Y(_, ref mut b) => b
+    };
+
+    *a += 1;
+    *b += 1;
+}
+
+fn same_variant() {
+    let mut y = Y(1, 2);
+
+    let a = match y {
+        Y(ref mut a, _) => a
+    };
+
+    let b = match y {
+        Y(ref mut b, _) => b //~ ERROR cannot borrow
+    };
+
+    *a += 1;
+    *b += 1;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-anon-fields-struct.stderr b/tests/ui/borrowck/borrowck-anon-fields-struct.stderr
new file mode 100644
index 00000000000..7a959fb6ec6
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-anon-fields-struct.stderr
@@ -0,0 +1,15 @@
+error[E0499]: cannot borrow `y.0` as mutable more than once at a time
+  --> $DIR/borrowck-anon-fields-struct.rs:29:11
+   |
+LL |         Y(ref mut a, _) => a
+   |           --------- first mutable borrow occurs here
+...
+LL |         Y(ref mut b, _) => b
+   |           ^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     *a += 1;
+   |     ------- first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-anon-fields-tuple.rs b/tests/ui/borrowck/borrowck-anon-fields-tuple.rs
new file mode 100644
index 00000000000..de2a8d83268
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-anon-fields-tuple.rs
@@ -0,0 +1,35 @@
+// Tests that we are able to distinguish when loans borrow different
+// anonymous fields of a tuple vs the same anonymous field.
+
+fn distinct_variant() {
+    let mut y = (1, 2);
+
+    let a = match y {
+        (ref mut a, _) => a
+    };
+
+    let b = match y {
+        (_, ref mut b) => b
+    };
+
+    *a += 1;
+    *b += 1;
+}
+
+fn same_variant() {
+    let mut y = (1, 2);
+
+    let a = match y {
+        (ref mut a, _) => a
+    };
+
+    let b = match y {
+        (ref mut b, _) => b //~ ERROR cannot borrow
+    };
+
+    *a += 1;
+    *b += 1;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-anon-fields-tuple.stderr b/tests/ui/borrowck/borrowck-anon-fields-tuple.stderr
new file mode 100644
index 00000000000..88a8867f5ee
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-anon-fields-tuple.stderr
@@ -0,0 +1,15 @@
+error[E0499]: cannot borrow `y.0` as mutable more than once at a time
+  --> $DIR/borrowck-anon-fields-tuple.rs:27:10
+   |
+LL |         (ref mut a, _) => a
+   |          --------- first mutable borrow occurs here
+...
+LL |         (ref mut b, _) => b
+   |          ^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     *a += 1;
+   |     ------- first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-anon-fields-variant.rs b/tests/ui/borrowck/borrowck-anon-fields-variant.rs
new file mode 100644
index 00000000000..6e63de9136c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-anon-fields-variant.rs
@@ -0,0 +1,46 @@
+enum Foo {
+    X, Y(usize, usize)
+}
+
+fn distinct_variant() {
+    let mut y = Foo::Y(1, 2);
+
+    let a = match y {
+      Foo::Y(ref mut a, _) => a,
+      Foo::X => panic!()
+    };
+
+    // While `a` and `b` are disjoint, borrowck doesn't know that `a` is not
+    // also used for the discriminant of `Foo`, which it would be if `a` was a
+    // reference.
+    let b = match y {
+      //~^ ERROR cannot use `y`
+      Foo::Y(_, ref mut b) => b,
+      Foo::X => panic!()
+    };
+
+    *a += 1;
+    *b += 1;
+}
+
+fn same_variant() {
+    let mut y = Foo::Y(1, 2);
+
+    let a = match y {
+      Foo::Y(ref mut a, _) => a,
+      Foo::X => panic!()
+    };
+
+    let b = match y {
+      //~^ ERROR cannot use `y`
+      Foo::Y(ref mut b, _) => b,
+      //~^ ERROR cannot borrow `y.0` as mutable
+      Foo::X => panic!()
+    };
+
+    *a += 1;
+    *b += 1;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-anon-fields-variant.stderr b/tests/ui/borrowck/borrowck-anon-fields-variant.stderr
new file mode 100644
index 00000000000..98f6f00a7d4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-anon-fields-variant.stderr
@@ -0,0 +1,40 @@
+error[E0503]: cannot use `y` because it was mutably borrowed
+  --> $DIR/borrowck-anon-fields-variant.rs:16:19
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- borrow of `y.0` occurs here
+...
+LL |     let b = match y {
+   |                   ^ use of borrowed `y.0`
+...
+LL |     *a += 1;
+   |     ------- borrow later used here
+
+error[E0503]: cannot use `y` because it was mutably borrowed
+  --> $DIR/borrowck-anon-fields-variant.rs:34:19
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- borrow of `y.0` occurs here
+...
+LL |     let b = match y {
+   |                   ^ use of borrowed `y.0`
+...
+LL |     *a += 1;
+   |     ------- borrow later used here
+
+error[E0499]: cannot borrow `y.0` as mutable more than once at a time
+  --> $DIR/borrowck-anon-fields-variant.rs:36:14
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- first mutable borrow occurs here
+...
+LL |       Foo::Y(ref mut b, _) => b,
+   |              ^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     *a += 1;
+   |     ------- first borrow later used here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0499, E0503.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-argument.rs b/tests/ui/borrowck/borrowck-argument.rs
new file mode 100644
index 00000000000..5d776d4fca4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-argument.rs
@@ -0,0 +1,34 @@
+#[derive(Copy, Clone)]
+struct S;
+
+impl S {
+    fn mutate(&mut self) {
+    }
+}
+
+fn func(arg: S) {
+    arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable
+}
+
+impl S {
+    fn method(&self, arg: S) {
+        arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable
+    }
+}
+
+trait T {
+    fn default(&self, arg: S) {
+        arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable
+    }
+}
+
+impl T for S {}
+
+fn main() {
+    let s = S;
+    func(s);
+    s.method(s);
+    s.default(s);
+    (|arg: S| { arg.mutate() })(s);
+    //~^ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable
+}
diff --git a/tests/ui/borrowck/borrowck-argument.stderr b/tests/ui/borrowck/borrowck-argument.stderr
new file mode 100644
index 00000000000..1c992dfcceb
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-argument.stderr
@@ -0,0 +1,47 @@
+error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-argument.rs:10:5
+   |
+LL |     arg.mutate();
+   |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn func(mut arg: S) {
+   |         +++
+
+error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-argument.rs:15:9
+   |
+LL |         arg.mutate();
+   |         ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn method(&self, mut arg: S) {
+   |                      +++
+
+error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-argument.rs:21:9
+   |
+LL |         arg.mutate();
+   |         ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn default(&self, mut arg: S) {
+   |                       +++
+
+error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-argument.rs:32:17
+   |
+LL |     (|arg: S| { arg.mutate() })(s);
+   |                 ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     (|mut arg: S| { arg.mutate() })(s);
+   |       +++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrowck-assign-comp-idx.rs b/tests/ui/borrowck/borrowck-assign-comp-idx.rs
new file mode 100644
index 00000000000..f4dffeb8c38
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-comp-idx.rs
@@ -0,0 +1,39 @@
+struct Point {
+    x: isize,
+    y: isize,
+}
+
+fn a() {
+    let mut p = vec![1];
+
+    // Create an immutable pointer into p's contents:
+    let q: &isize = &p[0];
+
+    p[0] = 5; //~ ERROR cannot borrow
+
+    println!("{}", *q);
+}
+
+fn borrow<F>(_x: &[isize], _f: F) where F: FnOnce() {}
+
+fn b() {
+    // here we alias the mutable vector into an imm slice and try to
+    // modify the original:
+
+    let mut p = vec![1];
+
+    borrow(
+        &p,
+        || p[0] = 5); //~ ERROR cannot borrow `p` as mutable
+}
+
+fn c() {
+    // Legal because the scope of the borrow does not include the
+    // modification:
+    let mut p = vec![1];
+    borrow(&p, ||{});
+    p[0] = 5;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-assign-comp-idx.stderr b/tests/ui/borrowck/borrowck-assign-comp-idx.stderr
new file mode 100644
index 00000000000..b80174ae687
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-comp-idx.stderr
@@ -0,0 +1,27 @@
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-assign-comp-idx.rs:12:5
+   |
+LL |     let q: &isize = &p[0];
+   |                      - immutable borrow occurs here
+LL |
+LL |     p[0] = 5;
+   |     ^ mutable borrow occurs here
+LL |
+LL |     println!("{}", *q);
+   |                    -- immutable borrow later used here
+
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-assign-comp-idx.rs:27:9
+   |
+LL |     borrow(
+   |     ------ immutable borrow later used by call
+LL |         &p,
+   |         -- immutable borrow occurs here
+LL |         || p[0] = 5);
+   |         ^^ - second borrow occurs due to use of `p` in closure
+   |         |
+   |         mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-assign-comp.rs b/tests/ui/borrowck/borrowck-assign-comp.rs
new file mode 100644
index 00000000000..98bb2d85ad7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-comp.rs
@@ -0,0 +1,36 @@
+struct Point { x: isize, y: isize }
+
+fn a() {
+    let mut p = Point {x: 3, y: 4};
+    let q = &p;
+
+    // This assignment is illegal because the field x is not
+    // inherently mutable; since `p` was made immutable, `p.x` is now
+    // immutable.  Otherwise the type of &_q.x (&isize) would be wrong.
+    p.x = 5; //~ ERROR cannot assign to `p.x` because it is borrowed
+    q.x;
+}
+
+fn c() {
+    // this is sort of the opposite.  We take a loan to the interior of `p`
+    // and then try to overwrite `p` as a whole.
+
+    let mut p = Point {x: 3, y: 4};
+    let q = &p.y;
+    p = Point {x: 5, y: 7};//~ ERROR cannot assign to `p` because it is borrowed
+    p.x; // silence warning
+    *q; // stretch loan
+}
+
+fn d() {
+    // just for completeness's sake, the easy case, where we take the
+    // address of a subcomponent and then modify that subcomponent:
+
+    let mut p = Point {x: 3, y: 4};
+    let q = &p.y;
+    p.y = 5; //~ ERROR cannot assign to `p.y` because it is borrowed
+    *q;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-assign-comp.stderr b/tests/ui/borrowck/borrowck-assign-comp.stderr
new file mode 100644
index 00000000000..2b7cef7b325
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-comp.stderr
@@ -0,0 +1,35 @@
+error[E0506]: cannot assign to `p.x` because it is borrowed
+  --> $DIR/borrowck-assign-comp.rs:10:5
+   |
+LL |     let q = &p;
+   |             -- borrow of `p.x` occurs here
+...
+LL |     p.x = 5;
+   |     ^^^^^^^ assignment to borrowed `p.x` occurs here
+LL |     q.x;
+   |     --- borrow later used here
+
+error[E0506]: cannot assign to `p` because it is borrowed
+  --> $DIR/borrowck-assign-comp.rs:20:5
+   |
+LL |     let q = &p.y;
+   |             ---- borrow of `p` occurs here
+LL |     p = Point {x: 5, y: 7};
+   |     ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here
+LL |     p.x; // silence warning
+LL |     *q; // stretch loan
+   |     -- borrow later used here
+
+error[E0506]: cannot assign to `p.y` because it is borrowed
+  --> $DIR/borrowck-assign-comp.rs:31:5
+   |
+LL |     let q = &p.y;
+   |             ---- borrow of `p.y` occurs here
+LL |     p.y = 5;
+   |     ^^^^^^^ assignment to borrowed `p.y` occurs here
+LL |     *q;
+   |     -- borrow later used here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.rs b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.rs
new file mode 100644
index 00000000000..879c03791eb
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.rs
@@ -0,0 +1,20 @@
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'a> {
+    pointer: &'a mut isize
+}
+
+fn a(s: &S) {
+    *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn b(s: &mut S) {
+    *s.pointer += 1;
+}
+
+fn c(s: & &mut S) {
+    *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr
new file mode 100644
index 00000000000..cbacc87a0e8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr
@@ -0,0 +1,25 @@
+error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference
+  --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:9:5
+   |
+LL |     *s.pointer += 1;
+   |     ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn a(s: &mut S<'_>) {
+   |         ~~~~~~~~~~
+
+error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference
+  --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:17:5
+   |
+LL |     *s.pointer += 1;
+   |     ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn c(s: &mut &mut S<'_>) {
+   |         ~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs
new file mode 100644
index 00000000000..f7aee2b8a93
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs
@@ -0,0 +1,23 @@
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'a> {
+    pointer: &'a mut isize
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+    S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+    let mut x = 1;
+
+    {
+        let mut y = S { pointer: &mut x };
+        let z = copy_borrowed_ptr(&mut y);
+        *y.pointer += 1;
+        //~^ ERROR cannot use `*y.pointer`
+        //~| ERROR cannot assign to `*y.pointer`
+        *z.pointer += 1;
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr
new file mode 100644
index 00000000000..0b21d113f74
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr
@@ -0,0 +1,26 @@
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
+  --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9
+   |
+LL |         let z = copy_borrowed_ptr(&mut y);
+   |                                   ------ borrow of `y` occurs here
+LL |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ use of borrowed `y`
+...
+LL |         *z.pointer += 1;
+   |         --------------- borrow later used here
+
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed
+  --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9
+   |
+LL |         let z = copy_borrowed_ptr(&mut y);
+   |                                   ------ borrow of `*y.pointer` occurs here
+LL |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+...
+LL |         *z.pointer += 1;
+   |         --------------- borrow later used here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0503, E0506.
+For more information about an error, try `rustc --explain E0503`.
diff --git a/tests/ui/borrowck/borrowck-assign-to-constants.rs b/tests/ui/borrowck/borrowck-assign-to-constants.rs
new file mode 100644
index 00000000000..5881dccf61a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-to-constants.rs
@@ -0,0 +1,6 @@
+static foo: isize = 5;
+
+fn main() {
+    // assigning to various global constants
+    foo = 6; //~ ERROR cannot assign to immutable static item `foo`
+}
diff --git a/tests/ui/borrowck/borrowck-assign-to-constants.stderr b/tests/ui/borrowck/borrowck-assign-to-constants.stderr
new file mode 100644
index 00000000000..864d933da12
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-to-constants.stderr
@@ -0,0 +1,9 @@
+error[E0594]: cannot assign to immutable static item `foo`
+  --> $DIR/borrowck-assign-to-constants.rs:5:5
+   |
+LL |     foo = 6;
+   |     ^^^^^^^ cannot assign
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/borrowck-assign-to-subfield.rs b/tests/ui/borrowck/borrowck-assign-to-subfield.rs
new file mode 100644
index 00000000000..050d702b625
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assign-to-subfield.rs
@@ -0,0 +1,23 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+pub fn main() {
+    struct A {
+        a: isize,
+        w: B,
+    }
+    struct B {
+        a: isize
+    }
+    let mut p = A {
+        a: 1,
+        w: B {a: 1},
+    };
+
+    // even though `x` is not declared as a mutable field,
+    // `p` as a whole is mutable, so it can be modified.
+    p.a = 2;
+
+    // this is true for an interior field too
+    p.w.a = 2;
+}
diff --git a/tests/ui/borrowck/borrowck-assignment-to-static-mut.rs b/tests/ui/borrowck/borrowck-assignment-to-static-mut.rs
new file mode 100644
index 00000000000..72bf43da95e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-assignment-to-static-mut.rs
@@ -0,0 +1,11 @@
+// run-pass
+#![allow(dead_code)]
+// Test taken from #45641 (https://github.com/rust-lang/rust/issues/45641)
+
+static mut Y: u32 = 0;
+
+unsafe fn should_ok() {
+    Y = 1;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.rs b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.rs
new file mode 100644
index 00000000000..247e3da186b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.rs
@@ -0,0 +1,16 @@
+// Tests that auto-ref can't create mutable aliases to immutable memory.
+
+struct Foo {
+    x: isize
+}
+
+impl Foo {
+    pub fn printme(&mut self) {
+        println!("{}", self.x);
+    }
+}
+
+fn main() {
+    let x = Foo { x: 3 };
+    x.printme();    //~ ERROR cannot borrow
+}
diff --git a/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr
new file mode 100644
index 00000000000..19ef0301a2d
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5
+   |
+LL |     x.printme();
+   |     ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = Foo { x: 3 };
+   |         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrowck-autoref-3261.rs b/tests/ui/borrowck/borrowck-autoref-3261.rs
new file mode 100644
index 00000000000..2ff3d5bd3db
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-autoref-3261.rs
@@ -0,0 +1,24 @@
+enum Either<T, U> { Left(T), Right(U) }
+
+struct X(Either<(usize,usize), fn()>);
+
+impl X {
+    pub fn with<F>(&self, blk: F) where F: FnOnce(&Either<(usize, usize), fn()>) {
+        let X(ref e) = *self;
+        blk(e)
+    }
+}
+
+fn main() {
+    let mut x = X(Either::Right(main as fn()));
+    (&mut x).with(
+        |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time
+            match opt {
+                &Either::Right(ref f) => {
+                    x = X(Either::Left((0, 0)));
+                    (*f)()
+                },
+                _ => panic!()
+            }
+        })
+}
diff --git a/tests/ui/borrowck/borrowck-autoref-3261.stderr b/tests/ui/borrowck/borrowck-autoref-3261.stderr
new file mode 100644
index 00000000000..c2dfb687e8e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-autoref-3261.stderr
@@ -0,0 +1,16 @@
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-autoref-3261.rs:15:9
+   |
+LL |     (&mut x).with(
+   |     -------- ---- first borrow later used by call
+   |     |
+   |     first mutable borrow occurs here
+LL |         |opt| {
+   |         ^^^^^ second mutable borrow occurs here
+...
+LL |                     x = X(Either::Left((0, 0)));
+   |                     - second borrow occurs due to use of `x` in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-free.rs b/tests/ui/borrowck/borrowck-bad-nested-calls-free.rs
new file mode 100644
index 00000000000..b0bb9a0351b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-bad-nested-calls-free.rs
@@ -0,0 +1,35 @@
+// Test that we detect nested calls that could free pointers evaluated
+// for earlier arguments.
+
+
+
+fn rewrite(v: &mut Box<usize>) -> usize {
+    *v = Box::new(22);
+    **v
+}
+
+fn add(v: &usize, w: usize) -> usize {
+    *v + w
+}
+
+fn implicit() {
+    let mut a: Box<_> = Box::new(1);
+
+    // Note the danger here:
+    //
+    //    the pointer for the first argument has already been
+    //    evaluated, but it gets freed when evaluating the second
+    //    argument!
+    add(
+        &*a,
+        rewrite(&mut a)); //~ ERROR cannot borrow
+}
+
+fn explicit() {
+    let mut a: Box<_> = Box::new(1);
+    add(
+        &*a,
+        rewrite(&mut a)); //~ ERROR cannot borrow
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-free.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-free.stderr
new file mode 100644
index 00000000000..e273a778fda
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-bad-nested-calls-free.stderr
@@ -0,0 +1,23 @@
+error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-bad-nested-calls-free.rs:25:17
+   |
+LL |     add(
+   |     --- immutable borrow later used by call
+LL |         &*a,
+   |         --- immutable borrow occurs here
+LL |         rewrite(&mut a));
+   |                 ^^^^^^ mutable borrow occurs here
+
+error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-bad-nested-calls-free.rs:32:17
+   |
+LL |     add(
+   |     --- immutable borrow later used by call
+LL |         &*a,
+   |         --- immutable borrow occurs here
+LL |         rewrite(&mut a));
+   |                 ^^^^^^ mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.rs b/tests/ui/borrowck/borrowck-bad-nested-calls-move.rs
new file mode 100644
index 00000000000..b2afb6391c1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.rs
@@ -0,0 +1,35 @@
+// Test that we detect nested calls that could free pointers evaluated
+// for earlier arguments.
+
+
+
+fn rewrite(v: &mut Box<usize>) -> usize {
+    *v = Box::new(22);
+    **v
+}
+
+fn add(v: &usize, w: Box<usize>) -> usize {
+    *v + *w
+}
+
+fn implicit() {
+    let mut a: Box<_> = Box::new(1);
+
+    // Note the danger here:
+    //
+    //    the pointer for the first argument has already been
+    //    evaluated, but it gets moved when evaluating the second
+    //    argument!
+    add(
+        &*a,
+        a); //~ ERROR cannot move
+}
+
+fn explicit() {
+    let mut a: Box<_> = Box::new(1);
+    add(
+        &*a,
+        a); //~ ERROR cannot move
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
new file mode 100644
index 00000000000..371bcf2b69c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
@@ -0,0 +1,23 @@
+error[E0505]: cannot move out of `a` because it is borrowed
+  --> $DIR/borrowck-bad-nested-calls-move.rs:25:9
+   |
+LL |     add(
+   |     --- borrow later used by call
+LL |         &*a,
+   |         --- borrow of `*a` occurs here
+LL |         a);
+   |         ^ move out of `a` occurs here
+
+error[E0505]: cannot move out of `a` because it is borrowed
+  --> $DIR/borrowck-bad-nested-calls-move.rs:32:9
+   |
+LL |     add(
+   |     --- borrow later used by call
+LL |         &*a,
+   |         --- borrow of `*a` occurs here
+LL |         a);
+   |         ^ move out of `a` occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-binding-mutbl.rs b/tests/ui/borrowck/borrowck-binding-mutbl.rs
new file mode 100644
index 00000000000..c2d2e02ec15
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-binding-mutbl.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+struct F { f: Vec<isize> }
+
+fn impure(_v: &[isize]) {
+}
+
+pub fn main() {
+    let mut x = F {f: vec![3]};
+
+    match x {
+      F {f: ref mut v} => {
+        impure(v);
+      }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-block-unint.rs b/tests/ui/borrowck/borrowck-block-unint.rs
new file mode 100644
index 00000000000..8d13b25a357
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-block-unint.rs
@@ -0,0 +1,7 @@
+fn force<F>(f: F) where F: FnOnce() { f(); }
+fn main() {
+    let x: isize;
+    force(|| {  //~ ERROR E0381
+        println!("{}", x);
+    });
+}
diff --git a/tests/ui/borrowck/borrowck-block-unint.stderr b/tests/ui/borrowck/borrowck-block-unint.stderr
new file mode 100644
index 00000000000..f47921a9752
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-block-unint.stderr
@@ -0,0 +1,18 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-block-unint.rs:4:11
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     force(|| {
+   |           ^^ `x` used here but it isn't initialized
+LL |         println!("{}", x);
+   |                        - borrow occurs due to use in closure
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-borrow-from-expr-block.rs b/tests/ui/borrowck/borrowck-borrow-from-expr-block.rs
new file mode 100644
index 00000000000..24efadc3055
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-from-expr-block.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+fn borrow<F>(x: &isize, f: F) where F: FnOnce(&isize) {
+    f(x)
+}
+
+fn test1(x: &Box<isize>) {
+    borrow(&*(*x).clone(), |p| {
+        let x_a = &**x as *const isize;
+        assert!((x_a as usize) != (p as *const isize as usize));
+        assert_eq!(unsafe{*x_a}, *p);
+    })
+}
+
+pub fn main() {
+    test1(&Box::new(22));
+}
diff --git a/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.rs b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.rs
new file mode 100644
index 00000000000..353e4e9f75e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.rs
@@ -0,0 +1,134 @@
+#[derive(Copy, Clone)]
+struct Foo {
+  bar1: Bar,
+  bar2: Bar
+}
+
+#[derive(Copy, Clone)]
+struct Bar {
+  int1: isize,
+  int2: isize,
+}
+
+fn make_foo() -> Box<Foo> { panic!() }
+
+fn borrow_same_field_twice_mut_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _bar2 = &mut foo.bar1;  //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_same_field_twice_mut_imm() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _bar2 = &foo.bar1;  //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_same_field_twice_imm_mut() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1;
+    let _bar2 = &mut foo.bar1;  //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_same_field_twice_imm_imm() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1;
+    let _bar2 = &foo.bar1;
+    *bar1;
+}
+
+fn borrow_both_fields_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _bar2 = &mut foo.bar2;
+    *bar1;
+}
+
+fn borrow_both_mut_pattern() {
+    let mut foo = make_foo();
+    match *foo {
+        Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {
+            *_bar1;
+            *_bar2;
+        }
+    }
+}
+
+fn borrow_var_and_pattern() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    match *foo {
+        Foo { bar1: ref mut _bar1, bar2: _ } => {}
+        //~^ ERROR cannot borrow
+    }
+    *bar1;
+}
+
+fn borrow_mut_and_base_imm() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let _foo1 = &foo.bar1; //~ ERROR cannot borrow
+    let _foo2 = &*foo; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_mut_and_base_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_mut_and_base_mut2() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let _foo2 = &mut *foo; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_imm_and_base_mut() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1.int1;
+    let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_imm_and_base_mut2() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1.int1;
+    let _foo2 = &mut *foo; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_imm_and_base_imm() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1.int1;
+    let _foo1 = &foo.bar1;
+    let _foo2 = &*foo;
+    *bar1;
+}
+
+fn borrow_mut_and_imm() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _foo1 = &foo.bar2;
+}
+
+fn borrow_mut_from_imm() {
+    let foo = make_foo();
+    let bar1 = &mut foo.bar1; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_long_path_both_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let foo1 = &mut foo.bar2.int2;
+    *bar1;
+    *foo1;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr
new file mode 100644
index 00000000000..c2351aacdae
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr
@@ -0,0 +1,119 @@
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:18:17
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ------------- first mutable borrow occurs here
+LL |     let _bar2 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:25:17
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ------------- mutable borrow occurs here
+LL |     let _bar2 = &foo.bar1;
+   |                 ^^^^^^^^^ immutable borrow occurs here
+LL |     *bar1;
+   |     ----- mutable borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:32:17
+   |
+LL |     let bar1 = &foo.bar1;
+   |                --------- immutable borrow occurs here
+LL |     let _bar2 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     *bar1;
+   |     ----- immutable borrow later used here
+
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:64:21
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ------------- first mutable borrow occurs here
+LL |     match *foo {
+LL |         Foo { bar1: ref mut _bar1, bar2: _ } => {}
+   |                     ^^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:73:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ mutable borrow occurs here
+LL |     let _foo1 = &foo.bar1;
+   |                 ^^^^^^^^^ immutable borrow occurs here
+LL |     let _foo2 = &*foo;
+LL |     *bar1;
+   |     ----- mutable borrow later used here
+
+error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:74:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ mutable borrow occurs here
+LL |     let _foo1 = &foo.bar1;
+LL |     let _foo2 = &*foo;
+   |                 ^^^^^ immutable borrow occurs here
+LL |     *bar1;
+   |     ----- mutable borrow later used here
+
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:81:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ first mutable borrow occurs here
+LL |     let _foo1 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0499]: cannot borrow `*foo` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:88:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ first mutable borrow occurs here
+LL |     let _foo2 = &mut *foo;
+   |                 ^^^^^^^^^ second mutable borrow occurs here
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:95:17
+   |
+LL |     let bar1 = &foo.bar1.int1;
+   |                -------------- immutable borrow occurs here
+LL |     let _foo1 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     *bar1;
+   |     ----- immutable borrow later used here
+
+error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:102:17
+   |
+LL |     let bar1 = &foo.bar1.int1;
+   |                -------------- immutable borrow occurs here
+LL |     let _foo2 = &mut *foo;
+   |                 ^^^^^^^^^ mutable borrow occurs here
+LL |     *bar1;
+   |     ----- immutable borrow later used here
+
+error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
+  --> $DIR/borrowck-borrow-from-owned-ptr.rs:122:16
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = make_foo();
+   |         +++
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0596.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-borrow-from-stack-variable.rs b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.rs
new file mode 100644
index 00000000000..231f6beab85
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.rs
@@ -0,0 +1,131 @@
+#[derive(Copy, Clone)]
+struct Foo {
+  bar1: Bar,
+  bar2: Bar
+}
+
+#[derive(Copy, Clone)]
+struct Bar {
+  int1: isize,
+  int2: isize,
+}
+
+fn make_foo() -> Foo { panic!() }
+
+fn borrow_same_field_twice_mut_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _bar2 = &mut foo.bar1;  //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_same_field_twice_mut_imm() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _bar2 = &foo.bar1;  //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_same_field_twice_imm_mut() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1;
+    let _bar2 = &mut foo.bar1;  //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_same_field_twice_imm_imm() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1;
+    let _bar2 = &foo.bar1;
+    *bar1;
+}
+
+fn borrow_both_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _bar2 = &mut foo.bar2;
+    *bar1;
+}
+
+fn borrow_both_mut_pattern() {
+    let mut foo = make_foo();
+    match foo {
+        Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {}
+    }
+}
+
+fn borrow_var_and_pattern() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    match foo {
+        Foo { bar1: ref mut _bar1, bar2: _ } => {} //
+        //~^ ERROR cannot borrow
+    }
+    *bar1;
+}
+
+fn borrow_mut_and_base_imm() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let _foo1 = &foo.bar1; //~ ERROR cannot borrow
+    let _foo2 = &foo; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_mut_and_base_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_mut_and_base_mut2() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let _foo2 = &mut foo; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_imm_and_base_mut() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1.int1;
+    let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_imm_and_base_mut2() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1.int1;
+    let _foo2 = &mut foo; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_imm_and_base_imm() {
+    let mut foo = make_foo();
+    let bar1 = &foo.bar1.int1;
+    let _foo1 = &foo.bar1;
+    let _foo2 = &foo;
+    *bar1;
+}
+
+fn borrow_mut_and_imm() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1;
+    let _foo1 = &foo.bar2;
+    *bar1;
+}
+
+fn borrow_mut_from_imm() {
+    let foo = make_foo();
+    let bar1 = &mut foo.bar1; //~ ERROR cannot borrow
+    *bar1;
+}
+
+fn borrow_long_path_both_mut() {
+    let mut foo = make_foo();
+    let bar1 = &mut foo.bar1.int1;
+    let _foo1 = &mut foo.bar2.int2;
+    *bar1;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-borrow-from-stack-variable.stderr b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.stderr
new file mode 100644
index 00000000000..8fcaaa883b2
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.stderr
@@ -0,0 +1,119 @@
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:18:17
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ------------- first mutable borrow occurs here
+LL |     let _bar2 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:25:17
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ------------- mutable borrow occurs here
+LL |     let _bar2 = &foo.bar1;
+   |                 ^^^^^^^^^ immutable borrow occurs here
+LL |     *bar1;
+   |     ----- mutable borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:32:17
+   |
+LL |     let bar1 = &foo.bar1;
+   |                --------- immutable borrow occurs here
+LL |     let _bar2 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     *bar1;
+   |     ----- immutable borrow later used here
+
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:61:21
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ------------- first mutable borrow occurs here
+LL |     match foo {
+LL |         Foo { bar1: ref mut _bar1, bar2: _ } => {} //
+   |                     ^^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:70:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ mutable borrow occurs here
+LL |     let _foo1 = &foo.bar1;
+   |                 ^^^^^^^^^ immutable borrow occurs here
+LL |     let _foo2 = &foo;
+LL |     *bar1;
+   |     ----- mutable borrow later used here
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:71:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ mutable borrow occurs here
+LL |     let _foo1 = &foo.bar1;
+LL |     let _foo2 = &foo;
+   |                 ^^^^ immutable borrow occurs here
+LL |     *bar1;
+   |     ----- mutable borrow later used here
+
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:78:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ first mutable borrow occurs here
+LL |     let _foo1 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:85:17
+   |
+LL |     let bar1 = &mut foo.bar1.int1;
+   |                ------------------ first mutable borrow occurs here
+LL |     let _foo2 = &mut foo;
+   |                 ^^^^^^^^ second mutable borrow occurs here
+LL |     *bar1;
+   |     ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:92:17
+   |
+LL |     let bar1 = &foo.bar1.int1;
+   |                -------------- immutable borrow occurs here
+LL |     let _foo1 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     *bar1;
+   |     ----- immutable borrow later used here
+
+error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:99:17
+   |
+LL |     let bar1 = &foo.bar1.int1;
+   |                -------------- immutable borrow occurs here
+LL |     let _foo2 = &mut foo;
+   |                 ^^^^^^^^ mutable borrow occurs here
+LL |     *bar1;
+   |     ----- immutable borrow later used here
+
+error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
+  --> $DIR/borrowck-borrow-from-stack-variable.rs:120:16
+   |
+LL |     let bar1 = &mut foo.bar1;
+   |                ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = make_foo();
+   |         +++
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0596.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-borrow-from-temporary.rs b/tests/ui/borrowck/borrowck-borrow-from-temporary.rs
new file mode 100644
index 00000000000..92f3ffd57a1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-from-temporary.rs
@@ -0,0 +1,14 @@
+// Test lifetimes are linked properly when we take reference
+// to interior.
+
+fn id<T>(x: T) -> T { x }
+
+struct Foo(isize);
+
+fn foo<'a>() -> &'a isize {
+    let &Foo(ref x) = &id(Foo(3));
+    x //~ ERROR cannot return value referencing temporary value
+}
+
+pub fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-borrow-from-temporary.stderr b/tests/ui/borrowck/borrowck-borrow-from-temporary.stderr
new file mode 100644
index 00000000000..71bf052c93d
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-from-temporary.stderr
@@ -0,0 +1,11 @@
+error[E0515]: cannot return value referencing temporary value
+  --> $DIR/borrowck-borrow-from-temporary.rs:10:5
+   |
+LL |     let &Foo(ref x) = &id(Foo(3));
+   |                        ---------- temporary value created here
+LL |     x
+   |     ^ returns a value referencing data owned by the current function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs
new file mode 100644
index 00000000000..6b5544a8a39
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs
@@ -0,0 +1,14 @@
+struct A;
+
+impl A {
+    fn foo(&mut self) {
+    }
+}
+
+
+
+pub fn main() {
+    let a: Box<_> = Box::new(A);
+    a.foo();
+    //~^ ERROR cannot borrow `*a` as mutable, as `a` is not declared as mutable [E0596]
+}
diff --git a/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr
new file mode 100644
index 00000000000..3c28ff56e41
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable
+  --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5
+   |
+LL |     a.foo();
+   |     ^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut a: Box<_> = Box::new(A);
+   |         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
new file mode 100644
index 00000000000..7a88c3df2e4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
@@ -0,0 +1,24 @@
+// Test that attempt to reborrow an `&mut` pointer in an aliasable
+// location yields an error.
+//
+// Example from compiler/rustc_borrowck/borrowck/README.md
+
+fn foo(t0: & &mut isize) {
+    let t1 = t0;
+    let p: &isize = &**t0;
+    **t1 = 22; //~ ERROR cannot assign
+}
+
+fn foo3(t0: &mut &mut isize) {
+    let t1 = &mut *t0;
+    let p: &isize = &**t0; //~ ERROR cannot borrow
+    **t1 = 22;
+}
+
+fn foo4(t0: & &mut isize) {
+    let x:  &mut isize = &mut **t0; //~ ERROR cannot borrow
+    *x += 1;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr
new file mode 100644
index 00000000000..ce9f7aa050a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr
@@ -0,0 +1,34 @@
+error[E0594]: cannot assign to `**t1`, which is behind a `&` reference
+  --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:9:5
+   |
+LL |     let t1 = t0;
+   |         -- consider changing this binding's type to be: `&mut &mut isize`
+LL |     let p: &isize = &**t0;
+LL |     **t1 = 22;
+   |     ^^^^^^^^^ `t1` is a `&` reference, so the data it refers to cannot be written
+
+error[E0502]: cannot borrow `**t0` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:14:21
+   |
+LL |     let t1 = &mut *t0;
+   |              -------- mutable borrow occurs here
+LL |     let p: &isize = &**t0;
+   |                     ^^^^^ immutable borrow occurs here
+LL |     **t1 = 22;
+   |     --------- mutable borrow later used here
+
+error[E0596]: cannot borrow `**t0` as mutable, as it is behind a `&` reference
+  --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:19:26
+   |
+LL |     let x:  &mut isize = &mut **t0;
+   |                          ^^^^^^^^^ `t0` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn foo4(t0: &mut &mut isize) {
+   |             ~~~~~~~~~~~~~~~
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0502, E0594, E0596.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-borrow-mut-object-twice.rs b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.rs
new file mode 100644
index 00000000000..b4d85b60cd5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.rs
@@ -0,0 +1,20 @@
+// Check that `&mut` objects cannot be borrowed twice, just like
+// other `&mut` pointers.
+
+
+
+trait Foo {
+    fn f1(&mut self) -> &();
+    fn f2(&mut self);
+}
+
+fn test(x: &mut dyn Foo) {
+    let y = x.f1();
+    x.f2(); //~ ERROR cannot borrow `*x` as mutable
+    y.use_ref();
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-borrow-mut-object-twice.stderr b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.stderr
new file mode 100644
index 00000000000..42b6c34cd2f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.stderr
@@ -0,0 +1,13 @@
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-mut-object-twice.rs:13:5
+   |
+LL |     let y = x.f1();
+   |             ------ first mutable borrow occurs here
+LL |     x.f2();
+   |     ^^^^^^ second mutable borrow occurs here
+LL |     y.use_ref();
+   |     ----------- first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs b/tests/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs
new file mode 100644
index 00000000000..5ef282c0ca0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs
@@ -0,0 +1,21 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_mut)]
+#![allow(unused_variables)]
+// Test that freezing an `&mut` pointer while referent is
+// frozen is legal.
+//
+// Example from compiler/rustc_borrowck/borrowck/README.md
+
+// pretty-expanded FIXME #23616
+
+fn foo<'a>(mut t0: &'a mut isize,
+           mut t1: &'a mut isize) {
+    let p: &isize = &*t0; // Freezes `*t0`
+    let mut t2 = &t0;
+    let q: &isize = &**t2; // Freezes `*t0`, but that's ok...
+    let r: &isize = &*t0; // ...after all, could do same thing directly.
+}
+
+pub fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs
new file mode 100644
index 00000000000..83eab7fdeab
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs
@@ -0,0 +1,103 @@
+// Test how overloaded deref interacts with borrows when only
+// Deref and not DerefMut is implemented.
+
+use std::ops::Deref;
+use std::rc::Rc;
+
+struct Point {
+    x: isize,
+    y: isize
+}
+
+impl Point {
+    fn get(&self) -> (isize, isize) {
+        (self.x, self.y)
+    }
+
+    fn set(&mut self, x: isize, y: isize) {
+        self.x = x;
+        self.y = y;
+    }
+
+    fn x_ref(&self) -> &isize {
+        &self.x
+    }
+
+    fn y_mut(&mut self) -> &mut isize {
+        &mut self.y
+    }
+}
+
+fn deref_imm_field(x: Rc<Point>) {
+    let __isize = &x.y;
+}
+
+fn deref_mut_field1(x: Rc<Point>) {
+    let __isize = &mut x.y; //~ ERROR cannot borrow
+}
+
+fn deref_mut_field2(mut x: Rc<Point>) {
+    let __isize = &mut x.y; //~ ERROR cannot borrow
+}
+
+fn deref_extend_field(x: &Rc<Point>) -> &isize {
+    &x.y
+}
+
+fn deref_extend_mut_field1(x: &Rc<Point>) -> &mut isize {
+    &mut x.y //~ ERROR cannot borrow
+}
+
+fn deref_extend_mut_field2(x: &mut Rc<Point>) -> &mut isize {
+    &mut x.y //~ ERROR cannot borrow
+}
+
+fn assign_field1<'a>(x: Rc<Point>) {
+    x.y = 3; //~ ERROR cannot assign
+}
+
+fn assign_field2<'a>(x: &'a Rc<Point>) {
+    x.y = 3; //~ ERROR cannot assign
+}
+
+fn assign_field3<'a>(x: &'a mut Rc<Point>) {
+    x.y = 3; //~ ERROR cannot assign
+}
+
+fn deref_imm_method(x: Rc<Point>) {
+    let __isize = x.get();
+}
+
+fn deref_mut_method1(x: Rc<Point>) {
+    x.set(0, 0); //~ ERROR cannot borrow
+}
+
+fn deref_mut_method2(mut x: Rc<Point>) {
+    x.set(0, 0); //~ ERROR cannot borrow
+}
+
+fn deref_extend_method(x: &Rc<Point>) -> &isize {
+    x.x_ref()
+}
+
+fn deref_extend_mut_method1(x: &Rc<Point>) -> &mut isize {
+    x.y_mut() //~ ERROR cannot borrow
+}
+
+fn deref_extend_mut_method2(x: &mut Rc<Point>) -> &mut isize {
+    x.y_mut() //~ ERROR cannot borrow
+}
+
+fn assign_method1<'a>(x: Rc<Point>) {
+    *x.y_mut() = 3; //~ ERROR cannot borrow
+}
+
+fn assign_method2<'a>(x: &'a Rc<Point>) {
+    *x.y_mut() = 3; //~ ERROR cannot borrow
+}
+
+fn assign_method3<'a>(x: &'a mut Rc<Point>) {
+    *x.y_mut() = 3; //~ ERROR cannot borrow
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr
new file mode 100644
index 00000000000..fdf6568d839
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr
@@ -0,0 +1,116 @@
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:36:19
+   |
+LL |     let __isize = &mut x.y;
+   |                   ^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:40:19
+   |
+LL |     let __isize = &mut x.y;
+   |                   ^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:48:5
+   |
+LL |     &mut x.y
+   |     ^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:52:5
+   |
+LL |     &mut x.y
+   |     ^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0594]: cannot assign to data in an `Rc`
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:56:5
+   |
+LL |     x.y = 3;
+   |     ^^^^^^^ cannot assign
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0594]: cannot assign to data in an `Rc`
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:60:5
+   |
+LL |     x.y = 3;
+   |     ^^^^^^^ cannot assign
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0594]: cannot assign to data in an `Rc`
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:64:5
+   |
+LL |     x.y = 3;
+   |     ^^^^^^^ cannot assign
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:72:5
+   |
+LL |     x.set(0, 0);
+   |     ^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:76:5
+   |
+LL |     x.set(0, 0);
+   |     ^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:84:5
+   |
+LL |     x.y_mut()
+   |     ^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:88:5
+   |
+LL |     x.y_mut()
+   |     ^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:92:6
+   |
+LL |     *x.y_mut() = 3;
+   |      ^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:96:6
+   |
+LL |     *x.y_mut() = 3;
+   |      ^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:100:6
+   |
+LL |     *x.y_mut() = 3;
+   |      ^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>`
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-deref.rs b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.rs
new file mode 100644
index 00000000000..2b98a7b9483
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.rs
@@ -0,0 +1,43 @@
+// Test how overloaded deref interacts with borrows when only
+// Deref and not DerefMut is implemented.
+
+use std::ops::Deref;
+use std::rc::Rc;
+
+fn deref_imm(x: Rc<isize>) {
+    let __isize = &*x;
+}
+
+fn deref_mut1(x: Rc<isize>) {
+    let __isize = &mut *x; //~ ERROR cannot borrow
+}
+
+fn deref_mut2(mut x: Rc<isize>) {
+    let __isize = &mut *x; //~ ERROR cannot borrow
+}
+
+fn deref_extend<'a>(x: &'a Rc<isize>) -> &'a isize {
+    &**x
+}
+
+fn deref_extend_mut1<'a>(x: &'a Rc<isize>) -> &'a mut isize {
+    &mut **x //~ ERROR cannot borrow
+}
+
+fn deref_extend_mut2<'a>(x: &'a mut Rc<isize>) -> &'a mut isize {
+    &mut **x //~ ERROR cannot borrow
+}
+
+fn assign1<'a>(x: Rc<isize>) {
+    *x = 3; //~ ERROR cannot assign
+}
+
+fn assign2<'a>(x: &'a Rc<isize>) {
+    **x = 3; //~ ERROR cannot assign
+}
+
+fn assign3<'a>(x: &'a mut Rc<isize>) {
+    **x = 3; //~ ERROR cannot assign
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.stderr
new file mode 100644
index 00000000000..9ed9d292493
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.stderr
@@ -0,0 +1,60 @@
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref.rs:12:19
+   |
+LL |     let __isize = &mut *x;
+   |                   ^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref.rs:16:19
+   |
+LL |     let __isize = &mut *x;
+   |                   ^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref.rs:24:5
+   |
+LL |     &mut **x
+   |     ^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>`
+
+error[E0596]: cannot borrow data in an `Rc` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref.rs:28:5
+   |
+LL |     &mut **x
+   |     ^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>`
+
+error[E0594]: cannot assign to data in an `Rc`
+  --> $DIR/borrowck-borrow-overloaded-deref.rs:32:5
+   |
+LL |     *x = 3;
+   |     ^^^^^^ cannot assign
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>`
+
+error[E0594]: cannot assign to data in an `Rc`
+  --> $DIR/borrowck-borrow-overloaded-deref.rs:36:5
+   |
+LL |     **x = 3;
+   |     ^^^^^^^ cannot assign
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>`
+
+error[E0594]: cannot assign to data in an `Rc`
+  --> $DIR/borrowck-borrow-overloaded-deref.rs:40:5
+   |
+LL |     **x = 3;
+   |     ^^^^^^^ cannot assign
+   |
+   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>`
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs
new file mode 100644
index 00000000000..e384aacb718
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs
@@ -0,0 +1,22 @@
+struct Defer<'a> {
+    x: &'a [&'a str],
+}
+
+impl<'a> Drop for Defer<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            println!("{:?}", self.x);
+        }
+    }
+}
+
+fn defer<'r>(x: &'r [&'r str]) -> Defer<'r> {
+    Defer {
+        x: x
+    }
+}
+
+fn main() {
+    let x = defer(&vec!["Goodbye", "world!"]); //~ ERROR temporary value dropped while borrowed
+    x.x[0];
+}
diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr
new file mode 100644
index 00000000000..4eeec09b910
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr
@@ -0,0 +1,16 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/borrowck-borrowed-uniq-rvalue-2.rs:20:20
+   |
+LL |     let x = defer(&vec!["Goodbye", "world!"]);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
+   |                    |
+   |                    creates a temporary value which is freed while still in use
+LL |     x.x[0];
+   |     ------ borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed
new file mode 100644
index 00000000000..8bf6a2f6db3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+
+use std::collections::HashMap;
+
+fn main() {
+    let tmp: Box<_>;
+    let mut buggy_map: HashMap<usize, &usize> = HashMap::new();
+    let binding = Box::new(1);
+    buggy_map.insert(42, &*binding); //~ ERROR temporary value dropped while borrowed
+
+    // but it is ok if we use a temporary
+    tmp = Box::new(2);
+    buggy_map.insert(43, &*tmp);
+}
diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs
new file mode 100644
index 00000000000..85481336a30
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs
@@ -0,0 +1,13 @@
+// run-rustfix
+
+use std::collections::HashMap;
+
+fn main() {
+    let tmp: Box<_>;
+    let mut buggy_map: HashMap<usize, &usize> = HashMap::new();
+    buggy_map.insert(42, &*Box::new(1)); //~ ERROR temporary value dropped while borrowed
+
+    // but it is ok if we use a temporary
+    tmp = Box::new(2);
+    buggy_map.insert(43, &*tmp);
+}
diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr
new file mode 100644
index 00000000000..c62d5f903c8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr
@@ -0,0 +1,20 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/borrowck-borrowed-uniq-rvalue.rs:8:28
+   |
+LL |     buggy_map.insert(42, &*Box::new(1));
+   |                            ^^^^^^^^^^^ - temporary value is freed at the end of this statement
+   |                            |
+   |                            creates a temporary value which is freed while still in use
+...
+LL |     buggy_map.insert(43, &*tmp);
+   |     --------------------------- borrow later used here
+   |
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~     let binding = Box::new(1);
+LL ~     buggy_map.insert(42, &*binding);
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/borrowck/borrowck-box-sensitivity.rs b/tests/ui/borrowck/borrowck-box-sensitivity.rs
new file mode 100644
index 00000000000..e880f876f91
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-box-sensitivity.rs
@@ -0,0 +1,148 @@
+// Test that `Box<T>` is treated specially by borrow checking. This is the case
+// because NLL reverted the deicision in rust-lang/rfcs#130.
+
+// run-pass
+
+struct A {
+    x: Box<isize>,
+    y: isize,
+}
+
+struct B {
+    x: Box<isize>,
+    y: Box<isize>,
+}
+
+struct C {
+    x: Box<A>,
+    y: isize,
+}
+
+struct D {
+    x: Box<A>,
+    y: Box<isize>,
+}
+
+fn copy_after_move() {
+    let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
+    let _x = a.x;
+    let _y = a.y;
+}
+
+fn move_after_move() {
+    let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
+    let _x = a.x;
+    let _y = a.y;
+}
+
+fn borrow_after_move() {
+    let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
+    let _x = a.x;
+    let _y = &a.y;
+}
+
+fn move_after_borrow() {
+    let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
+    let _x = &a.x;
+    let _y = a.y;
+    use_imm(_x);
+}
+fn copy_after_mut_borrow() {
+    let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
+    let _x = &mut a.x;
+    let _y = a.y;
+    use_mut(_x);
+}
+fn move_after_mut_borrow() {
+    let mut a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
+    let _x = &mut a.x;
+    let _y = a.y;
+    use_mut(_x);
+}
+fn borrow_after_mut_borrow() {
+    let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
+    let _x = &mut a.x;
+    let _y = &a.y;
+    use_mut(_x);
+}
+fn mut_borrow_after_borrow() {
+    let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
+    let _x = &a.x;
+    let _y = &mut a.y;
+    use_imm(_x);
+}
+fn copy_after_move_nested() {
+    let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
+    let _x = a.x.x;
+    let _y = a.y;
+}
+
+fn move_after_move_nested() {
+    let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
+    let _x = a.x.x;
+    let _y = a.y;
+}
+
+fn borrow_after_move_nested() {
+    let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
+    let _x = a.x.x;
+    let _y = &a.y;
+}
+
+fn move_after_borrow_nested() {
+    let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
+    let _x = &a.x.x;
+    let _y = a.y;
+    use_imm(_x);
+}
+fn copy_after_mut_borrow_nested() {
+    let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
+    let _x = &mut a.x.x;
+    let _y = a.y;
+    use_mut(_x);
+}
+fn move_after_mut_borrow_nested() {
+    let mut a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
+    let _x = &mut a.x.x;
+    let _y = a.y;
+    use_mut(_x);
+}
+fn borrow_after_mut_borrow_nested() {
+    let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
+    let _x = &mut a.x.x;
+    let _y = &a.y;
+    use_mut(_x);
+}
+fn mut_borrow_after_borrow_nested() {
+    let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
+    let _x = &a.x.x;
+    let _y = &mut a.y;
+    use_imm(_x);
+}
+
+fn main() {
+    copy_after_move();
+    move_after_move();
+    borrow_after_move();
+
+    move_after_borrow();
+
+    copy_after_mut_borrow();
+    move_after_mut_borrow();
+    borrow_after_mut_borrow();
+    mut_borrow_after_borrow();
+
+    copy_after_move_nested();
+    move_after_move_nested();
+    borrow_after_move_nested();
+
+    move_after_borrow_nested();
+
+    copy_after_mut_borrow_nested();
+    move_after_mut_borrow_nested();
+    borrow_after_mut_borrow_nested();
+    mut_borrow_after_borrow_nested();
+}
+
+fn use_mut<T>(_: &mut T) { }
+fn use_imm<T>(_: &T) { }
diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.rs b/tests/ui/borrowck/borrowck-break-uninit-2.rs
new file mode 100644
index 00000000000..3abca33a84a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-break-uninit-2.rs
@@ -0,0 +1,14 @@
+fn foo() -> isize {
+    let x: isize;
+
+    while 1 != 2  {
+        break;
+        x = 0;
+    }
+
+    println!("{}", x); //~ ERROR E0381
+
+    return 17;
+}
+
+fn main() { println!("{}", foo()); }
diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.stderr b/tests/ui/borrowck/borrowck-break-uninit-2.stderr
new file mode 100644
index 00000000000..ea93a8f409c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-break-uninit-2.stderr
@@ -0,0 +1,18 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-break-uninit-2.rs:9:20
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+...
+LL |     println!("{}", x);
+   |                    ^ `x` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-break-uninit.rs b/tests/ui/borrowck/borrowck-break-uninit.rs
new file mode 100644
index 00000000000..824f91dbc62
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-break-uninit.rs
@@ -0,0 +1,14 @@
+fn foo() -> isize {
+    let x: isize;
+
+    loop {
+        break;
+        x = 0;
+    }
+
+    println!("{}", x); //~ ERROR E0381
+
+    return 17;
+}
+
+fn main() { println!("{}", foo()); }
diff --git a/tests/ui/borrowck/borrowck-break-uninit.stderr b/tests/ui/borrowck/borrowck-break-uninit.stderr
new file mode 100644
index 00000000000..a7a8fc2ff83
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-break-uninit.stderr
@@ -0,0 +1,18 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-break-uninit.rs:9:20
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+...
+LL |     println!("{}", x);
+   |                    ^ `x` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-closures-mut-and-imm.rs b/tests/ui/borrowck/borrowck-closures-mut-and-imm.rs
new file mode 100644
index 00000000000..a8225f2faf1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-mut-and-imm.rs
@@ -0,0 +1,87 @@
+// Tests that two closures cannot simultaneously have mutable
+// and immutable access to the variable. Issue #6801.
+
+fn get(x: &isize) -> isize {
+    *x
+}
+
+fn set(x: &mut isize) {
+    *x = 4;
+}
+
+
+
+fn a() {
+    let mut x = 3;
+    let c1 = || x = 4;
+    let c2 = || x * 5;
+    //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+    drop(c1);
+}
+
+fn b() {
+    let mut x = 3;
+    let c1 = || set(&mut x);
+    let c2 = || get(&x);
+    //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+    drop(c1);
+}
+
+fn c() {
+    let mut x = 3;
+    let c1 = || set(&mut x);
+    let c2 = || x * 5;
+    //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+    drop(c1);
+}
+
+fn d() {
+    let mut x = 3;
+    let c2 = || x * 5;
+    x = 5;
+    //~^ ERROR cannot assign to `x` because it is borrowed
+    drop(c2);
+}
+
+fn e() {
+    let mut x = 3;
+    let c1 = || get(&x);
+    x = 5;
+    //~^ ERROR cannot assign to `x` because it is borrowed
+    drop(c1);
+}
+
+fn f() {
+    let mut x: Box<_> = Box::new(3);
+    let c1 = || get(&*x);
+    *x = 5;
+    //~^ ERROR cannot assign to `*x` because it is borrowed
+    drop(c1);
+}
+
+fn g() {
+    struct Foo {
+        f: Box<isize>
+    }
+
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
+    let c1 = || get(&*x.f);
+    *x.f = 5;
+    //~^ ERROR cannot assign to `*x.f` because it is borrowed
+    drop(c1);
+}
+
+fn h() {
+    struct Foo {
+        f: Box<isize>
+    }
+
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
+    let c1 = || get(&*x.f);
+    let c2 = || *x.f = 5;
+    //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+    drop(c1);
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr b/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr
new file mode 100644
index 00000000000..fadcd11a592
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr
@@ -0,0 +1,116 @@
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-closures-mut-and-imm.rs:17:14
+   |
+LL |     let c1 = || x = 4;
+   |              -- - first borrow occurs due to use of `x` in closure
+   |              |
+   |              mutable borrow occurs here
+LL |     let c2 = || x * 5;
+   |              ^^ - second borrow occurs due to use of `x` in closure
+   |              |
+   |              immutable borrow occurs here
+LL |
+LL |     drop(c1);
+   |          -- mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-closures-mut-and-imm.rs:25:14
+   |
+LL |     let c1 = || set(&mut x);
+   |              --          - first borrow occurs due to use of `x` in closure
+   |              |
+   |              mutable borrow occurs here
+LL |     let c2 = || get(&x);
+   |              ^^      - second borrow occurs due to use of `x` in closure
+   |              |
+   |              immutable borrow occurs here
+LL |
+LL |     drop(c1);
+   |          -- mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-closures-mut-and-imm.rs:33:14
+   |
+LL |     let c1 = || set(&mut x);
+   |              --          - first borrow occurs due to use of `x` in closure
+   |              |
+   |              mutable borrow occurs here
+LL |     let c2 = || x * 5;
+   |              ^^ - second borrow occurs due to use of `x` in closure
+   |              |
+   |              immutable borrow occurs here
+LL |
+LL |     drop(c1);
+   |          -- mutable borrow later used here
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/borrowck-closures-mut-and-imm.rs:41:5
+   |
+LL |     let c2 = || x * 5;
+   |              -- - borrow occurs due to use in closure
+   |              |
+   |              borrow of `x` occurs here
+LL |     x = 5;
+   |     ^^^^^ assignment to borrowed `x` occurs here
+LL |
+LL |     drop(c2);
+   |          -- borrow later used here
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/borrowck-closures-mut-and-imm.rs:49:5
+   |
+LL |     let c1 = || get(&x);
+   |              --      - borrow occurs due to use in closure
+   |              |
+   |              borrow of `x` occurs here
+LL |     x = 5;
+   |     ^^^^^ assignment to borrowed `x` occurs here
+LL |
+LL |     drop(c1);
+   |          -- borrow later used here
+
+error[E0506]: cannot assign to `*x` because it is borrowed
+  --> $DIR/borrowck-closures-mut-and-imm.rs:57:5
+   |
+LL |     let c1 = || get(&*x);
+   |              --      -- borrow occurs due to use in closure
+   |              |
+   |              borrow of `*x` occurs here
+LL |     *x = 5;
+   |     ^^^^^^ assignment to borrowed `*x` occurs here
+LL |
+LL |     drop(c1);
+   |          -- borrow later used here
+
+error[E0506]: cannot assign to `*x.f` because it is borrowed
+  --> $DIR/borrowck-closures-mut-and-imm.rs:69:5
+   |
+LL |     let c1 = || get(&*x.f);
+   |              --      ---- borrow occurs due to use in closure
+   |              |
+   |              borrow of `*x.f` occurs here
+LL |     *x.f = 5;
+   |     ^^^^^^^^ assignment to borrowed `*x.f` occurs here
+LL |
+LL |     drop(c1);
+   |          -- borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-closures-mut-and-imm.rs:81:14
+   |
+LL |     let c1 = || get(&*x.f);
+   |              --      ---- first borrow occurs due to use of `x` in closure
+   |              |
+   |              immutable borrow occurs here
+LL |     let c2 = || *x.f = 5;
+   |              ^^ ---- second borrow occurs due to use of `x` in closure
+   |              |
+   |              mutable borrow occurs here
+LL |
+LL |     drop(c1);
+   |          -- immutable borrow later used here
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0502, E0506.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-imm.rs b/tests/ui/borrowck/borrowck-closures-mut-of-imm.rs
new file mode 100644
index 00000000000..d7e187a2b39
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-mut-of-imm.rs
@@ -0,0 +1,18 @@
+// Tests that two closures cannot simultaneously have mutable
+// and immutable access to the variable. Issue #6801.
+
+fn set(x: &mut isize) {
+    *x = 4;
+}
+
+fn a(x: &isize) {
+    let mut c1 = || set(&mut *x);
+    //~^ ERROR cannot borrow
+    let mut c2 = || set(&mut *x);
+    //~^ ERROR cannot borrow
+    //~| ERROR two closures require unique access to `x` at the same time
+    c2(); c1();
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/tests/ui/borrowck/borrowck-closures-mut-of-imm.stderr
new file mode 100644
index 00000000000..537ec9895e1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-mut-of-imm.stderr
@@ -0,0 +1,32 @@
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
+  --> $DIR/borrowck-closures-mut-of-imm.rs:9:25
+   |
+LL |     let mut c1 = || set(&mut *x);
+   |                         ^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
+  --> $DIR/borrowck-closures-mut-of-imm.rs:11:25
+   |
+LL |     let mut c2 = || set(&mut *x);
+   |                         ^^^^^^^ cannot borrow as mutable
+
+error[E0524]: two closures require unique access to `x` at the same time
+  --> $DIR/borrowck-closures-mut-of-imm.rs:11:18
+   |
+LL |     let mut c1 = || set(&mut *x);
+   |                  --          -- first borrow occurs due to use of `x` in closure
+   |                  |
+   |                  first closure is constructed here
+LL |
+LL |     let mut c2 = || set(&mut *x);
+   |                  ^^          -- second borrow occurs due to use of `x` in closure
+   |                  |
+   |                  second closure is constructed here
+...
+LL |     c2(); c1();
+   |           -- first borrow later used here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0524, E0596.
+For more information about an error, try `rustc --explain E0524`.
diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-mut.rs b/tests/ui/borrowck/borrowck-closures-mut-of-mut.rs
new file mode 100644
index 00000000000..50c6f2c585e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-mut-of-mut.rs
@@ -0,0 +1,20 @@
+// Tests that two closures cannot simultaneously both have mutable
+// access to the variable. Related to issue #6801.
+
+fn get(x: &isize) -> isize {
+    *x
+}
+
+fn set(x: &mut isize) {
+    *x = 4;
+}
+
+fn a(x: &mut isize) {
+    let mut c1 = || set(&mut *x);
+    let mut c2 = || set(&mut *x);
+    //~^ ERROR two closures require unique access to `x` at the same time
+    c2(); c1();
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/tests/ui/borrowck/borrowck-closures-mut-of-mut.stderr
new file mode 100644
index 00000000000..e5ee5a40105
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-mut-of-mut.stderr
@@ -0,0 +1,18 @@
+error[E0524]: two closures require unique access to `x` at the same time
+  --> $DIR/borrowck-closures-mut-of-mut.rs:14:18
+   |
+LL |     let mut c1 = || set(&mut *x);
+   |                  --          -- first borrow occurs due to use of `x` in closure
+   |                  |
+   |                  first closure is constructed here
+LL |     let mut c2 = || set(&mut *x);
+   |                  ^^          -- second borrow occurs due to use of `x` in closure
+   |                  |
+   |                  second closure is constructed here
+LL |
+LL |     c2(); c1();
+   |           -- first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0524`.
diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs
new file mode 100644
index 00000000000..0229ca37a69
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs
@@ -0,0 +1,117 @@
+// Check that closure captures for slice patterns are inferred correctly
+
+#![allow(unused_variables)]
+
+// run-pass
+
+fn arr_by_ref(x: [String; 3]) {
+    let r = &x;
+    let f = || {
+        let [ref y, ref z @ ..] = x;
+    };
+    f();
+    f();
+    // Ensure `x` was borrowed
+    drop(r);
+    // Ensure that `x` wasn't moved from.
+    drop(x);
+}
+
+fn arr_by_mut(mut x: [String; 3]) {
+    let mut f = || {
+        let [ref mut y, ref mut z @ ..] = x;
+    };
+    f();
+    f();
+    drop(x);
+}
+
+fn arr_by_move(x: [String; 3]) {
+    let f = || {
+        let [y, z @ ..] = x;
+    };
+    f();
+}
+
+fn arr_ref_by_ref(x: &[String; 3]) {
+    let r = &x;
+    let f = || {
+        let [ref y, ref z @ ..] = *x;
+    };
+    let g = || {
+        let [y, z @ ..] = x;
+    };
+    f();
+    g();
+    f();
+    g();
+    drop(r);
+    drop(x);
+}
+
+fn arr_ref_by_mut(x: &mut [String; 3]) {
+    let mut f = || {
+        let [ref mut y, ref mut z @ ..] = *x;
+    };
+    f();
+    f();
+    let mut g = || {
+        let [y, z @ ..] = x;
+        // Ensure binding mode was chosen correctly:
+        std::mem::swap(y, &mut z[0]);
+    };
+    g();
+    g();
+    drop(x);
+}
+
+fn arr_box_by_move(x: Box<[String; 3]>) {
+    let f = || {
+        let [y, z @ ..] = *x;
+    };
+    f();
+}
+
+fn slice_by_ref(x: &[String]) {
+    let r = &x;
+    let f = || {
+        if let [ref y, ref z @ ..] = *x {}
+    };
+    let g = || {
+        if let [y, z @ ..] = x {}
+    };
+    f();
+    g();
+    f();
+    g();
+    drop(r);
+    drop(x);
+}
+
+fn slice_by_mut(x: &mut [String]) {
+    let mut f = || {
+        if let [ref mut y, ref mut z @ ..] = *x {}
+    };
+    f();
+    f();
+    let mut g = || {
+        if let [y, z @ ..] = x {
+            // Ensure binding mode was chosen correctly:
+            std::mem::swap(y, &mut z[0]);
+        }
+    };
+    g();
+    g();
+    drop(x);
+}
+
+fn main() {
+    arr_by_ref(Default::default());
+    arr_by_mut(Default::default());
+    arr_by_move(Default::default());
+    arr_ref_by_ref(&Default::default());
+    arr_ref_by_mut(&mut Default::default());
+    arr_box_by_move(Default::default());
+    slice_by_ref(&<[_; 3]>::default());
+    slice_by_mut(&mut <[_; 3]>::default());
+}
diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns.rs b/tests/ui/borrowck/borrowck-closures-slice-patterns.rs
new file mode 100644
index 00000000000..32057d5c126
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-slice-patterns.rs
@@ -0,0 +1,82 @@
+// Check that closure captures for slice patterns are inferred correctly
+
+fn arr_by_ref(mut x: [String; 3]) {
+    let f = || {
+        let [ref y, ref z @ ..] = x;
+    };
+    let r = &mut x;
+    //~^ ERROR cannot borrow
+    f();
+}
+
+fn arr_by_mut(mut x: [String; 3]) {
+    let mut f = || {
+        let [ref mut y, ref mut z @ ..] = x;
+    };
+    let r = &x;
+    //~^ ERROR cannot borrow
+    f();
+}
+
+fn arr_by_move(x: [String; 3]) {
+    let f = || {
+        let [y, z @ ..] = x;
+    };
+    &x;
+    //~^ ERROR borrow of moved value
+}
+
+fn arr_ref_by_ref(x: &mut [String; 3]) {
+    let f = || {
+        let [ref y, ref z @ ..] = *x;
+    };
+    let r = &mut *x;
+    //~^ ERROR cannot borrow
+    f();
+}
+
+fn arr_ref_by_uniq(x: &mut [String; 3]) {
+    let mut f = || {
+        let [ref mut y, ref mut z @ ..] = *x;
+    };
+    let r = &x;
+    //~^ ERROR cannot borrow
+    f();
+}
+
+fn arr_box_by_move(x: Box<[String; 3]>) {
+    let f = || {
+        let [y, z @ ..] = *x;
+    };
+    &x;
+    //~^ ERROR borrow of moved value
+}
+
+fn slice_by_ref(x: &mut [String]) {
+    let f = || {
+        if let [ref y, ref z @ ..] = *x {}
+    };
+    let r = &mut *x;
+    //~^ ERROR cannot borrow
+    f();
+}
+
+fn slice_by_uniq(x: &mut [String]) {
+    let mut f = || {
+        if let [ref mut y, ref mut z @ ..] = *x {}
+    };
+    let r = &x;
+    //~^ ERROR cannot borrow
+    f();
+}
+
+fn main() {
+    arr_by_ref(Default::default());
+    arr_by_mut(Default::default());
+    arr_by_move(Default::default());
+    arr_ref_by_ref(&mut Default::default());
+    arr_ref_by_uniq(&mut Default::default());
+    arr_box_by_move(Default::default());
+    slice_by_ref(&mut <[_; 3]>::default());
+    slice_by_uniq(&mut <[_; 3]>::default());
+}
diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr
new file mode 100644
index 00000000000..411d85b8e05
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr
@@ -0,0 +1,114 @@
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-closures-slice-patterns.rs:7:13
+   |
+LL |     let f = || {
+   |             -- immutable borrow occurs here
+LL |         let [ref y, ref z @ ..] = x;
+   |                                   - first borrow occurs due to use of `x` in closure
+LL |     };
+LL |     let r = &mut x;
+   |             ^^^^^^ mutable borrow occurs here
+LL |
+LL |     f();
+   |     - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-closures-slice-patterns.rs:16:13
+   |
+LL |     let mut f = || {
+   |                 -- mutable borrow occurs here
+LL |         let [ref mut y, ref mut z @ ..] = x;
+   |                                           - first borrow occurs due to use of `x` in closure
+LL |     };
+LL |     let r = &x;
+   |             ^^ immutable borrow occurs here
+LL |
+LL |     f();
+   |     - mutable borrow later used here
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/borrowck-closures-slice-patterns.rs:25:5
+   |
+LL | fn arr_by_move(x: [String; 3]) {
+   |                - move occurs because `x` has type `[String; 3]`, which does not implement the `Copy` trait
+LL |     let f = || {
+   |             -- value moved into closure here
+LL |         let [y, z @ ..] = x;
+   |                           - variable moved due to use in closure
+LL |     };
+LL |     &x;
+   |     ^^ value borrowed here after move
+
+error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-closures-slice-patterns.rs:33:13
+   |
+LL |     let f = || {
+   |             -- immutable borrow occurs here
+LL |         let [ref y, ref z @ ..] = *x;
+   |                                   -- first borrow occurs due to use of `x` in closure
+LL |     };
+LL |     let r = &mut *x;
+   |             ^^^^^^^ mutable borrow occurs here
+LL |
+LL |     f();
+   |     - immutable borrow later used here
+
+error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
+  --> $DIR/borrowck-closures-slice-patterns.rs:42:13
+   |
+LL |     let mut f = || {
+   |                 -- closure construction occurs here
+LL |         let [ref mut y, ref mut z @ ..] = *x;
+   |                                           -- first borrow occurs due to use of `x` in closure
+LL |     };
+LL |     let r = &x;
+   |             ^^ second borrow occurs here
+LL |
+LL |     f();
+   |     - first borrow later used here
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/borrowck-closures-slice-patterns.rs:51:5
+   |
+LL | fn arr_box_by_move(x: Box<[String; 3]>) {
+   |                    - move occurs because `x` has type `Box<[String; 3]>`, which does not implement the `Copy` trait
+LL |     let f = || {
+   |             -- value moved into closure here
+LL |         let [y, z @ ..] = *x;
+   |                           -- variable moved due to use in closure
+LL |     };
+LL |     &x;
+   |     ^^ value borrowed here after move
+
+error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-closures-slice-patterns.rs:59:13
+   |
+LL |     let f = || {
+   |             -- immutable borrow occurs here
+LL |         if let [ref y, ref z @ ..] = *x {}
+   |                                      -- first borrow occurs due to use of `x` in closure
+LL |     };
+LL |     let r = &mut *x;
+   |             ^^^^^^^ mutable borrow occurs here
+LL |
+LL |     f();
+   |     - immutable borrow later used here
+
+error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
+  --> $DIR/borrowck-closures-slice-patterns.rs:68:13
+   |
+LL |     let mut f = || {
+   |                 -- closure construction occurs here
+LL |         if let [ref mut y, ref mut z @ ..] = *x {}
+   |                                              -- first borrow occurs due to use of `x` in closure
+LL |     };
+LL |     let r = &x;
+   |             ^^ second borrow occurs here
+LL |
+LL |     f();
+   |     - first borrow later used here
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0382, E0501, E0502.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-closures-two-imm.rs b/tests/ui/borrowck/borrowck-closures-two-imm.rs
new file mode 100644
index 00000000000..ab135194a09
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-two-imm.rs
@@ -0,0 +1,41 @@
+// run-pass
+// Tests that two closures can simultaneously have immutable
+// access to the variable, whether that immutable access be used
+// for direct reads or for taking immutable ref. Also check
+// that the main function can read the variable too while
+// the closures are in scope. Issue #6801.
+
+
+fn a() -> i32 {
+    let mut x = 3;
+    x += 1;
+    let c1 = || x * 4;
+    let c2 = || x * 5;
+    c1() * c2() * x
+}
+
+fn get(x: &i32) -> i32 {
+    *x * 4
+}
+
+fn b() -> i32 {
+    let mut x = 3;
+    x += 1;
+    let c1 = || get(&x);
+    let c2 = || get(&x);
+    c1() * c2() * x
+}
+
+fn c() -> i32 {
+    let mut x = 3;
+    x += 1;
+    let c1 = || x * 5;
+    let c2 = || get(&x);
+    c1() * c2() * x
+}
+
+pub fn main() {
+    assert_eq!(a(), 1280);
+    assert_eq!(b(), 1024);
+    assert_eq!(c(), 1280);
+}
diff --git a/tests/ui/borrowck/borrowck-closures-two-mut-fail.rs b/tests/ui/borrowck/borrowck-closures-two-mut-fail.rs
new file mode 100644
index 00000000000..63a75cdff42
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-two-mut-fail.rs
@@ -0,0 +1,59 @@
+// Tests that two closures cannot simultaneously have mutable
+// access to the variable, whether that mutable access be used
+// for direct assignment or for taking mutable ref. Issue #6801.
+
+
+
+
+
+
+
+fn to_fn_mut<F: FnMut()>(f: F) -> F { f }
+
+fn a() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| x = 4);
+    let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
+    c1;
+}
+
+fn set(x: &mut isize) {
+    *x = 4;
+}
+
+fn b() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| set(&mut x));
+    let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
+    c1;
+}
+
+fn c() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| x = 5);
+    let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
+    c1;
+}
+
+fn d() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| x = 5);
+    let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
+    //~^ ERROR cannot borrow `x` as mutable more than once
+    c1;
+}
+
+fn g() {
+    struct Foo {
+        f: Box<isize>
+    }
+
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
+    let c1 = to_fn_mut(|| set(&mut *x.f));
+    let c2 = to_fn_mut(|| set(&mut *x.f));
+    //~^ ERROR cannot borrow `x` as mutable more than once
+    c1;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-closures-two-mut-fail.stderr b/tests/ui/borrowck/borrowck-closures-two-mut-fail.stderr
new file mode 100644
index 00000000000..fe8e7a29e24
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-two-mut-fail.stderr
@@ -0,0 +1,75 @@
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut-fail.rs:16:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 4);
+   |                        -- - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| x = 5);
+   |                        ^^ - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |     c1;
+   |     -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut-fail.rs:27:24
+   |
+LL |     let c1 = to_fn_mut(|| set(&mut x));
+   |                        --          - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut x));
+   |                        ^^          - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |     c1;
+   |     -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut-fail.rs:34:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 5);
+   |                        -- - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut x));
+   |                        ^^          - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |     c1;
+   |     -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut-fail.rs:41:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 5);
+   |                        -- - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
+   |                        ^^                                  - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |
+LL |     c1;
+   |     -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut-fail.rs:53:24
+   |
+LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
+   |                        --          ---- first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
+   |                        ^^          ---- second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |
+LL |     c1;
+   |     -- first borrow later used here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-closures-two-mut.rs b/tests/ui/borrowck/borrowck-closures-two-mut.rs
new file mode 100644
index 00000000000..cdff8f9e890
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-two-mut.rs
@@ -0,0 +1,55 @@
+// Tests that two closures cannot simultaneously have mutable
+// access to the variable, whether that mutable access be used
+// for direct assignment or for taking mutable ref. Issue #6801.
+
+
+
+fn to_fn_mut<F: FnMut()>(f: F) -> F { f }
+
+fn a() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| x = 4);
+    let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
+    drop((c1, c2));
+}
+
+fn set(x: &mut isize) {
+    *x = 4;
+}
+
+fn b() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| set(&mut x));
+    let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
+    drop((c1, c2));
+}
+
+fn c() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| x = 5);
+    let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
+    drop((c1, c2));
+}
+
+fn d() {
+    let mut x = 3;
+    let c1 = to_fn_mut(|| x = 5);
+    let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
+    //~^ ERROR cannot borrow `x` as mutable more than once
+    drop((c1, c2));
+}
+
+fn g() {
+    struct Foo {
+        f: Box<isize>
+    }
+
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
+    let c1 = to_fn_mut(|| set(&mut *x.f));
+    let c2 = to_fn_mut(|| set(&mut *x.f));
+    //~^ ERROR cannot borrow `x` as mutable more than once
+    drop((c1, c2));
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-closures-two-mut.stderr b/tests/ui/borrowck/borrowck-closures-two-mut.stderr
new file mode 100644
index 00000000000..21e329f4329
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-two-mut.stderr
@@ -0,0 +1,75 @@
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:12:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 4);
+   |                        -- - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| x = 5);
+   |                        ^^ - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |     drop((c1, c2));
+   |           -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:23:24
+   |
+LL |     let c1 = to_fn_mut(|| set(&mut x));
+   |                        --          - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut x));
+   |                        ^^          - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |     drop((c1, c2));
+   |           -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:30:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 5);
+   |                        -- - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut x));
+   |                        ^^          - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |     drop((c1, c2));
+   |           -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:37:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 5);
+   |                        -- - first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
+   |                        ^^                                  - second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |
+LL |     drop((c1, c2));
+   |           -- first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:49:24
+   |
+LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
+   |                        --          ---- first borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
+   |                        ^^          ---- second borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+LL |
+LL |     drop((c1, c2));
+   |           -- first borrow later used here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-closures-unique-imm.rs b/tests/ui/borrowck/borrowck-closures-unique-imm.rs
new file mode 100644
index 00000000000..0dd00476910
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-unique-imm.rs
@@ -0,0 +1,18 @@
+struct Foo {
+    x: isize,
+}
+
+pub fn main() {
+    let mut this = &mut Foo {
+        x: 1,
+    };
+    let mut r = || {
+        let p = &this.x;
+        &mut this.x; //~ ERROR cannot borrow
+        p.use_ref();
+    };
+    r()
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-closures-unique-imm.stderr b/tests/ui/borrowck/borrowck-closures-unique-imm.stderr
new file mode 100644
index 00000000000..0c5fd39b718
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-unique-imm.stderr
@@ -0,0 +1,13 @@
+error[E0502]: cannot borrow `this.x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-closures-unique-imm.rs:11:9
+   |
+LL |         let p = &this.x;
+   |                 ------- immutable borrow occurs here
+LL |         &mut this.x;
+   |         ^^^^^^^^^^^ mutable borrow occurs here
+LL |         p.use_ref();
+   |         ----------- immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-closures-unique.rs b/tests/ui/borrowck/borrowck-closures-unique.rs
new file mode 100644
index 00000000000..67f91dfa842
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-unique.rs
@@ -0,0 +1,54 @@
+// Tests that a closure which requires mutable access to the referent
+// of an `&mut` requires a "unique" borrow -- that is, the variable to
+// be borrowed (here, `x`) will not be borrowed *mutably*, but
+//  may be *immutable*, but we cannot allow
+// multiple borrows.
+
+
+
+fn get(x: &isize) -> isize {
+    *x
+}
+
+fn set(x: &mut isize) -> isize {
+    *x
+}
+
+fn a(x: &mut isize) {
+    let c1 = || get(x);
+    let c2 = || get(x);
+    c1();
+    c2();
+}
+
+fn b(x: &mut isize) {
+    let c1 = || get(x);
+    let c2 = || set(x); //~ ERROR closure requires unique access to `x`
+    c1;
+}
+
+fn c(x: &mut isize) {
+    let c1 = || get(x);
+    let c2 = || { get(x); set(x); }; //~ ERROR closure requires unique access to `x`
+    c1;
+}
+
+fn d(x: &mut isize) {
+    let c1 = || set(x);
+    let c2 = || set(x); //~ ERROR two closures require unique access to `x` at the same time
+    c1;
+}
+
+fn e(x: &'static mut isize) {
+    let c1 = |y: &'static mut isize| x = y;
+    //~^ ERROR cannot assign to `x`, as it is not declared as mutable
+    c1;
+}
+
+fn f(x: &'static mut isize) {
+    let c1 = || x = panic!(); // OK assignment is unreachable.
+    c1;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-closures-unique.stderr b/tests/ui/borrowck/borrowck-closures-unique.stderr
new file mode 100644
index 00000000000..23d3cc0e76f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-unique.stderr
@@ -0,0 +1,54 @@
+error[E0500]: closure requires unique access to `x` but it is already borrowed
+  --> $DIR/borrowck-closures-unique.rs:26:14
+   |
+LL |     let c1 = || get(x);
+   |              --     - first borrow occurs due to use of `x` in closure
+   |              |
+   |              borrow occurs here
+LL |     let c2 = || set(x);
+   |              ^^     - second borrow occurs due to use of `x` in closure
+   |              |
+   |              closure construction occurs here
+LL |     c1;
+   |     -- first borrow later used here
+
+error[E0500]: closure requires unique access to `x` but it is already borrowed
+  --> $DIR/borrowck-closures-unique.rs:32:14
+   |
+LL |     let c1 = || get(x);
+   |              --     - first borrow occurs due to use of `x` in closure
+   |              |
+   |              borrow occurs here
+LL |     let c2 = || { get(x); set(x); };
+   |              ^^               - second borrow occurs due to use of `x` in closure
+   |              |
+   |              closure construction occurs here
+LL |     c1;
+   |     -- first borrow later used here
+
+error[E0524]: two closures require unique access to `x` at the same time
+  --> $DIR/borrowck-closures-unique.rs:38:14
+   |
+LL |     let c1 = || set(x);
+   |              --     - first borrow occurs due to use of `x` in closure
+   |              |
+   |              first closure is constructed here
+LL |     let c2 = || set(x);
+   |              ^^     - second borrow occurs due to use of `x` in closure
+   |              |
+   |              second closure is constructed here
+LL |     c1;
+   |     -- first borrow later used here
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+  --> $DIR/borrowck-closures-unique.rs:43:38
+   |
+LL | fn e(x: &'static mut isize) {
+   |      - help: consider changing this to be mutable: `mut x`
+LL |     let c1 = |y: &'static mut isize| x = y;
+   |                                      ^^^^^ cannot assign
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0500, E0524, E0594.
+For more information about an error, try `rustc --explain E0500`.
diff --git a/tests/ui/borrowck/borrowck-closures-use-after-free.rs b/tests/ui/borrowck/borrowck-closures-use-after-free.rs
new file mode 100644
index 00000000000..be5f1f873df
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-use-after-free.rs
@@ -0,0 +1,23 @@
+// Tests that a closure which mutates a local variable
+// cannot also be supplied a borrowed version of that
+// variable's contents. Issue #11192.
+
+struct Foo {
+  x: isize
+}
+
+impl Drop for Foo {
+  fn drop(&mut self) {
+    println!("drop {}", self.x);
+  }
+}
+
+
+
+fn main() {
+  let mut ptr: Box<_> = Box::new(Foo { x: 0 });
+  let mut test = |foo: &Foo| {
+    ptr = Box::new(Foo { x: ptr.x + 1 });
+  };
+  test(&*ptr); //~ ERROR cannot borrow `*ptr`
+}
diff --git a/tests/ui/borrowck/borrowck-closures-use-after-free.stderr b/tests/ui/borrowck/borrowck-closures-use-after-free.stderr
new file mode 100644
index 00000000000..30900a3b6d9
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-closures-use-after-free.stderr
@@ -0,0 +1,16 @@
+error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-closures-use-after-free.rs:22:8
+   |
+LL |   let mut test = |foo: &Foo| {
+   |                  ----------- mutable borrow occurs here
+LL |     ptr = Box::new(Foo { x: ptr.x + 1 });
+   |     --- first borrow occurs due to use of `ptr` in closure
+LL |   };
+LL |   test(&*ptr);
+   |   ---- ^^^^^ immutable borrow occurs here
+   |   |
+   |   mutable borrow later used by call
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-consume-unsize-vec.rs b/tests/ui/borrowck/borrowck-consume-unsize-vec.rs
new file mode 100644
index 00000000000..347f0212c7f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-consume-unsize-vec.rs
@@ -0,0 +1,12 @@
+// Check that we report an error if an upcast box is moved twice.
+
+fn consume(_: Box<[i32]>) {
+}
+
+fn foo(b: Box<[i32;5]>) {
+    consume(b);
+    consume(b); //~ ERROR use of moved value
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-consume-unsize-vec.stderr b/tests/ui/borrowck/borrowck-consume-unsize-vec.stderr
new file mode 100644
index 00000000000..d2e9497d079
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-consume-unsize-vec.stderr
@@ -0,0 +1,25 @@
+error[E0382]: use of moved value: `b`
+  --> $DIR/borrowck-consume-unsize-vec.rs:8:13
+   |
+LL | fn foo(b: Box<[i32;5]>) {
+   |        - move occurs because `b` has type `Box<[i32; 5]>`, which does not implement the `Copy` trait
+LL |     consume(b);
+   |             - value moved here
+LL |     consume(b);
+   |             ^ value used here after move
+   |
+note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrowck-consume-unsize-vec.rs:3:15
+   |
+LL | fn consume(_: Box<[i32]>) {
+   |    -------    ^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     consume(b.clone());
+   |              ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-consume-upcast-box.rs b/tests/ui/borrowck/borrowck-consume-upcast-box.rs
new file mode 100644
index 00000000000..6b32d185b6f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-consume-upcast-box.rs
@@ -0,0 +1,14 @@
+// Check that we report an error if an upcast box is moved twice.
+
+trait Foo { fn dummy(&self); }
+
+fn consume(_: Box<dyn Foo>) {
+}
+
+fn foo(b: Box<dyn Foo + Send>) {
+    consume(b);
+    consume(b); //~ ERROR use of moved value
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-consume-upcast-box.stderr b/tests/ui/borrowck/borrowck-consume-upcast-box.stderr
new file mode 100644
index 00000000000..ed7e883ca63
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-consume-upcast-box.stderr
@@ -0,0 +1,21 @@
+error[E0382]: use of moved value: `b`
+  --> $DIR/borrowck-consume-upcast-box.rs:10:13
+   |
+LL | fn foo(b: Box<dyn Foo + Send>) {
+   |        - move occurs because `b` has type `Box<dyn Foo + Send>`, which does not implement the `Copy` trait
+LL |     consume(b);
+   |             - value moved here
+LL |     consume(b);
+   |             ^ value used here after move
+   |
+note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrowck-consume-upcast-box.rs:5:15
+   |
+LL | fn consume(_: Box<dyn Foo>) {
+   |    -------    ^^^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.rs b/tests/ui/borrowck/borrowck-describe-lvalue.rs
new file mode 100644
index 00000000000..cdcff69d6e5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-describe-lvalue.rs
@@ -0,0 +1,279 @@
+pub struct Foo {
+  x: u32
+}
+
+pub struct Bar(u32);
+
+pub enum Baz {
+    X(u32)
+}
+
+union U {
+    a: u8,
+    b: u64,
+}
+
+impl Foo {
+  fn x(&mut self) -> &mut u32 { &mut self.x }
+}
+
+impl Bar {
+    fn x(&mut self) -> &mut u32 { &mut self.0 }
+}
+
+impl Baz {
+    fn x(&mut self) -> &mut u32 {
+        match *self {
+            Baz::X(ref mut value) => value
+        }
+    }
+}
+
+fn main() {
+    // Local and field from struct
+    {
+        let mut f = Foo { x: 22 };
+        let x = f.x();
+        f.x; //~ ERROR cannot use `f.x` because it was mutably borrowed
+        drop(x);
+    }
+    // Local and field from tuple-struct
+    {
+        let mut g = Bar(22);
+        let x = g.x();
+        g.0; //~ ERROR cannot use `g.0` because it was mutably borrowed
+        drop(x);
+    }
+    // Local and field from tuple
+    {
+        let mut h = (22, 23);
+        let x = &mut h.0;
+        h.0; //~ ERROR cannot use `h.0` because it was mutably borrowed
+        drop(x);
+    }
+    // Local and field from enum
+    {
+        let mut e = Baz::X(2);
+        let x = e.x();
+        match e {
+            Baz::X(value) => value //~ ERROR cannot use `e.0` because it was mutably borrowed
+        };
+        drop(x);
+    }
+    // Local and field from union
+    unsafe {
+        let mut u = U { b: 0 };
+        let x = &mut u.a;
+        u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
+        drop(x);
+    }
+    // Deref and field from struct
+    {
+        let mut f = Box::new(Foo { x: 22 });
+        let x = f.x();
+        f.x; //~ ERROR cannot use `f.x` because it was mutably borrowed
+        drop(x);
+    }
+    // Deref and field from tuple-struct
+    {
+        let mut g = Box::new(Bar(22));
+        let x = g.x();
+        g.0; //~ ERROR cannot use `g.0` because it was mutably borrowed
+        drop(x);
+    }
+    // Deref and field from tuple
+    {
+        let mut h = Box::new((22, 23));
+        let x = &mut h.0;
+        h.0; //~ ERROR cannot use `h.0` because it was mutably borrowed
+        drop(x);
+    }
+    // Deref and field from enum
+    {
+        let mut e = Box::new(Baz::X(3));
+        let x = e.x();
+        match *e {
+            Baz::X(value) => value
+            //~^ ERROR cannot use `e.0` because it was mutably borrowed
+        };
+        drop(x);
+    }
+    // Deref and field from union
+    unsafe {
+        let mut u = Box::new(U { b: 0 });
+        let x = &mut u.a;
+        u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
+        drop(x);
+    }
+    // Constant index
+    {
+        let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+        let x = &mut v;
+        match v {
+            &[x, _, .., _, _] => println!("{}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                            _ => panic!("other case"),
+        }
+        match v {
+            &[_, x, .., _, _] => println!("{}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                            _ => panic!("other case"),
+        }
+        match v {
+            &[_, _, .., x, _] => println!("{}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                            _ => panic!("other case"),
+        }
+        match v {
+            &[_, _, .., _, x] => println!("{}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                            _ => panic!("other case"),
+        }
+        drop(x);
+    }
+    // Subslices
+    {
+        let mut v = &[1, 2, 3, 4, 5];
+        let x = &mut v;
+        match v {
+            &[x @ ..] => println!("{:?}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+            _ => panic!("other case"),
+        }
+        match v {
+            &[_, x @ ..] => println!("{:?}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+            _ => panic!("other case"),
+        }
+        match v {
+            &[x @ .., _] => println!("{:?}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+            _ => panic!("other case"),
+        }
+        match v {
+            &[_, x @ .., _] => println!("{:?}", x),
+                //~^ ERROR cannot use `v[..]` because it was mutably borrowed
+            _ => panic!("other case"),
+        }
+        drop(x);
+    }
+    // Downcasted field
+    {
+        enum E<X> { A(X), B { x: X } }
+
+        let mut e = E::A(3);
+        let x = &mut e;
+        match e {
+            //~^ ERROR cannot use `e` because it was mutably borrowed
+            E::A(ref ax) =>
+                //~^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable
+                println!("e.ax: {:?}", ax),
+            E::B { x: ref bx } =>
+                //~^ ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable
+                println!("e.bx: {:?}", bx),
+        }
+        drop(x);
+    }
+    // Field in field
+    {
+        struct F { x: u32, y: u32 };
+        struct S { x: F, y: (u32, u32), };
+        let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) };
+        let x = &mut s;
+        match s {
+            S  { y: (ref y0, _), .. } =>
+                //~^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
+                println!("y0: {:?}", y0),
+            _ => panic!("other case"),
+        }
+        match s {
+            S  { x: F { y: ref x0, .. }, .. } =>
+                //~^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
+                println!("x0: {:?}", x0),
+            _ => panic!("other case"),
+        }
+        drop(x);
+    }
+    // Field of ref
+    {
+        struct Block<'a> {
+            current: &'a u8,
+            unrelated: &'a u8,
+        };
+
+        fn bump<'a>(mut block: &mut Block<'a>) {
+            let x = &mut block;
+            let p: &'a u8 = &*block.current;
+            //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+            // See issue rust#38899
+            drop(x);
+        }
+    }
+    // Field of ptr
+    {
+        struct Block2 {
+            current: *const u8,
+            unrelated: *const u8,
+        }
+
+        unsafe fn bump2(mut block: *mut Block2) {
+            let x = &mut block;
+            let p : *const u8 = &*(*block).current;
+            //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+            // See issue rust#38899
+            drop(x);
+        }
+    }
+    // Field of index
+    {
+        struct F {x: u32, y: u32};
+        let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
+        let x = &mut v;
+        v[0].y;
+        //~^ ERROR cannot use `v[_].y` because it was mutably borrowed
+        //~| ERROR cannot use `*v` because it was mutably borrowed
+        drop(x);
+    }
+    // Field of constant index
+    {
+        struct F {x: u32, y: u32};
+        let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
+        let x = &mut v;
+        match v {
+            &[_, F {x: ref xf, ..}] => println!("{}", xf),
+            //~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
+            _ => panic!("other case")
+        }
+        drop(x);
+    }
+    // Field from upvar
+    {
+        let mut x = 0;
+        || {
+            let y = &mut x;
+            &mut x; //~ ERROR cannot borrow `x` as mutable more than once at a time
+            *y = 1;
+        };
+    }
+    // Field from upvar nested
+    {
+        let mut x = 0;
+           || {
+               || { //~ ERROR captured variable cannot escape `FnMut` closure body
+                   let y = &mut x;
+                   &mut x; //~ ERROR cannot borrow `x` as mutable more than once at a time
+                   *y = 1;
+                   drop(y);
+                }
+           };
+    }
+    {
+        fn foo(x: Vec<i32>) {
+            let c = || {
+                drop(x);
+                drop(x); //~ ERROR use of moved value: `x`
+            };
+            c();
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.stderr b/tests/ui/borrowck/borrowck-describe-lvalue.stderr
new file mode 100644
index 00000000000..2c1b9c10d46
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-describe-lvalue.stderr
@@ -0,0 +1,372 @@
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-describe-lvalue.rs:254:13
+   |
+LL |             let y = &mut x;
+   |                     ------ first mutable borrow occurs here
+LL |             &mut x;
+   |             ^^^^^^ second mutable borrow occurs here
+LL |             *y = 1;
+   |             ------ first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-describe-lvalue.rs:264:20
+   |
+LL |                    let y = &mut x;
+   |                            ------ first mutable borrow occurs here
+LL |                    &mut x;
+   |                    ^^^^^^ second mutable borrow occurs here
+LL |                    *y = 1;
+   |                    ------ first borrow later used here
+
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/borrowck-describe-lvalue.rs:262:16
+   |
+LL |           let mut x = 0;
+   |               ----- variable defined here
+LL |              || {
+   |               - inferred to be a `FnMut` closure
+LL | /                || {
+LL | |                    let y = &mut x;
+   | |                                 - variable captured here
+LL | |                    &mut x;
+LL | |                    *y = 1;
+LL | |                    drop(y);
+LL | |                 }
+   | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = 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
+help: consider adding 'move' keyword before the nested closure
+   |
+LL |                move || {
+   |                ++++
+
+error[E0503]: cannot use `f.x` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:37:9
+   |
+LL |         let x = f.x();
+   |                 ----- borrow of `f` occurs here
+LL |         f.x;
+   |         ^^^ use of borrowed `f`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `g.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:44:9
+   |
+LL |         let x = g.x();
+   |                 ----- borrow of `g` occurs here
+LL |         g.0;
+   |         ^^^ use of borrowed `g`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `h.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:51:9
+   |
+LL |         let x = &mut h.0;
+   |                 -------- borrow of `h.0` occurs here
+LL |         h.0;
+   |         ^^^ use of borrowed `h.0`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `e.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:59:20
+   |
+LL |         let x = e.x();
+   |                 ----- borrow of `e` occurs here
+LL |         match e {
+LL |             Baz::X(value) => value
+   |                    ^^^^^ use of borrowed `e`
+LL |         };
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `u.a` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:67:9
+   |
+LL |         let x = &mut u.a;
+   |                 -------- borrow of `u.a` occurs here
+LL |         u.a;
+   |         ^^^ use of borrowed `u.a`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `f.x` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:74:9
+   |
+LL |         let x = f.x();
+   |                 ----- borrow of `*f` occurs here
+LL |         f.x;
+   |         ^^^ use of borrowed `*f`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `g.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:81:9
+   |
+LL |         let x = g.x();
+   |                 ----- borrow of `*g` occurs here
+LL |         g.0;
+   |         ^^^ use of borrowed `*g`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `h.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:88:9
+   |
+LL |         let x = &mut h.0;
+   |                 -------- borrow of `h.0` occurs here
+LL |         h.0;
+   |         ^^^ use of borrowed `h.0`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `e.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:96:20
+   |
+LL |         let x = e.x();
+   |                 ----- borrow of `*e` occurs here
+LL |         match *e {
+LL |             Baz::X(value) => value
+   |                    ^^^^^ use of borrowed `*e`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `u.a` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:105:9
+   |
+LL |         let x = &mut u.a;
+   |                 -------- borrow of `u.a` occurs here
+LL |         u.a;
+   |         ^^^ use of borrowed `u.a`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:113:15
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         match v {
+LL |             &[x, _, .., _, _] => println!("{}", x),
+   |               ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:118:18
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, x, .., _, _] => println!("{}", x),
+   |                  ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:123:25
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, _, .., x, _] => println!("{}", x),
+   |                         ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:128:28
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, _, .., _, x] => println!("{}", x),
+   |                            ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:139:15
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         match v {
+LL |             &[x @ ..] => println!("{:?}", x),
+   |               ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:144:18
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, x @ ..] => println!("{:?}", x),
+   |                  ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:149:15
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[x @ .., _] => println!("{:?}", x),
+   |               ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:154:18
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, x @ .., _] => println!("{:?}", x),
+   |                  ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `e` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:166:15
+   |
+LL |         let x = &mut e;
+   |                 ------ borrow of `e` occurs here
+LL |         match e {
+   |               ^ use of borrowed `e`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:168:18
+   |
+LL |         let x = &mut e;
+   |                 ------ mutable borrow occurs here
+...
+LL |             E::A(ref ax) =>
+   |                  ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:171:23
+   |
+LL |         let x = &mut e;
+   |                 ------ mutable borrow occurs here
+...
+LL |             E::B { x: ref bx } =>
+   |                       ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:184:22
+   |
+LL |         let x = &mut s;
+   |                 ------ mutable borrow occurs here
+LL |         match s {
+LL |             S  { y: (ref y0, _), .. } =>
+   |                      ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:190:28
+   |
+LL |         let x = &mut s;
+   |                 ------ mutable borrow occurs here
+...
+LL |             S  { x: F { y: ref x0, .. }, .. } =>
+   |                            ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0503]: cannot use `*v` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:232:9
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         v[0].y;
+   |         ^^^^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[_].y` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:232:9
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         v[0].y;
+   |         ^^^^^^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:243:24
+   |
+LL |         let x = &mut v;
+   |                 ------ mutable borrow occurs here
+LL |         match v {
+LL |             &[_, F {x: ref xf, ..}] => println!("{}", xf),
+   |                        ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:206:29
+   |
+LL |             let x = &mut block;
+   |                     ---------- mutable borrow occurs here
+LL |             let p: &'a u8 = &*block.current;
+   |                             ^^^^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |             drop(x);
+   |                  - mutable borrow later used here
+
+error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:221:33
+   |
+LL |             let x = &mut block;
+   |                     ---------- mutable borrow occurs here
+LL |             let p : *const u8 = &*(*block).current;
+   |                                 ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |             drop(x);
+   |                  - mutable borrow later used here
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrowck-describe-lvalue.rs:274:22
+   |
+LL |                 drop(x);
+   |                      - value moved here
+LL |                 drop(x);
+   |                      ^ value used here after move
+   |
+   = note: move occurs because `x` has type `Vec<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to 32 previous errors
+
+Some errors have detailed explanations: E0382, E0499, E0502, E0503.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-drop-from-guard.rs b/tests/ui/borrowck/borrowck-drop-from-guard.rs
new file mode 100644
index 00000000000..0f320af2657
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-drop-from-guard.rs
@@ -0,0 +1,20 @@
+#![feature(if_let_guard)]
+
+fn foo(_:String) {}
+
+fn main()
+{
+    let my_str = "hello".to_owned();
+    match Some(42) {
+        Some(_) if { drop(my_str); false } => {}
+        Some(_) => {}
+        None => { foo(my_str); } //~ ERROR [E0382]
+    }
+
+    let my_str = "hello".to_owned();
+    match Some(42) {
+        Some(_) if let Some(()) = { drop(my_str); None } => {}
+        Some(_) => {}
+        None => { foo(my_str); } //~ ERROR [E0382]
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-drop-from-guard.stderr b/tests/ui/borrowck/borrowck-drop-from-guard.stderr
new file mode 100644
index 00000000000..9fa28efd855
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-drop-from-guard.stderr
@@ -0,0 +1,37 @@
+error[E0382]: use of moved value: `my_str`
+  --> $DIR/borrowck-drop-from-guard.rs:11:23
+   |
+LL |     let my_str = "hello".to_owned();
+   |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL |     match Some(42) {
+LL |         Some(_) if { drop(my_str); false } => {}
+   |                           ------ value moved here
+LL |         Some(_) => {}
+LL |         None => { foo(my_str); }
+   |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if { drop(my_str.clone()); false } => {}
+   |                                 ++++++++
+
+error[E0382]: use of moved value: `my_str`
+  --> $DIR/borrowck-drop-from-guard.rs:18:23
+   |
+LL |     let my_str = "hello".to_owned();
+   |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL |     match Some(42) {
+LL |         Some(_) if let Some(()) = { drop(my_str); None } => {}
+   |                                          ------ value moved here
+LL |         Some(_) => {}
+LL |         None => { foo(my_str); }
+   |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
+   |                                                ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-1.rs b/tests/ui/borrowck/borrowck-escaping-closure-error-1.rs
new file mode 100644
index 00000000000..11c0610aa0c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-escaping-closure-error-1.rs
@@ -0,0 +1,15 @@
+use std::thread::spawn;
+
+// Test that we give a custom error (E0373) for the case where a
+// closure is escaping current frame, and offer a suggested code edit.
+// I refrained from including the precise message here, but the
+// original text as of the time of this writing is:
+//
+//    closure may outlive the current function, but it borrows `books`,
+//    which is owned by the current function
+
+fn main() {
+    let mut books = vec![1,2,3];
+    spawn(|| books.push(4));
+    //~^ ERROR E0373
+}
diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-1.stderr b/tests/ui/borrowck/borrowck-escaping-closure-error-1.stderr
new file mode 100644
index 00000000000..acf6b37b773
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-escaping-closure-error-1.stderr
@@ -0,0 +1,21 @@
+error[E0373]: closure may outlive the current function, but it borrows `books`, which is owned by the current function
+  --> $DIR/borrowck-escaping-closure-error-1.rs:13:11
+   |
+LL |     spawn(|| books.push(4));
+   |           ^^ ----- `books` is borrowed here
+   |           |
+   |           may outlive borrowed value `books`
+   |
+note: function requires argument type to outlive `'static`
+  --> $DIR/borrowck-escaping-closure-error-1.rs:13:5
+   |
+LL |     spawn(|| books.push(4));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword
+   |
+LL |     spawn(move || books.push(4));
+   |           ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-2.rs b/tests/ui/borrowck/borrowck-escaping-closure-error-2.rs
new file mode 100644
index 00000000000..b50d455637b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-escaping-closure-error-2.rs
@@ -0,0 +1,15 @@
+// Test that we give a custom error (E0373) for the case where a
+// closure is escaping current frame, and offer a suggested code edit.
+// I refrained from including the precise message here, but the
+// original text as of the time of this writing is:
+//
+//    closure may outlive the current function, but it borrows `books`,
+//    which is owned by the current function
+
+fn foo<'a>(x: &'a i32) -> Box<dyn FnMut() + 'a> {
+    let mut books = vec![1,2,3];
+    Box::new(|| books.push(4))
+    //~^ ERROR E0373
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-2.stderr b/tests/ui/borrowck/borrowck-escaping-closure-error-2.stderr
new file mode 100644
index 00000000000..814042539a2
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-escaping-closure-error-2.stderr
@@ -0,0 +1,21 @@
+error[E0373]: closure may outlive the current function, but it borrows `books`, which is owned by the current function
+  --> $DIR/borrowck-escaping-closure-error-2.rs:11:14
+   |
+LL |     Box::new(|| books.push(4))
+   |              ^^ ----- `books` is borrowed here
+   |              |
+   |              may outlive borrowed value `books`
+   |
+note: closure is returned here
+  --> $DIR/borrowck-escaping-closure-error-2.rs:11:5
+   |
+LL |     Box::new(|| books.push(4))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword
+   |
+LL |     Box::new(move || books.push(4))
+   |              ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs
new file mode 100644
index 00000000000..dd6708582c1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs
@@ -0,0 +1,264 @@
+// run-pass
+#![allow(unused_mut)]
+#![allow(unused_variables)]
+// pretty-expanded FIXME #23616
+
+struct A { a: isize, b: Box<isize> }
+struct B { a: Box<isize>, b: Box<isize> }
+
+fn move_after_copy() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.a);
+    drop(x.b);
+}
+
+fn move_after_fu_copy() {
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { b: Box::new(3), .. x };
+    drop(x.b);
+}
+
+fn fu_move_after_copy() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.a);
+    let _y = A { a: 3, .. x };
+}
+
+fn fu_move_after_fu_copy() {
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { b: Box::new(3), .. x };
+    let _z = A { a: 4, .. x };
+}
+
+fn copy_after_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    drop(x.a);
+}
+
+fn copy_after_fu_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    let y = A { a: 3, .. x };
+    drop(x.a);
+}
+
+fn fu_copy_after_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    let _y = A { b: Box::new(3), .. x };
+}
+
+fn fu_copy_after_fu_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    let _z = A { b: Box::new(3), .. x };
+}
+
+fn borrow_after_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    let p = &x.a;
+    drop(*p);
+}
+
+fn borrow_after_fu_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    let p = &x.a;
+    drop(*p);
+}
+
+fn move_after_borrow() {
+    let x = A { a: 1, b: Box::new(2) };
+    let p = &x.a;
+    drop(x.b);
+    drop(*p);
+}
+
+fn fu_move_after_borrow() {
+    let x = A { a: 1, b: Box::new(2) };
+    let p = &x.a;
+    let _y = A { a: 3, .. x };
+    drop(*p);
+}
+
+fn mut_borrow_after_mut_borrow() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let p = &mut x.a;
+    let q = &mut x.b;
+    drop(*p);
+    drop(**q);
+}
+
+fn move_after_move() {
+    let x = B { a: Box::new(1), b: Box::new(2) };
+    drop(x.a);
+    drop(x.b);
+}
+
+fn move_after_fu_move() {
+    let x = B { a: Box::new(1), b: Box::new(2) };
+    let y = B { a: Box::new(3), .. x };
+    drop(x.a);
+}
+
+fn fu_move_after_move() {
+    let x = B { a: Box::new(1), b: Box::new(2) };
+    drop(x.a);
+    let z = B { a: Box::new(3), .. x };
+    drop(z.b);
+}
+
+fn fu_move_after_fu_move() {
+    let x = B { a: Box::new(1), b: Box::new(2) };
+    let _y = B { b: Box::new(3), .. x };
+    let _z = B { a: Box::new(4), .. x };
+}
+
+fn copy_after_assign_after_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    x = A { a: 3, b: Box::new(4) };
+    drop(*x.b);
+}
+
+fn copy_after_assign_after_fu_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    x = A { a: 3, b: Box::new(4) };
+    drop(*x.b);
+}
+
+fn copy_after_field_assign_after_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    x.b = Box::new(3);
+    drop(*x.b);
+}
+
+fn copy_after_field_assign_after_fu_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    x.b = Box::new(3);
+    drop(*x.b);
+}
+
+fn borrow_after_assign_after_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    x = A { a: 3, b: Box::new(4) };
+    let p = &x.b;
+    drop(**p);
+}
+
+fn borrow_after_assign_after_fu_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    x = A { a: 3, b: Box::new(4) };
+    let p = &x.b;
+    drop(**p);
+}
+
+fn borrow_after_field_assign_after_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    x.b = Box::new(3);
+    let p = &x.b;
+    drop(**p);
+}
+
+fn borrow_after_field_assign_after_fu_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    x.b = Box::new(3);
+    let p = &x.b;
+    drop(**p);
+}
+
+fn move_after_assign_after_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let _y = x.b;
+    x = A { a: 3, b: Box::new(4) };
+    drop(x.b);
+}
+
+fn move_after_assign_after_fu_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    x = A { a: 3, b: Box::new(4) };
+    drop(x.b);
+}
+
+fn move_after_field_assign_after_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    x.b = Box::new(3);
+    drop(x.b);
+}
+
+fn move_after_field_assign_after_fu_move() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    x.b = Box::new(3);
+    drop(x.b);
+}
+
+fn copy_after_assign_after_uninit() {
+    let mut x: A;
+    x = A { a: 1, b: Box::new(2) };
+    drop(x.a);
+}
+
+fn borrow_after_assign_after_uninit() {
+    let mut x: A;
+    x = A { a: 1, b: Box::new(2) };
+    let p = &x.a;
+    drop(*p);
+}
+
+fn move_after_assign_after_uninit() {
+    let mut x: A;
+    x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+}
+
+fn main() {
+    move_after_copy();
+    move_after_fu_copy();
+    fu_move_after_copy();
+    fu_move_after_fu_copy();
+    copy_after_move();
+    copy_after_fu_move();
+    fu_copy_after_move();
+    fu_copy_after_fu_move();
+
+    borrow_after_move();
+    borrow_after_fu_move();
+    move_after_borrow();
+    fu_move_after_borrow();
+    mut_borrow_after_mut_borrow();
+
+    move_after_move();
+    move_after_fu_move();
+    fu_move_after_move();
+    fu_move_after_fu_move();
+
+    copy_after_assign_after_move();
+    copy_after_assign_after_fu_move();
+    copy_after_field_assign_after_move();
+    copy_after_field_assign_after_fu_move();
+
+    borrow_after_assign_after_move();
+    borrow_after_assign_after_fu_move();
+    borrow_after_field_assign_after_move();
+    borrow_after_field_assign_after_fu_move();
+
+    move_after_assign_after_move();
+    move_after_assign_after_fu_move();
+    move_after_field_assign_after_move();
+    move_after_field_assign_after_fu_move();
+
+    copy_after_assign_after_uninit();
+    borrow_after_assign_after_uninit();
+    move_after_assign_after_uninit();
+}
diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.rs b/tests/ui/borrowck/borrowck-field-sensitivity.rs
new file mode 100644
index 00000000000..03edf445ee9
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-field-sensitivity.rs
@@ -0,0 +1,116 @@
+struct A { a: isize, b: Box<isize> }
+
+
+
+fn deref_after_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    drop(*x.b); //~ ERROR use of moved value: `x.b`
+}
+
+fn deref_after_fu_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    let y = A { a: 3, .. x };
+    drop(*x.b); //~ ERROR use of moved value: `x.b`
+}
+
+fn borrow_after_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    let p = &x.b; //~ ERROR borrow of moved value: `x.b`
+    drop(**p);
+}
+
+fn borrow_after_fu_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    let p = &x.b; //~ ERROR borrow of moved value: `x.b`
+    drop(**p);
+}
+
+fn move_after_borrow() {
+    let x = A { a: 1, b: Box::new(2) };
+    let p = &x.b;
+    drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed
+    drop(**p);
+}
+
+fn fu_move_after_borrow() {
+    let x = A { a: 1, b: Box::new(2) };
+    let p = &x.b;
+    let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed
+    drop(**p);
+}
+
+fn mut_borrow_after_mut_borrow() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let p = &mut x.a;
+    let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time
+    drop(*p);
+    drop(*q);
+}
+
+fn move_after_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    drop(x.b);  //~ ERROR use of moved value: `x.b`
+}
+
+fn move_after_fu_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    drop(x.b);  //~ ERROR use of moved value: `x.b`
+}
+
+fn fu_move_after_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    drop(x.b);
+    let _z = A { a: 3, .. x };  //~ ERROR use of moved value: `x.b`
+}
+
+fn fu_move_after_fu_move() {
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { a: 3, .. x };
+    let _z = A { a: 4, .. x };  //~ ERROR use of moved value: `x.b`
+}
+
+// The following functions aren't yet accepted, but they should be.
+
+fn copy_after_field_assign_after_uninit() {
+    let mut x: A;
+    x.a = 1; //~ ERROR E0381
+    drop(x.a);
+}
+
+fn borrow_after_field_assign_after_uninit() {
+    let mut x: A;
+    x.a = 1; //~ ERROR E0381
+    let p = &x.a;
+    drop(*p);
+}
+
+fn move_after_field_assign_after_uninit() {
+    let mut x: A;
+    x.b = Box::new(1); //~ ERROR E0381
+    drop(x.b);
+}
+
+fn main() {
+    deref_after_move();
+    deref_after_fu_move();
+
+    borrow_after_move();
+    borrow_after_fu_move();
+    move_after_borrow();
+    fu_move_after_borrow();
+    mut_borrow_after_mut_borrow();
+
+    move_after_move();
+    move_after_fu_move();
+    fu_move_after_move();
+    fu_move_after_fu_move();
+
+    copy_after_field_assign_after_uninit();
+    borrow_after_field_assign_after_uninit();
+    move_after_field_assign_after_uninit();
+}
diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.stderr b/tests/ui/borrowck/borrowck-field-sensitivity.stderr
new file mode 100644
index 00000000000..e009f5913ed
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-field-sensitivity.stderr
@@ -0,0 +1,144 @@
+error[E0382]: use of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:8:10
+   |
+LL |     drop(x.b);
+   |          --- value moved here
+LL |     drop(*x.b);
+   |          ^^^^ value used here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:14:10
+   |
+LL |     let y = A { a: 3, .. x };
+   |             ---------------- value moved here
+LL |     drop(*x.b);
+   |          ^^^^ value used here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:20:13
+   |
+LL |     drop(x.b);
+   |          --- value moved here
+LL |     let p = &x.b;
+   |             ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:27:13
+   |
+LL |     let _y = A { a: 3, .. x };
+   |              ---------------- value moved here
+LL |     let p = &x.b;
+   |             ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0505]: cannot move out of `x.b` because it is borrowed
+  --> $DIR/borrowck-field-sensitivity.rs:34:10
+   |
+LL |     let p = &x.b;
+   |             ---- borrow of `x.b` occurs here
+LL |     drop(x.b);
+   |          ^^^ move out of `x.b` occurs here
+LL |     drop(**p);
+   |          --- borrow later used here
+
+error[E0505]: cannot move out of `x.b` because it is borrowed
+  --> $DIR/borrowck-field-sensitivity.rs:41:14
+   |
+LL |     let p = &x.b;
+   |             ---- borrow of `x.b` occurs here
+LL |     let _y = A { a: 3, .. x };
+   |              ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here
+LL |     drop(**p);
+   |          --- borrow later used here
+
+error[E0499]: cannot borrow `x.a` as mutable more than once at a time
+  --> $DIR/borrowck-field-sensitivity.rs:48:13
+   |
+LL |     let p = &mut x.a;
+   |             -------- first mutable borrow occurs here
+LL |     let q = &mut x.a;
+   |             ^^^^^^^^ second mutable borrow occurs here
+LL |     drop(*p);
+   |          -- first borrow later used here
+
+error[E0382]: use of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:56:10
+   |
+LL |     drop(x.b);
+   |          --- value moved here
+LL |     drop(x.b);
+   |          ^^^ value used here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:62:10
+   |
+LL |     let _y = A { a: 3, .. x };
+   |              ---------------- value moved here
+LL |     drop(x.b);
+   |          ^^^ value used here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:68:14
+   |
+LL |     drop(x.b);
+   |          --- value moved here
+LL |     let _z = A { a: 3, .. x };
+   |              ^^^^^^^^^^^^^^^^ value used here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x.b`
+  --> $DIR/borrowck-field-sensitivity.rs:74:14
+   |
+LL |     let _y = A { a: 3, .. x };
+   |              ---------------- value moved here
+LL |     let _z = A { a: 4, .. x };
+   |              ^^^^^^^^^^^^^^^^ value used here after move
+   |
+   = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/borrowck-field-sensitivity.rs:81:5
+   |
+LL |     let mut x: A;
+   |         ----- binding declared here but left uninitialized
+LL |     x.a = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/borrowck-field-sensitivity.rs:87:5
+   |
+LL |     let mut x: A;
+   |         ----- binding declared here but left uninitialized
+LL |     x.a = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/borrowck-field-sensitivity.rs:94:5
+   |
+LL |     let mut x: A;
+   |         ----- binding declared here but left uninitialized
+LL |     x.b = Box::new(1);
+   |     ^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0381, E0382, E0499, E0505.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-fixed-length-vecs.rs b/tests/ui/borrowck/borrowck-fixed-length-vecs.rs
new file mode 100644
index 00000000000..126323d8d24
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-fixed-length-vecs.rs
@@ -0,0 +1,7 @@
+// run-pass
+
+pub fn main() {
+    let x = [22];
+    let y = &x[0];
+    assert_eq!(*y, 22);
+}
diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.rs b/tests/ui/borrowck/borrowck-fn-in-const-a.rs
new file mode 100644
index 00000000000..d4ceae2963b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-fn-in-const-a.rs
@@ -0,0 +1,12 @@
+// Check that we check fns appearing in constant declarations.
+// Issue #22382.
+
+const MOVE: fn(&String) -> String = {
+    fn broken(x: &String) -> String {
+        return *x //~ ERROR cannot move
+    }
+    broken
+};
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.stderr b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr
new file mode 100644
index 00000000000..e7491afdad1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr
@@ -0,0 +1,9 @@
+error[E0507]: cannot move out of `*x` which is behind a shared reference
+  --> $DIR/borrowck-fn-in-const-a.rs:6:16
+   |
+LL |         return *x
+   |                ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-fn-in-const-c.rs b/tests/ui/borrowck/borrowck-fn-in-const-c.rs
new file mode 100644
index 00000000000..c638cd08bc9
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-fn-in-const-c.rs
@@ -0,0 +1,23 @@
+// Check that we check fns appearing in constant declarations.
+// Issue #22382.
+
+// Returning local references?
+struct DropString {
+    inner: String
+}
+impl Drop for DropString {
+    fn drop(&mut self) {
+        self.inner.clear();
+        self.inner.push_str("dropped");
+    }
+}
+const LOCAL_REF: fn() -> &'static str = {
+    fn broken() -> &'static str {
+        let local = DropString { inner: format!("Some local string") };
+        return &local.inner; //~ borrow may still be in use when destructor runs
+    }
+    broken
+};
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-fn-in-const-c.stderr b/tests/ui/borrowck/borrowck-fn-in-const-c.stderr
new file mode 100644
index 00000000000..d48866dce04
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-fn-in-const-c.stderr
@@ -0,0 +1,11 @@
+error[E0713]: borrow may still be in use when destructor runs
+  --> $DIR/borrowck-fn-in-const-c.rs:17:16
+   |
+LL |         return &local.inner;
+   |                ^^^^^^^^^^^^ returning this value requires that `local.inner` is borrowed for `'static`
+LL |     }
+   |     - here, drop of `local` needs exclusive access to `local.inner`, because the type `DropString` implements the `Drop` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0713`.
diff --git a/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs
new file mode 100644
index 00000000000..389b8a43c05
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs
@@ -0,0 +1,24 @@
+// Issue #16205.
+
+
+
+struct Foo {
+    a: [Box<isize>; 3],
+}
+
+fn main() {
+    let mut y = 1;
+    let x = Some(&mut y);
+    for &a in x.iter() {    //~ ERROR cannot move out
+    }
+
+    let f = Foo {
+        a: [Box::new(3), Box::new(4), Box::new(5)],
+    };
+    for &a in &f.a {  //~ ERROR cannot move out
+    }
+
+    let x: Option<Box<_>> = Some(Box::new(1));
+    for &a in x.iter() {    //~ ERROR cannot move out
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr
new file mode 100644
index 00000000000..f9ced03e0f0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr
@@ -0,0 +1,48 @@
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:15
+   |
+LL |     for &a in x.iter() {
+   |          -    ^^^^^^^^
+   |          |
+   |          data moved here
+   |          move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     for &a in x.iter() {
+LL +     for a in x.iter() {
+   |
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:15
+   |
+LL |     for &a in &f.a {
+   |          -    ^^^^
+   |          |
+   |          data moved here
+   |          move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     for &a in &f.a {
+LL +     for a in &f.a {
+   |
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15
+   |
+LL |     for &a in x.iter() {
+   |          -    ^^^^^^^^
+   |          |
+   |          data moved here
+   |          move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     for &a in x.iter() {
+LL +     for a in x.iter() {
+   |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-for-loop-head-linkage.rs b/tests/ui/borrowck/borrowck-for-loop-head-linkage.rs
new file mode 100644
index 00000000000..a84b695aafb
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-for-loop-head-linkage.rs
@@ -0,0 +1,10 @@
+use std::iter::repeat;
+
+fn main() {
+    let mut vector = vec![1, 2];
+    for &x in &vector {
+        let cap = vector.capacity();
+        vector.extend(repeat(0));      //~ ERROR cannot borrow
+        vector[1] = 5;   //~ ERROR cannot borrow
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-for-loop-head-linkage.stderr b/tests/ui/borrowck/borrowck-for-loop-head-linkage.stderr
new file mode 100644
index 00000000000..f47dce45369
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-for-loop-head-linkage.stderr
@@ -0,0 +1,27 @@
+error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-for-loop-head-linkage.rs:7:9
+   |
+LL |     for &x in &vector {
+   |               -------
+   |               |
+   |               immutable borrow occurs here
+   |               immutable borrow later used here
+LL |         let cap = vector.capacity();
+LL |         vector.extend(repeat(0));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+
+error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-for-loop-head-linkage.rs:8:9
+   |
+LL |     for &x in &vector {
+   |               -------
+   |               |
+   |               immutable borrow occurs here
+   |               immutable borrow later used here
+...
+LL |         vector[1] = 5;
+   |         ^^^^^^ mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs
new file mode 100644
index 00000000000..f619c045b25
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs
@@ -0,0 +1,7 @@
+fn f() -> isize {
+    let mut x: isize;
+    for _ in 0..0 { x = 10; }
+    return x; //~ ERROR E0381
+}
+
+fn main() { f(); }
diff --git a/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
new file mode 100644
index 00000000000..fc1a44c3ca0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
@@ -0,0 +1,13 @@
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/borrowck-for-loop-uninitialized-binding.rs:4:12
+   |
+LL |     let mut x: isize;
+   |         ----- binding declared here but left uninitialized
+LL |     for _ in 0..0 { x = 10; }
+   |              ---- if the `for` loop runs 0 times, `x` is not initialized
+LL |     return x;
+   |            ^ `x` used here but it is possibly-uninitialized
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-freeze-frozen-mut.rs b/tests/ui/borrowck/borrowck-freeze-frozen-mut.rs
new file mode 100644
index 00000000000..199931d6d1e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-freeze-frozen-mut.rs
@@ -0,0 +1,28 @@
+// run-pass
+// Test that a `&mut` inside of an `&` is freezable.
+
+
+struct MutSlice<'a, T:'a> {
+    data: &'a mut [T]
+}
+
+fn get<'a, T>(ms: &'a MutSlice<'a, T>, index: usize) -> &'a T {
+    &ms.data[index]
+}
+
+pub fn main() {
+    let mut data = [1, 2, 3];
+    {
+        let slice = MutSlice { data: &mut data };
+        slice.data[0] += 4;
+        let index0 = get(&slice, 0);
+        let index1 = get(&slice, 1);
+        let index2 = get(&slice, 2);
+        assert_eq!(*index0, 5);
+        assert_eq!(*index1, 2);
+        assert_eq!(*index2, 3);
+    }
+    assert_eq!(data[0], 5);
+    assert_eq!(data[1], 2);
+    assert_eq!(data[2], 3);
+}
diff --git a/tests/ui/borrowck/borrowck-if-no-else.rs b/tests/ui/borrowck/borrowck-if-no-else.rs
new file mode 100644
index 00000000000..534d771be1d
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-if-no-else.rs
@@ -0,0 +1,6 @@
+fn foo(x: isize) { println!("{}", x); }
+
+fn main() {
+    let x: isize; if 1 > 2 { x = 10; }
+    foo(x); //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-if-no-else.stderr b/tests/ui/borrowck/borrowck-if-no-else.stderr
new file mode 100644
index 00000000000..9eafc2c2a86
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-if-no-else.stderr
@@ -0,0 +1,14 @@
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/borrowck-if-no-else.rs:5:9
+   |
+LL |     let x: isize; if 1 > 2 { x = 10; }
+   |         -            -----            - an `else` arm might be missing here, initializing `x`
+   |         |            |
+   |         |            if this `if` condition is `false`, `x` is not initialized
+   |         binding declared here but left uninitialized
+LL |     foo(x);
+   |         ^ `x` used here but it is possibly-uninitialized
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-if-with-else.rs b/tests/ui/borrowck/borrowck-if-with-else.rs
new file mode 100644
index 00000000000..69d450c5989
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-if-with-else.rs
@@ -0,0 +1,11 @@
+fn foo(x: isize) { println!("{}", x); }
+
+fn main() {
+    let x: isize;
+    if 1 > 2 {
+        println!("whoops");
+    } else {
+        x = 10;
+    }
+    foo(x); //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-if-with-else.stderr b/tests/ui/borrowck/borrowck-if-with-else.stderr
new file mode 100644
index 00000000000..3f0fe291ca2
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-if-with-else.stderr
@@ -0,0 +1,14 @@
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/borrowck-if-with-else.rs:10:9
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     if 1 > 2 {
+   |        ----- if this condition is `true`, `x` is not initialized
+...
+LL |     foo(x);
+   |         ^ `x` used here but it is possibly-uninitialized
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs
new file mode 100644
index 00000000000..97107c2e30f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs
@@ -0,0 +1,10 @@
+fn main() {
+    let mut _a = 3;
+    let b = &mut _a;
+    {
+        let c = &*b;
+        _a = 4; //~ ERROR cannot assign to `_a` because it is borrowed
+        drop(c);
+    }
+    drop(b);
+}
diff --git a/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr
new file mode 100644
index 00000000000..a66db05ccc5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `_a` because it is borrowed
+  --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:6:9
+   |
+LL |     let b = &mut _a;
+   |             ------- borrow of `_a` occurs here
+...
+LL |         _a = 4;
+   |         ^^^^^^ assignment to borrowed `_a` occurs here
+...
+LL |     drop(b);
+   |          - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-in-static.rs b/tests/ui/borrowck/borrowck-in-static.rs
new file mode 100644
index 00000000000..a45f7b18e07
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-in-static.rs
@@ -0,0 +1,12 @@
+// check that borrowck looks inside consts/statics
+
+static FN : &'static (dyn Fn() -> (Box<dyn Fn()->Box<i32>>) + Sync) = &|| {
+    let x = Box::new(0);
+    Box::new(|| x) //~ ERROR cannot move out of `x`, a captured variable in an `Fn` closure
+};
+
+fn main() {
+    let f = (FN)();
+    f();
+    f();
+}
diff --git a/tests/ui/borrowck/borrowck-in-static.stderr b/tests/ui/borrowck/borrowck-in-static.stderr
new file mode 100644
index 00000000000..2033e4a5730
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-in-static.stderr
@@ -0,0 +1,13 @@
+error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
+  --> $DIR/borrowck-in-static.rs:5:17
+   |
+LL |     let x = Box::new(0);
+   |         - captured outer variable
+LL |     Box::new(|| x)
+   |              -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |              |
+   |              captured by this `Fn` closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.rs b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.rs
new file mode 100644
index 00000000000..e6476b9c1be
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let j = || -> isize {
+        let i: isize;
+        i //~ ERROR E0381
+    };
+    j();
+}
diff --git a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
new file mode 100644
index 00000000000..1a22b5f0975
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `i` isn't initialized
+  --> $DIR/borrowck-init-in-called-fn-expr.rs:4:9
+   |
+LL |         let i: isize;
+   |             - binding declared here but left uninitialized
+LL |         i
+   |         ^ `i` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let i: isize = 0;
+   |                      +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-init-in-fn-expr.rs b/tests/ui/borrowck/borrowck-init-in-fn-expr.rs
new file mode 100644
index 00000000000..7eb204a0d16
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-in-fn-expr.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let f  = || -> isize {
+        let i: isize;
+        i //~ ERROR E0381
+    };
+    println!("{}", f());
+}
diff --git a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
new file mode 100644
index 00000000000..f1b9b9aa709
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `i` isn't initialized
+  --> $DIR/borrowck-init-in-fn-expr.rs:4:9
+   |
+LL |         let i: isize;
+   |             - binding declared here but left uninitialized
+LL |         i
+   |         ^ `i` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let i: isize = 0;
+   |                      +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-init-in-fru.rs b/tests/ui/borrowck/borrowck-init-in-fru.rs
new file mode 100644
index 00000000000..c07957ab139
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-in-fru.rs
@@ -0,0 +1,12 @@
+#[derive(Clone)]
+struct Point {
+    x: isize,
+    y: isize,
+}
+
+fn main() {
+    let mut origin: Point;
+    origin = Point { x: 10, ..origin };
+    //~^ ERROR E0381
+    origin.clone();
+}
diff --git a/tests/ui/borrowck/borrowck-init-in-fru.stderr b/tests/ui/borrowck/borrowck-init-in-fru.stderr
new file mode 100644
index 00000000000..39b28811a0c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-in-fru.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `origin` isn't initialized
+  --> $DIR/borrowck-init-in-fru.rs:9:14
+   |
+LL |     let mut origin: Point;
+   |         ---------- binding declared here but left uninitialized
+LL |     origin = Point { x: 10, ..origin };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ `origin.y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut origin: Point = todo!();
+   |                           +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-init-op-equal.rs b/tests/ui/borrowck/borrowck-init-op-equal.rs
new file mode 100644
index 00000000000..3d08c1b81a7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-op-equal.rs
@@ -0,0 +1,8 @@
+fn test() {
+    let v: isize;
+    v += 1; //~ ERROR E0381
+    v.clone();
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-init-op-equal.stderr b/tests/ui/borrowck/borrowck-init-op-equal.stderr
new file mode 100644
index 00000000000..ef0fa6df4fb
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-op-equal.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `v` isn't initialized
+  --> $DIR/borrowck-init-op-equal.rs:3:5
+   |
+LL |     let v: isize;
+   |         - binding declared here but left uninitialized
+LL |     v += 1;
+   |     ^^^^^^ `v` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let v: isize = 0;
+   |                  +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-init-plus-equal.rs b/tests/ui/borrowck/borrowck-init-plus-equal.rs
new file mode 100644
index 00000000000..2a52a3f4e5e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-plus-equal.rs
@@ -0,0 +1,8 @@
+fn test() {
+    let mut v: isize;
+    v = v + 1; //~ ERROR E0381
+    v.clone();
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-init-plus-equal.stderr b/tests/ui/borrowck/borrowck-init-plus-equal.stderr
new file mode 100644
index 00000000000..cec05331836
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-init-plus-equal.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `v` isn't initialized
+  --> $DIR/borrowck-init-plus-equal.rs:3:9
+   |
+LL |     let mut v: isize;
+   |         ----- binding declared here but left uninitialized
+LL |     v = v + 1;
+   |         ^ `v` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut v: isize = 0;
+   |                      +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-insert-during-each.rs b/tests/ui/borrowck/borrowck-insert-during-each.rs
new file mode 100644
index 00000000000..df967e61189
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-insert-during-each.rs
@@ -0,0 +1,26 @@
+use std::collections::HashSet;
+
+struct Foo {
+  n: HashSet<isize>,
+}
+
+impl Foo {
+    pub fn foo<F>(&mut self, mut fun: F) where F: FnMut(&isize) {
+        for f in &self.n {
+            fun(f);
+        }
+    }
+}
+
+fn bar(f: &mut Foo) {
+    f.foo(
+    //~^ ERROR cannot borrow `*f` as mutable
+        |a| { //~ ERROR closure requires unique access to `f`
+            f.n.insert(*a);
+        })
+}
+
+fn main() {
+  let mut f = Foo { n: HashSet::new() };
+  bar(&mut f);
+}
diff --git a/tests/ui/borrowck/borrowck-insert-during-each.stderr b/tests/ui/borrowck/borrowck-insert-during-each.stderr
new file mode 100644
index 00000000000..99d08e905d5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-insert-during-each.stderr
@@ -0,0 +1,34 @@
+error[E0501]: cannot borrow `*f` as mutable because previous closure requires unique access
+  --> $DIR/borrowck-insert-during-each.rs:16:5
+   |
+LL |       f.foo(
+   |       ^ --- first borrow later used by call
+   |  _____|
+   | |
+LL | |
+LL | |         |a| {
+   | |         --- closure construction occurs here
+LL | |             f.n.insert(*a);
+   | |             --- first borrow occurs due to use of `f` in closure
+LL | |         })
+   | |__________^ second borrow occurs here
+
+error[E0500]: closure requires unique access to `f` but it is already borrowed
+  --> $DIR/borrowck-insert-during-each.rs:18:9
+   |
+LL |       f.foo(
+   |       - --- first borrow later used by call
+   |  _____|
+   | |
+LL | |
+LL | |         |a| {
+   | |         ^^^ closure construction occurs here
+LL | |             f.n.insert(*a);
+   | |             --- second borrow occurs due to use of `f` in closure
+LL | |         })
+   | |__________- borrow occurs here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0500, E0501.
+For more information about an error, try `rustc --explain E0500`.
diff --git a/tests/ui/borrowck/borrowck-issue-14498.rs b/tests/ui/borrowck/borrowck-issue-14498.rs
new file mode 100644
index 00000000000..003533a5184
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-14498.rs
@@ -0,0 +1,110 @@
+// This tests that we can't modify Box<&mut T> contents while they
+// are borrowed (#14498).
+//
+// Also includes tests of the errors reported when the Box in question
+// is immutable (#14270).
+
+
+
+struct A { a: isize }
+struct B<'a> { a: Box<&'a mut isize> }
+
+fn indirect_write_to_imm_box() {
+    let mut x: isize = 1;
+    let y: Box<_> = Box::new(&mut x);
+    let p = &y;
+    ***p = 2; //~ ERROR cannot assign to `***p`
+    drop(p);
+}
+
+fn borrow_in_var_from_var() {
+    let mut x: isize = 1;
+    let mut y: Box<_> = Box::new(&mut x);
+    let p = &y;
+    let q = &***p;
+    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn borrow_in_var_from_var_via_imm_box() {
+    let mut x: isize = 1;
+    let y: Box<_> = Box::new(&mut x);
+    let p = &y;
+    let q = &***p;
+    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn borrow_in_var_from_field() {
+    let mut x = A { a: 1 };
+    let mut y: Box<_> = Box::new(&mut x.a);
+    let p = &y;
+    let q = &***p;
+    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn borrow_in_var_from_field_via_imm_box() {
+    let mut x = A { a: 1 };
+    let y: Box<_> = Box::new(&mut x.a);
+    let p = &y;
+    let q = &***p;
+    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn borrow_in_field_from_var() {
+    let mut x: isize = 1;
+    let mut y = B { a: Box::new(&mut x) };
+    let p = &y.a;
+    let q = &***p;
+    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn borrow_in_field_from_var_via_imm_box() {
+    let mut x: isize = 1;
+    let y = B { a: Box::new(&mut x) };
+    let p = &y.a;
+    let q = &***p;
+    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn borrow_in_field_from_field() {
+    let mut x = A { a: 1 };
+    let mut y = B { a: Box::new(&mut x.a) };
+    let p = &y.a;
+    let q = &***p;
+    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn borrow_in_field_from_field_via_imm_box() {
+    let mut x = A { a: 1 };
+    let y = B { a: Box::new(&mut x.a) };
+    let p = &y.a;
+    let q = &***p;
+    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
+    drop(p);
+    drop(q);
+}
+
+fn main() {
+    indirect_write_to_imm_box();
+    borrow_in_var_from_var();
+    borrow_in_var_from_var_via_imm_box();
+    borrow_in_var_from_field();
+    borrow_in_var_from_field_via_imm_box();
+    borrow_in_field_from_var();
+    borrow_in_field_from_var_via_imm_box();
+    borrow_in_field_from_field();
+    borrow_in_field_from_field_via_imm_box();
+}
diff --git a/tests/ui/borrowck/borrowck-issue-14498.stderr b/tests/ui/borrowck/borrowck-issue-14498.stderr
new file mode 100644
index 00000000000..42a55b7a854
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-14498.stderr
@@ -0,0 +1,103 @@
+error[E0594]: cannot assign to `***p`, which is behind a `&` reference
+  --> $DIR/borrowck-issue-14498.rs:16:5
+   |
+LL |     ***p = 2;
+   |     ^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let p = &mut y;
+   |             ~~~~~~
+
+error[E0506]: cannot assign to `**y` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:25:5
+   |
+LL |     let p = &y;
+   |             -- borrow of `**y` occurs here
+LL |     let q = &***p;
+LL |     **y = 2;
+   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0506]: cannot assign to `**y` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:35:5
+   |
+LL |     let p = &y;
+   |             -- borrow of `**y` occurs here
+LL |     let q = &***p;
+LL |     **y = 2;
+   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0506]: cannot assign to `**y` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:45:5
+   |
+LL |     let p = &y;
+   |             -- borrow of `**y` occurs here
+LL |     let q = &***p;
+LL |     **y = 2;
+   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0506]: cannot assign to `**y` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:55:5
+   |
+LL |     let p = &y;
+   |             -- borrow of `**y` occurs here
+LL |     let q = &***p;
+LL |     **y = 2;
+   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0506]: cannot assign to `**y.a` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:65:5
+   |
+LL |     let p = &y.a;
+   |             ---- borrow of `**y.a` occurs here
+LL |     let q = &***p;
+LL |     **y.a = 2;
+   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0506]: cannot assign to `**y.a` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:75:5
+   |
+LL |     let p = &y.a;
+   |             ---- borrow of `**y.a` occurs here
+LL |     let q = &***p;
+LL |     **y.a = 2;
+   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0506]: cannot assign to `**y.a` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:85:5
+   |
+LL |     let p = &y.a;
+   |             ---- borrow of `**y.a` occurs here
+LL |     let q = &***p;
+LL |     **y.a = 2;
+   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0506]: cannot assign to `**y.a` because it is borrowed
+  --> $DIR/borrowck-issue-14498.rs:95:5
+   |
+LL |     let p = &y.a;
+   |             ---- borrow of `**y.a` occurs here
+LL |     let q = &***p;
+LL |     **y.a = 2;
+   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+LL |     drop(p);
+   |          - borrow later used here
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0506, E0594.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-issue-2657-1.rs b/tests/ui/borrowck/borrowck-issue-2657-1.rs
new file mode 100644
index 00000000000..0fb2267b982
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-2657-1.rs
@@ -0,0 +1,14 @@
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
+
+
+fn main() {
+    let x: Option<Box<_>> = Some(Box::new(1));
+    match x {
+      Some(ref _y) => {
+        let _a = x; //~ ERROR cannot move
+        _y.use_ref();
+      }
+      _ => {}
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-issue-2657-1.stderr b/tests/ui/borrowck/borrowck-issue-2657-1.stderr
new file mode 100644
index 00000000000..390bb9384f8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-2657-1.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/borrowck-issue-2657-1.rs:9:18
+   |
+LL |       Some(ref _y) => {
+   |            ------ borrow of `x.0` occurs here
+LL |         let _a = x;
+   |                  ^ move out of `x` occurs here
+LL |         _y.use_ref();
+   |         ------------ borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.fixed b/tests/ui/borrowck/borrowck-issue-2657-2.fixed
new file mode 100644
index 00000000000..625e7c3cad5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-2657-2.fixed
@@ -0,0 +1,12 @@
+// run-rustfix
+fn main() {
+
+    let x: Option<Box<_>> = Some(Box::new(1));
+
+    match x {
+      Some(ref y) => {
+        let _b = y; //~ ERROR cannot move out
+      }
+      _ => {}
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.rs b/tests/ui/borrowck/borrowck-issue-2657-2.rs
new file mode 100644
index 00000000000..f79a846e70e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-2657-2.rs
@@ -0,0 +1,12 @@
+// run-rustfix
+fn main() {
+
+    let x: Option<Box<_>> = Some(Box::new(1));
+
+    match x {
+      Some(ref y) => {
+        let _b = *y; //~ ERROR cannot move out
+      }
+      _ => {}
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.stderr b/tests/ui/borrowck/borrowck-issue-2657-2.stderr
new file mode 100644
index 00000000000..850bb9ae393
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-2657-2.stderr
@@ -0,0 +1,15 @@
+error[E0507]: cannot move out of `*y` which is behind a shared reference
+  --> $DIR/borrowck-issue-2657-2.rs:8:18
+   |
+LL |         let _b = *y;
+   |                  ^^ move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -         let _b = *y;
+LL +         let _b = y;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-issue-48962.rs b/tests/ui/borrowck/borrowck-issue-48962.rs
new file mode 100644
index 00000000000..86061c8cd6e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-48962.rs
@@ -0,0 +1,26 @@
+struct Node {
+    elem: i32,
+    next: Option<Box<Node>>,
+}
+
+fn a() {
+    let mut node = Node {
+        elem: 5,
+        next: None,
+    };
+
+    let mut src = &mut node;
+    {src};
+    src.next = None; //~ ERROR use of moved value: `src` [E0382]
+}
+
+fn b() {
+    let mut src = &mut (22, 44);
+    {src};
+    src.0 = 66; //~ ERROR use of moved value: `src` [E0382]
+}
+
+fn main() {
+    a();
+    b();
+}
diff --git a/tests/ui/borrowck/borrowck-issue-48962.stderr b/tests/ui/borrowck/borrowck-issue-48962.stderr
new file mode 100644
index 00000000000..ee174f6736e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-issue-48962.stderr
@@ -0,0 +1,23 @@
+error[E0382]: use of moved value: `src`
+  --> $DIR/borrowck-issue-48962.rs:14:5
+   |
+LL |     let mut src = &mut node;
+   |         ------- move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait
+LL |     {src};
+   |      --- value moved here
+LL |     src.next = None;
+   |     ^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `src`
+  --> $DIR/borrowck-issue-48962.rs:20:5
+   |
+LL |     let mut src = &mut (22, 44);
+   |         ------- move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait
+LL |     {src};
+   |      --- value moved here
+LL |     src.0 = 66;
+   |     ^^^^^^^^^^ value used here after move
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-lend-args.rs b/tests/ui/borrowck/borrowck-lend-args.rs
new file mode 100644
index 00000000000..d0ef2dcdd28
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-args.rs
@@ -0,0 +1,21 @@
+// run-pass
+#![allow(dead_code)]
+
+// pretty-expanded FIXME #23616
+
+fn borrow(_v: &isize) {}
+
+fn borrow_from_arg_imm_ref(v: Box<isize>) {
+    borrow(&*v);
+}
+
+fn borrow_from_arg_mut_ref(v: &mut Box<isize>) {
+    borrow(&**v);
+}
+
+fn borrow_from_arg_copy(v: Box<isize>) {
+    borrow(&*v);
+}
+
+pub fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-lend-flow-if.rs b/tests/ui/borrowck/borrowck-lend-flow-if.rs
new file mode 100644
index 00000000000..19a0dd0c6b1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow-if.rs
@@ -0,0 +1,51 @@
+// Note: the borrowck analysis is currently flow-insensitive.
+// Therefore, some of these errors are marked as spurious and could be
+// corrected by a simple change to the analysis.  The others are
+// either genuine or would require more advanced changes.  The latter
+// cases are noted.
+
+
+
+fn borrow(_v: &isize) {}
+fn borrow_mut(_v: &mut isize) {}
+fn cond() -> bool { panic!() }
+fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() }
+fn produce<T>() -> T { panic!(); }
+
+fn inc(v: &mut Box<isize>) {
+    *v = Box::new(**v + 1);
+}
+
+fn pre_freeze_cond() {
+    // In this instance, the freeze is conditional and starts before
+    // the mut borrow.
+
+    let u = Box::new(0);
+    let mut v: Box<_> = Box::new(3);
+    let mut _w = &u;
+    if cond() {
+        _w = &v;
+    }
+    borrow_mut(&mut *v); //~ ERROR cannot borrow
+    _w.use_ref();
+}
+
+fn pre_freeze_else() {
+    // In this instance, the freeze and mut borrow are on separate sides
+    // of the if.
+
+    let u = Box::new(0);
+    let mut v: Box<_> = Box::new(3);
+    let mut _w = &u;
+    if cond() {
+        _w = &v;
+    } else {
+        borrow_mut(&mut *v);
+    }
+    _w.use_ref();
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-lend-flow-if.stderr b/tests/ui/borrowck/borrowck-lend-flow-if.stderr
new file mode 100644
index 00000000000..e47efc0e0b3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow-if.stderr
@@ -0,0 +1,14 @@
+error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-lend-flow-if.rs:29:16
+   |
+LL |         _w = &v;
+   |              -- immutable borrow occurs here
+LL |     }
+LL |     borrow_mut(&mut *v);
+   |                ^^^^^^^ mutable borrow occurs here
+LL |     _w.use_ref();
+   |     ------------ immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-lend-flow-loop.rs b/tests/ui/borrowck/borrowck-lend-flow-loop.rs
new file mode 100644
index 00000000000..548ffbd515e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow-loop.rs
@@ -0,0 +1,132 @@
+fn borrow(_v: &isize) {}
+fn borrow_mut(_v: &mut isize) {}
+fn cond() -> bool { panic!() }
+fn produce<T>() -> T { panic!(); }
+
+
+fn inc(v: &mut Box<isize>) {
+    *v = Box::new(**v + 1);
+}
+
+
+fn loop_overarching_alias_mut() {
+    // In this instance, the borrow ends on the line before the loop
+
+    let mut v: Box<_> = Box::new(3);
+    let mut x = &mut v;
+    **x += 1;
+    loop {
+        borrow(&*v); // OK
+    }
+}
+
+fn block_overarching_alias_mut() {
+    // In this instance, the borrow encompasses the entire closure call.
+
+    let mut v: Box<_> = Box::new(3);
+    let mut x = &mut v;
+    for _ in 0..3 {
+        borrow(&*v); //~ ERROR cannot borrow
+    }
+    *x = Box::new(5);
+}
+fn loop_aliased_mut() {
+    // In this instance, the borrow ends right after each assignment to _x
+
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
+    let mut _x = &w;
+    loop {
+        borrow_mut(&mut *v); // OK
+        _x = &v;
+    }
+}
+
+fn while_aliased_mut() {
+    // In this instance, the borrow ends right after each assignment to _x
+
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
+    let mut _x = &w;
+    while cond() {
+        borrow_mut(&mut *v); // OK
+        _x = &v;
+    }
+}
+
+
+fn loop_aliased_mut_break() {
+    // In this instance, the borrow ends right after each assignment to _x
+
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
+    let mut _x = &w;
+    loop {
+        borrow_mut(&mut *v);
+        _x = &v;
+        break;
+    }
+    borrow_mut(&mut *v); // OK
+}
+
+fn while_aliased_mut_break() {
+    // In this instance, the borrow ends right after each assignment to _x
+
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
+    let mut _x = &w;
+    while cond() {
+        borrow_mut(&mut *v);
+        _x = &v;
+        break;
+    }
+    borrow_mut(&mut *v); // OK
+}
+
+fn while_aliased_mut_cond(cond: bool, cond2: bool) {
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
+    let mut x = &mut w;
+    while cond {
+        **x += 1;
+        borrow(&*v); //~ ERROR cannot borrow
+        if cond2 {
+            x = &mut v; // OK
+        }
+    }
+}
+fn loop_break_pops_scopes<'r, F>(_v: &'r mut [usize], mut f: F) where
+    F: FnMut(&'r mut usize) -> bool,
+{
+    // Here we check that when you break out of an inner loop, the
+    // borrows that go out of scope as you exit the inner loop are
+    // removed from the bitset.
+
+    while cond() {
+        while cond() {
+            // this borrow is limited to the scope of `r`...
+            let r: &'r mut usize = produce();
+            if !f(&mut *r) {
+                break; // ...so it is not live as exit the `while` loop here
+            }
+        }
+    }
+}
+
+fn loop_loop_pops_scopes<'r, F>(_v: &'r mut [usize], mut f: F)
+    where F: FnMut(&'r mut usize) -> bool
+{
+    // Similar to `loop_break_pops_scopes` but for the `loop` keyword
+
+    while cond() {
+        while cond() {
+            // this borrow is limited to the scope of `r`...
+            let r: &'r mut usize = produce();
+            if !f(&mut *r) {
+                continue; // ...so it is not live as exit (and re-enter) the `while` loop here
+            }
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-lend-flow-loop.stderr b/tests/ui/borrowck/borrowck-lend-flow-loop.stderr
new file mode 100644
index 00000000000..df7c86b8562
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow-loop.stderr
@@ -0,0 +1,26 @@
+error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-lend-flow-loop.rs:29:16
+   |
+LL |     let mut x = &mut v;
+   |                 ------ mutable borrow occurs here
+LL |     for _ in 0..3 {
+LL |         borrow(&*v);
+   |                ^^^ immutable borrow occurs here
+LL |     }
+LL |     *x = Box::new(5);
+   |     -- mutable borrow later used here
+
+error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-lend-flow-loop.rs:92:16
+   |
+LL |         **x += 1;
+   |         -------- mutable borrow later used here
+LL |         borrow(&*v);
+   |                ^^^ immutable borrow occurs here
+LL |         if cond2 {
+LL |             x = &mut v; // OK
+   |                 ------ mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-lend-flow-match.rs b/tests/ui/borrowck/borrowck-lend-flow-match.rs
new file mode 100644
index 00000000000..9737bc7695d
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow-match.rs
@@ -0,0 +1,18 @@
+fn separate_arms() {
+    // Here both arms perform assignments, but only one is illegal.
+
+    let mut x = None;
+    match x {
+        None => {
+            // It is ok to reassign x here, because there is in
+            // fact no outstanding loan of x!
+            x = Some(0);
+        }
+        Some(ref r) => {
+            x = Some(1); //~ ERROR cannot assign to `x` because it is borrowed
+            drop(r);
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-lend-flow-match.stderr b/tests/ui/borrowck/borrowck-lend-flow-match.stderr
new file mode 100644
index 00000000000..66f1cd9bd56
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow-match.stderr
@@ -0,0 +1,13 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/borrowck-lend-flow-match.rs:12:13
+   |
+LL |         Some(ref r) => {
+   |              ----- borrow of `x` occurs here
+LL |             x = Some(1);
+   |             ^^^^^^^^^^^ assignment to borrowed `x` occurs here
+LL |             drop(r);
+   |                  - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-lend-flow.rs b/tests/ui/borrowck/borrowck-lend-flow.rs
new file mode 100644
index 00000000000..564c57044a3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow.rs
@@ -0,0 +1,39 @@
+// Note: the borrowck analysis is currently flow-insensitive.
+// Therefore, some of these errors are marked as spurious and could be
+// corrected by a simple change to the analysis.  The others are
+// either genuine or would require more advanced changes.  The latter
+// cases are noted.
+
+
+
+fn borrow(_v: &isize) {}
+fn borrow_mut(_v: &mut isize) {}
+fn cond() -> bool { panic!() }
+fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() }
+fn produce<T>() -> T { panic!(); }
+
+fn inc(v: &mut Box<isize>) {
+    *v = Box::new(**v + 1);
+}
+
+fn pre_freeze() {
+    // In this instance, the freeze starts before the mut borrow.
+
+    let mut v: Box<_> = Box::new(3);
+    let _w = &v;
+    borrow_mut(&mut *v); //~ ERROR cannot borrow
+    _w.use_ref();
+}
+
+fn post_freeze() {
+    // In this instance, the const alias starts after the borrow.
+
+    let mut v: Box<_> = Box::new(3);
+    borrow_mut(&mut *v);
+    let _w = &v;
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-lend-flow.stderr b/tests/ui/borrowck/borrowck-lend-flow.stderr
new file mode 100644
index 00000000000..40c14f54cb8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-lend-flow.stderr
@@ -0,0 +1,13 @@
+error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-lend-flow.rs:24:16
+   |
+LL |     let _w = &v;
+   |              -- immutable borrow occurs here
+LL |     borrow_mut(&mut *v);
+   |                ^^^^^^^ mutable borrow occurs here
+LL |     _w.use_ref();
+   |     ------------ immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.rs b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.rs
new file mode 100644
index 00000000000..e536d404099
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.rs
@@ -0,0 +1,35 @@
+use std::thread;
+
+
+
+fn borrow<F>(v: &isize, f: F) where F: FnOnce(&isize) {
+    f(v);
+}
+
+
+
+fn box_imm() {
+    let v: Box<_> = Box::new(3);
+    let w = &v;
+    thread::spawn(move|| {
+    //~^ ERROR cannot move out of `v` because it is borrowed
+        println!("v={}", *v);
+    });
+    w.use_ref();
+}
+
+fn box_imm_explicit() {
+    let v: Box<_> = Box::new(3);
+    let w = &v;
+    thread::spawn(move|| {
+    //~^ ERROR cannot move
+        println!("v={}", *v);
+    });
+    w.use_ref();
+}
+
+fn main() {
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
new file mode 100644
index 00000000000..3548da35b61
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
@@ -0,0 +1,31 @@
+error[E0505]: cannot move out of `v` because it is borrowed
+  --> $DIR/borrowck-loan-blocks-move-cc.rs:14:19
+   |
+LL |     let w = &v;
+   |             -- borrow of `v` occurs here
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ move out of `v` occurs here
+LL |
+LL |         println!("v={}", *v);
+   |                          -- move occurs due to use in closure
+LL |     });
+LL |     w.use_ref();
+   |     ----------- borrow later used here
+
+error[E0505]: cannot move out of `v` because it is borrowed
+  --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
+   |
+LL |     let w = &v;
+   |             -- borrow of `v` occurs here
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ move out of `v` occurs here
+LL |
+LL |         println!("v={}", *v);
+   |                          -- move occurs due to use in closure
+LL |     });
+LL |     w.use_ref();
+   |     ----------- borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.rs b/tests/ui/borrowck/borrowck-loan-blocks-move.rs
new file mode 100644
index 00000000000..f3f443721b5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move.rs
@@ -0,0 +1,19 @@
+fn take(_v: Box<isize>) {
+}
+
+
+
+
+
+fn box_imm() {
+    let v = Box::new(3);
+    let w = &v;
+    take(v); //~ ERROR cannot move out of `v` because it is borrowed
+    w.use_ref();
+}
+
+fn main() {
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
new file mode 100644
index 00000000000..b5c6b101f76
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `v` because it is borrowed
+  --> $DIR/borrowck-loan-blocks-move.rs:11:10
+   |
+LL |     let w = &v;
+   |             -- borrow of `v` occurs here
+LL |     take(v);
+   |          ^ move out of `v` occurs here
+LL |     w.use_ref();
+   |     ----------- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs
new file mode 100644
index 00000000000..33d6af30310
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs
@@ -0,0 +1,18 @@
+fn borrow<F>(v: &isize, f: F) where F: FnOnce(&isize) {
+    f(v);
+}
+
+
+
+fn box_imm() {
+    let mut v: Box<_> = Box::new(3);
+    borrow(&*v,
+           |w| { //~ ERROR cannot borrow `v` as mutable
+            v = Box::new(4);
+            assert_eq!(*v, 3);
+            assert_eq!(*w, 4);
+        })
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr
new file mode 100644
index 00000000000..fa5308c2903
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-loan-blocks-mut-uniq.rs:10:12
+   |
+LL |     borrow(&*v,
+   |     ------ --- immutable borrow occurs here
+   |     |
+   |     immutable borrow later used by call
+LL |            |w| {
+   |            ^^^ mutable borrow occurs here
+LL |             v = Box::new(4);
+   |             - second borrow occurs due to use of `v` in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-loan-in-overloaded-op.rs b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.rs
new file mode 100644
index 00000000000..b8f1650fcdc
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.rs
@@ -0,0 +1,23 @@
+#![feature(box_patterns)]
+
+
+use std::ops::Add;
+
+#[derive(Clone)]
+struct Foo(Box<usize>);
+
+impl Add for Foo {
+    type Output = Foo;
+
+    fn add(self, f: Foo) -> Foo {
+        let Foo(box i) = self;
+        let Foo(box j) = f;
+        Foo(Box::new(i + j))
+    }
+}
+
+fn main() {
+    let x = Foo(Box::new(3));
+    let _y = {x} + x.clone(); // the `{x}` forces a move to occur
+    //~^ ERROR borrow of moved value: `x`
+}
diff --git a/tests/ui/borrowck/borrowck-loan-in-overloaded-op.stderr b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
new file mode 100644
index 00000000000..e1b99162088
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
@@ -0,0 +1,18 @@
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/borrowck-loan-in-overloaded-op.rs:21:20
+   |
+LL |     let x = Foo(Box::new(3));
+   |         - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
+LL |     let _y = {x} + x.clone(); // the `{x}` forces a move to occur
+   |               -    ^^^^^^^^^ value borrowed here after move
+   |               |
+   |               value moved here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = {x.clone()} + x.clone(); // the `{x}` forces a move to occur
+   |                ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.rs b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.rs
new file mode 100644
index 00000000000..cb801ef1b5b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.rs
@@ -0,0 +1,24 @@
+use std::mem;
+
+fn leak<T>(mut b: Box<T>) -> &'static mut T {
+    // isn't this supposed to be safe?
+    let inner = &mut *b as *mut _;
+    mem::forget(b);
+    unsafe { &mut *inner }
+}
+
+fn evil(mut s: &'static mut String)
+{
+    // create alias
+    let alias: &'static mut String = s;
+    let inner: &str = &alias;
+    // free value
+    *s = String::new(); //~ ERROR cannot assign
+    let _spray = "0wned".to_owned();
+    // ... and then use it
+    println!("{}", inner);
+}
+
+fn main() {
+    evil(leak(Box::new("hello".to_owned())));
+}
diff --git a/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr
new file mode 100644
index 00000000000..6994c837dfc
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `*s` because it is borrowed
+  --> $DIR/borrowck-loan-of-static-data-issue-27616.rs:16:5
+   |
+LL |     let alias: &'static mut String = s;
+   |                -------------------   - borrow of `*s` occurs here
+   |                |
+   |                type annotation requires that `*s` is borrowed for `'static`
+...
+LL |     *s = String::new();
+   |     ^^ assignment to borrowed `*s` occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.rs b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.rs
new file mode 100644
index 00000000000..4da10fd44ce
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.rs
@@ -0,0 +1,46 @@
+use std::ops::Add;
+
+#[derive(Copy, Clone)]
+struct Point {
+    x: isize,
+    y: isize,
+}
+
+impl Add<isize> for Point {
+    type Output = isize;
+
+    fn add(self, z: isize) -> isize {
+        self.x + self.y + z
+    }
+}
+
+impl Point {
+    pub fn times(&self, z: isize) -> isize {
+        self.x * self.y * z
+    }
+}
+
+fn a() {
+    let mut p = Point {x: 3, y: 4};
+
+    // ok (we can loan out rcvr)
+    p + 3;
+    p.times(3);
+}
+
+fn b() {
+    let mut p = Point {x: 3, y: 4};
+
+    // Here I create an outstanding loan and check that we get conflicts:
+
+    let q = &mut p;
+
+    p + 3;  //~ ERROR cannot use `p`
+    p.times(3); //~ ERROR cannot borrow `p`
+
+    *q + 3; // OK to use the new alias `q`
+    q.x += 1; // and OK to mutate it
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr
new file mode 100644
index 00000000000..24cc4933ef1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr
@@ -0,0 +1,28 @@
+error[E0503]: cannot use `p` because it was mutably borrowed
+  --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:38:5
+   |
+LL |     let q = &mut p;
+   |             ------ borrow of `p` occurs here
+LL |
+LL |     p + 3;
+   |     ^ use of borrowed `p`
+...
+LL |     *q + 3; // OK to use the new alias `q`
+   |     -- borrow later used here
+
+error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:39:5
+   |
+LL |     let q = &mut p;
+   |             ------ mutable borrow occurs here
+...
+LL |     p.times(3);
+   |     ^^^^^^^^^^ immutable borrow occurs here
+LL |
+LL |     *q + 3; // OK to use the new alias `q`
+   |     -- mutable borrow later used here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0502, E0503.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-loan-rcvr.rs b/tests/ui/borrowck/borrowck-loan-rcvr.rs
new file mode 100644
index 00000000000..d2234e17ac7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-rcvr.rs
@@ -0,0 +1,40 @@
+struct Point { x: isize, y: isize }
+
+trait Methods {
+    fn impurem(&self);
+    fn blockm<F>(&self, f: F) where F: FnOnce();
+}
+
+impl Methods for Point {
+    fn impurem(&self) {
+    }
+
+    fn blockm<F>(&self, f: F) where F: FnOnce() { f() }
+}
+
+fn a() {
+    let mut p = Point {x: 3, y: 4};
+
+    // Here: it's ok to call even though receiver is mutable, because we
+    // can loan it out.
+    p.impurem();
+
+    // But in this case we do not honor the loan:
+    p.blockm(|| { //~ ERROR cannot borrow `p` as mutable
+        p.x = 10;
+    })
+}
+
+fn b() {
+    let mut p = Point {x: 3, y: 4};
+
+    // Here I create an outstanding loan and check that we get conflicts:
+
+    let l = &mut p;
+    p.impurem(); //~ ERROR cannot borrow
+
+    l.x += 1;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-loan-rcvr.stderr b/tests/ui/borrowck/borrowck-loan-rcvr.stderr
new file mode 100644
index 00000000000..1d6bd4e2ec8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-rcvr.stderr
@@ -0,0 +1,27 @@
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-loan-rcvr.rs:23:14
+   |
+LL |       p.blockm(|| {
+   |       - ------ ^^ mutable borrow occurs here
+   |       | |
+   |  _____| immutable borrow later used by call
+   | |
+LL | |         p.x = 10;
+   | |         --- second borrow occurs due to use of `p` in closure
+LL | |     })
+   | |______- immutable borrow occurs here
+
+error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-loan-rcvr.rs:34:5
+   |
+LL |     let l = &mut p;
+   |             ------ mutable borrow occurs here
+LL |     p.impurem();
+   |     ^^^^^^^^^^^ immutable borrow occurs here
+LL |
+LL |     l.x += 1;
+   |     -------- mutable borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-loan-vec-content.rs b/tests/ui/borrowck/borrowck-loan-vec-content.rs
new file mode 100644
index 00000000000..300ec88c5cd
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-vec-content.rs
@@ -0,0 +1,24 @@
+// Here we check that it is allowed to lend out an element of a
+// (locally rooted) mutable, unique vector, and that we then prevent
+// modifications to the contents.
+
+fn takes_imm_elt<F>(_v: &isize, f: F) where F: FnOnce() {
+    f();
+}
+
+fn has_mut_vec_and_does_not_try_to_change_it() {
+    let mut v: Vec<isize> = vec![1, 2, 3];
+    takes_imm_elt(&v[0], || {})
+}
+
+fn has_mut_vec_but_tries_to_change_it() {
+    let mut v: Vec<isize> = vec![1, 2, 3];
+    takes_imm_elt(
+        &v[0],
+        || { //~ ERROR cannot borrow `v` as mutable
+            v[1] = 4;
+        })
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-loan-vec-content.stderr b/tests/ui/borrowck/borrowck-loan-vec-content.stderr
new file mode 100644
index 00000000000..6691a2396a1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-loan-vec-content.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-loan-vec-content.rs:18:9
+   |
+LL |     takes_imm_elt(
+   |     ------------- immutable borrow later used by call
+LL |         &v[0],
+   |          - immutable borrow occurs here
+LL |         || {
+   |         ^^ mutable borrow occurs here
+LL |             v[1] = 4;
+   |             - second borrow occurs due to use of `v` in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.rs b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.rs
new file mode 100644
index 00000000000..b6eebd4e325
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.rs
@@ -0,0 +1,6 @@
+fn cplusplus_mode(x: isize) -> &'static isize {
+    &x
+    //~^ ERROR cannot return reference to function parameter `x` [E0515]
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr
new file mode 100644
index 00000000000..9d19de211a5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr
@@ -0,0 +1,9 @@
+error[E0515]: cannot return reference to function parameter `x`
+  --> $DIR/borrowck-local-borrow-outlives-fn.rs:2:5
+   |
+LL |     &x
+   |     ^^ returns a reference to data owned by the current function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs
new file mode 100644
index 00000000000..ffb2da28023
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs
@@ -0,0 +1,10 @@
+fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) {
+    let mut z = (0, 0);
+    *x = Some(&mut z.1);
+    //~^ ERROR `z.1` does not live long enough [E0597]
+    panic!("catch me for a dangling pointer!")
+}
+
+fn main() {
+    cplusplus_mode_exceptionally_unsafe(&mut None);
+}
diff --git a/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr
new file mode 100644
index 00000000000..6ea6951ad96
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `z.1` does not live long enough
+  --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:3:15
+   |
+LL |     *x = Some(&mut z.1);
+   |     ----------^^^^^^^^-
+   |     |         |
+   |     |         borrowed value does not live long enough
+   |     assignment requires that `z.1` is borrowed for `'static`
+...
+LL | }
+   | - `z.1` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/borrowck/borrowck-local-borrow.rs b/tests/ui/borrowck/borrowck-local-borrow.rs
new file mode 100644
index 00000000000..0aaa4e4c684
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-local-borrow.rs
@@ -0,0 +1,9 @@
+// run-fail
+// error-pattern:panic 1
+// ignore-emscripten no processes
+
+fn main() {
+    let x = 2;
+    let y = &x;
+    panic!("panic 1");
+}
diff --git a/tests/ui/borrowck/borrowck-macro-interaction-issue-6304.rs b/tests/ui/borrowck/borrowck-macro-interaction-issue-6304.rs
new file mode 100644
index 00000000000..4e969f6ed83
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-macro-interaction-issue-6304.rs
@@ -0,0 +1,36 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unconditional_recursion)]
+
+// Check that we do not ICE when compiling this
+// macro, which reuses the expression `$id`
+
+#![feature(box_patterns)]
+
+struct Foo {
+  a: isize
+}
+
+pub enum Bar {
+  Bar1, Bar2(isize, Box<Bar>),
+}
+
+impl Foo {
+  fn elaborate_stm(&mut self, s: Box<Bar>) -> Box<Bar> {
+    macro_rules! declare {
+      ($id:expr, $rest:expr) => ({
+        self.check_id($id);
+        Box::new(Bar::Bar2($id, $rest))
+      })
+    }
+    match s {
+      box Bar::Bar2(id, rest) => declare!(id, self.elaborate_stm(rest)),
+      _ => panic!()
+    }
+  }
+
+  fn check_id(&mut self, s: isize) { panic!() }
+}
+
+pub fn main() { }
diff --git a/tests/ui/borrowck/borrowck-match-already-borrowed.rs b/tests/ui/borrowck/borrowck-match-already-borrowed.rs
new file mode 100644
index 00000000000..a925cbbf57b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-match-already-borrowed.rs
@@ -0,0 +1,26 @@
+enum Foo {
+    A(i32),
+    B
+}
+
+fn match_enum() {
+    let mut foo = Foo::B;
+    let p = &mut foo;
+    let _ = match foo { //~ ERROR [E0503]
+        Foo::B => 1,
+        _ => 2,
+        Foo::A(x) => x //~ ERROR [E0503]
+    };
+    drop(p);
+}
+
+
+fn main() {
+    let mut x = 1;
+    let r = &mut x;
+    let _ = match x {
+        x => x + 1, //~ ERROR [E0503]
+        y => y + 2, //~ ERROR [E0503]
+    };
+    drop(r);
+}
diff --git a/tests/ui/borrowck/borrowck-match-already-borrowed.stderr b/tests/ui/borrowck/borrowck-match-already-borrowed.stderr
new file mode 100644
index 00000000000..39047be9de6
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-match-already-borrowed.stderr
@@ -0,0 +1,50 @@
+error[E0503]: cannot use `foo` because it was mutably borrowed
+  --> $DIR/borrowck-match-already-borrowed.rs:9:19
+   |
+LL |     let p = &mut foo;
+   |             -------- borrow of `foo` occurs here
+LL |     let _ = match foo {
+   |                   ^^^ use of borrowed `foo`
+...
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0503]: cannot use `foo.0` because it was mutably borrowed
+  --> $DIR/borrowck-match-already-borrowed.rs:12:16
+   |
+LL |     let p = &mut foo;
+   |             -------- borrow of `foo` occurs here
+...
+LL |         Foo::A(x) => x
+   |                ^ use of borrowed `foo`
+LL |     };
+LL |     drop(p);
+   |          - borrow later used here
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+  --> $DIR/borrowck-match-already-borrowed.rs:22:9
+   |
+LL |     let r = &mut x;
+   |             ------ borrow of `x` occurs here
+LL |     let _ = match x {
+LL |         x => x + 1,
+   |         ^ use of borrowed `x`
+...
+LL |     drop(r);
+   |          - borrow later used here
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+  --> $DIR/borrowck-match-already-borrowed.rs:23:9
+   |
+LL |     let r = &mut x;
+   |             ------ borrow of `x` occurs here
+...
+LL |         y => y + 2,
+   |         ^ use of borrowed `x`
+LL |     };
+LL |     drop(r);
+   |          - borrow later used here
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0503`.
diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.rs b/tests/ui/borrowck/borrowck-match-binding-is-assignment.rs
new file mode 100644
index 00000000000..064bf69ae79
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.rs
@@ -0,0 +1,41 @@
+// Test that immutable pattern bindings cannot be reassigned.
+
+enum E {
+    Foo(isize)
+}
+
+struct S {
+    bar: isize,
+}
+
+pub fn main() {
+    match 1 {
+        x => {
+            x += 1; //~ ERROR [E0384]
+        }
+    }
+
+    match E::Foo(1) {
+        E::Foo(x) => {
+            x += 1; //~ ERROR [E0384]
+        }
+    }
+
+    match (S { bar: 1 }) {
+        S { bar: x } => {
+            x += 1; //~ ERROR [E0384]
+        }
+    }
+
+    match (1,) {
+        (x,) => {
+            x += 1; //~ ERROR [E0384]
+        }
+    }
+
+    match [1,2,3] {
+        [x,_,_] => {
+            x += 1; //~ ERROR [E0384]
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr
new file mode 100644
index 00000000000..dd22d7e2e2e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr
@@ -0,0 +1,58 @@
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/borrowck-match-binding-is-assignment.rs:14:13
+   |
+LL |         x => {
+   |         -
+   |         |
+   |         first assignment to `x`
+   |         help: consider making this binding mutable: `mut x`
+LL |             x += 1;
+   |             ^^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/borrowck-match-binding-is-assignment.rs:20:13
+   |
+LL |         E::Foo(x) => {
+   |                -
+   |                |
+   |                first assignment to `x`
+   |                help: consider making this binding mutable: `mut x`
+LL |             x += 1;
+   |             ^^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/borrowck-match-binding-is-assignment.rs:26:13
+   |
+LL |         S { bar: x } => {
+   |                  -
+   |                  |
+   |                  first assignment to `x`
+   |                  help: consider making this binding mutable: `mut x`
+LL |             x += 1;
+   |             ^^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/borrowck-match-binding-is-assignment.rs:32:13
+   |
+LL |         (x,) => {
+   |          -
+   |          |
+   |          first assignment to `x`
+   |          help: consider making this binding mutable: `mut x`
+LL |             x += 1;
+   |             ^^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/borrowck-match-binding-is-assignment.rs:38:13
+   |
+LL |         [x,_,_] => {
+   |          -
+   |          |
+   |          first assignment to `x`
+   |          help: consider making this binding mutable: `mut x`
+LL |             x += 1;
+   |             ^^^^^^ cannot assign twice to immutable variable
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0384`.
diff --git a/tests/ui/borrowck/borrowck-move-by-capture-ok.rs b/tests/ui/borrowck/borrowck-move-by-capture-ok.rs
new file mode 100644
index 00000000000..e7a48ebf6ca
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-by-capture-ok.rs
@@ -0,0 +1,7 @@
+// run-pass
+
+pub fn main() {
+    let bar: Box<_> = Box::new(3);
+    let h = || -> isize { *bar };
+    assert_eq!(h(), 3);
+}
diff --git a/tests/ui/borrowck/borrowck-move-by-capture.rs b/tests/ui/borrowck/borrowck-move-by-capture.rs
new file mode 100644
index 00000000000..6f0eb1870f3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-by-capture.rs
@@ -0,0 +1,11 @@
+#![feature(unboxed_closures, tuple_trait)]
+
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
+
+pub fn main() {
+    let bar: Box<_> = Box::new(3);
+    let _g = to_fn_mut(|| {
+        let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of
+    });
+}
diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr
new file mode 100644
index 00000000000..8ddc48b2a99
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr
@@ -0,0 +1,17 @@
+error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
+  --> $DIR/borrowck-move-by-capture.rs:9:29
+   |
+LL |     let bar: Box<_> = Box::new(3);
+   |         --- captured outer variable
+LL |     let _g = to_fn_mut(|| {
+   |                        -- captured by this `FnMut` closure
+LL |         let _h = to_fn_once(move || -> isize { *bar });
+   |                             ^^^^^^^^^^^^^^^^   ----
+   |                             |                  |
+   |                             |                  variable moved due to use in closure
+   |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+   |                             move out of `bar` occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-move-error-with-note.fixed b/tests/ui/borrowck/borrowck-move-error-with-note.fixed
new file mode 100644
index 00000000000..cf6c382a692
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-error-with-note.fixed
@@ -0,0 +1,56 @@
+// run-rustfix
+#![allow(unused)]
+enum Foo {
+    Foo1(Box<u32>, Box<u32>),
+    Foo2(Box<u32>),
+    Foo3,
+}
+
+
+
+fn blah() {
+    let f = &Foo::Foo1(Box::new(1), Box::new(2));
+    match f { //~ ERROR cannot move out of
+        Foo::Foo1(num1,
+                  num2) => (),
+        Foo::Foo2(num) => (),
+        Foo::Foo3 => ()
+    }
+}
+
+struct S {
+    f: String,
+    g: String
+}
+impl Drop for S {
+    fn drop(&mut self) { println!("{}", self.f); }
+}
+
+fn move_in_match() {
+    match (S {f: "foo".to_string(), g: "bar".to_string()}) {
+        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+        S {
+            f: ref _s,
+            g: ref _t
+        } => {}
+    }
+}
+
+// from issue-8064
+struct A {
+    a: Box<isize>,
+}
+
+fn free<T>(_: T) {}
+
+fn blah2() {
+    let a = &A { a: Box::new(1) };
+    match &a.a { //~ ERROR cannot move out of
+        n => {
+            free(n)
+        }
+    }
+    free(a)
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-error-with-note.rs b/tests/ui/borrowck/borrowck-move-error-with-note.rs
new file mode 100644
index 00000000000..f336ac4f994
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-error-with-note.rs
@@ -0,0 +1,56 @@
+// run-rustfix
+#![allow(unused)]
+enum Foo {
+    Foo1(Box<u32>, Box<u32>),
+    Foo2(Box<u32>),
+    Foo3,
+}
+
+
+
+fn blah() {
+    let f = &Foo::Foo1(Box::new(1), Box::new(2));
+    match *f { //~ ERROR cannot move out of
+        Foo::Foo1(num1,
+                  num2) => (),
+        Foo::Foo2(num) => (),
+        Foo::Foo3 => ()
+    }
+}
+
+struct S {
+    f: String,
+    g: String
+}
+impl Drop for S {
+    fn drop(&mut self) { println!("{}", self.f); }
+}
+
+fn move_in_match() {
+    match (S {f: "foo".to_string(), g: "bar".to_string()}) {
+        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+        S {
+            f: _s,
+            g: _t
+        } => {}
+    }
+}
+
+// from issue-8064
+struct A {
+    a: Box<isize>,
+}
+
+fn free<T>(_: T) {}
+
+fn blah2() {
+    let a = &A { a: Box::new(1) };
+    match a.a { //~ ERROR cannot move out of
+        n => {
+            free(n)
+        }
+    }
+    free(a)
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-error-with-note.stderr b/tests/ui/borrowck/borrowck-move-error-with-note.stderr
new file mode 100644
index 00000000000..722c2c1443a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-error-with-note.stderr
@@ -0,0 +1,60 @@
+error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
+  --> $DIR/borrowck-move-error-with-note.rs:13:11
+   |
+LL |     match *f {
+   |           ^^
+LL |         Foo::Foo1(num1,
+   |                   ---- data moved here
+LL |                   num2) => (),
+   |                   ---- ...and here
+LL |         Foo::Foo2(num) => (),
+   |                   --- ...and here
+   |
+   = note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the dereference here
+   |
+LL -     match *f {
+LL +     match f {
+   |
+
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-move-error-with-note.rs:30:11
+   |
+LL |     match (S {f: "foo".to_string(), g: "bar".to_string()}) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
+...
+LL |             f: _s,
+   |                -- data moved here
+LL |             g: _t
+   |                -- ...and here
+   |
+   = note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing the pattern binding
+   |
+LL |             f: ref _s,
+   |                +++
+help: consider borrowing the pattern binding
+   |
+LL |             g: ref _t
+   |                +++
+
+error[E0507]: cannot move out of `a.a` which is behind a shared reference
+  --> $DIR/borrowck-move-error-with-note.rs:48:11
+   |
+LL |     match a.a {
+   |           ^^^
+LL |         n => {
+   |         -
+   |         |
+   |         data moved here
+   |         move occurs because `n` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |     match &a.a {
+   |           +
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0507, E0509.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs
new file mode 100644
index 00000000000..71405f7a732
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs
@@ -0,0 +1,17 @@
+// verify that an error is raised when trying to move out of a
+// borrowed path.
+
+
+
+
+
+fn main() {
+    let a: Box<Box<_>> = Box::new(Box::new(2));
+    let b = &a;
+
+    let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed
+    b.use_ref();
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
new file mode 100644
index 00000000000..f833abcc02a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
@@ -0,0 +1,14 @@
+error[E0505]: cannot move out of `*a` because it is borrowed
+  --> $DIR/borrowck-move-from-subpath-of-borrowed-path.rs:12:13
+   |
+LL |     let b = &a;
+   |             -- borrow of `a` occurs here
+LL |
+LL |     let z = *a;
+   |             ^^ move out of `*a` occurs here
+LL |     b.use_ref();
+   |     ----------- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.rs b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.rs
new file mode 100644
index 00000000000..824da5ceb07
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.rs
@@ -0,0 +1,7 @@
+unsafe fn foo(x: *const Box<isize>) -> Box<isize> {
+    let y = *x; //~ ERROR cannot move out of `*x` which is behind a raw pointer
+    return y;
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
new file mode 100644
index 00000000000..43fc102bd62
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr
@@ -0,0 +1,15 @@
+error[E0507]: cannot move out of `*x` which is behind a raw pointer
+  --> $DIR/borrowck-move-from-unsafe-ptr.rs:2:13
+   |
+LL |     let y = *x;
+   |             ^^ move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -     let y = *x;
+LL +     let y = x;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-move-in-irrefut-pat.rs b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.rs
new file mode 100644
index 00000000000..f4f402dd96a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.rs
@@ -0,0 +1,16 @@
+fn with<F>(f: F) where F: FnOnce(&String) {}
+
+fn arg_item(&_x: &String) {}
+    //~^ ERROR [E0507]
+
+fn arg_closure() {
+    with(|&_x| ())
+    //~^ ERROR [E0507]
+}
+
+fn let_pat() {
+    let &_x = &"hi".to_string();
+    //~^ ERROR [E0507]
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr
new file mode 100644
index 00000000000..21bd073321b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr
@@ -0,0 +1,48 @@
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:3:13
+   |
+LL | fn arg_item(&_x: &String) {}
+   |             ^--
+   |              |
+   |              data moved here
+   |              move occurs because `_x` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL - fn arg_item(&_x: &String) {}
+LL + fn arg_item(_x: &String) {}
+   |
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:7:11
+   |
+LL |     with(|&_x| ())
+   |           ^--
+   |            |
+   |            data moved here
+   |            move occurs because `_x` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     with(|&_x| ())
+LL +     with(|_x| ())
+   |
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:12:15
+   |
+LL |     let &_x = &"hi".to_string();
+   |          --   ^^^^^^^^^^^^^^^^^
+   |          |
+   |          data moved here
+   |          move occurs because `_x` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     let &_x = &"hi".to_string();
+LL +     let _x = &"hi".to_string();
+   |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-move-moved-value-into-closure.rs b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.rs
new file mode 100644
index 00000000000..72e7b5a7162
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.rs
@@ -0,0 +1,12 @@
+fn call_f<F:FnOnce() -> isize>(f: F) -> isize {
+    f()
+}
+
+
+
+fn main() {
+    let t: Box<_> = Box::new(3);
+
+    call_f(move|| { *t + 1 });
+    call_f(move|| { *t + 1 }); //~ ERROR use of moved value
+}
diff --git a/tests/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.stderr
new file mode 100644
index 00000000000..9509ebb7cde
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.stderr
@@ -0,0 +1,18 @@
+error[E0382]: use of moved value: `t`
+  --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12
+   |
+LL |     let t: Box<_> = Box::new(3);
+   |         - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait
+LL |
+LL |     call_f(move|| { *t + 1 });
+   |            ------   -- variable moved due to use in closure
+   |            |
+   |            value moved into closure here
+LL |     call_f(move|| { *t + 1 });
+   |            ^^^^^^   -- use occurs due to use in closure
+   |            |
+   |            value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.rs b/tests/ui/borrowck/borrowck-move-mut-base-ptr.rs
new file mode 100644
index 00000000000..fa2d5531b13
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.rs
@@ -0,0 +1,19 @@
+// Test that attempt to move `&mut` pointer while pointee is borrowed
+// yields an error.
+//
+// Example from compiler/rustc_borrowck/borrowck/README.md
+
+
+
+fn foo(t0: &mut isize) {
+    let p: &isize = &*t0; // Freezes `*t0`
+    let t1 = t0;        //~ ERROR cannot move out of `t0`
+    *t1 = 22;
+    p.use_ref();
+}
+
+fn main() {
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
new file mode 100644
index 00000000000..d5ff0c501c4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
@@ -0,0 +1,14 @@
+error[E0505]: cannot move out of `t0` because it is borrowed
+  --> $DIR/borrowck-move-mut-base-ptr.rs:10:14
+   |
+LL |     let p: &isize = &*t0; // Freezes `*t0`
+   |                     ---- borrow of `*t0` occurs here
+LL |     let t1 = t0;
+   |              ^^ move out of `t0` occurs here
+LL |     *t1 = 22;
+LL |     p.use_ref();
+   |     ----------- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-match.rs
new file mode 100644
index 00000000000..ced4d002b38
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-match.rs
@@ -0,0 +1,116 @@
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        [.., _y] => {} //~ ERROR use of moved value
+    }
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., _y] => {} //~ ERROR use of partially moved value
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., (_y, _)] => {} //~ ERROR use of moved value
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, _, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, _, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _, _] => {}
+    }
+    match a {
+        [(_x, _), _, _] => {} //~ ERROR use of moved value
+    }
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    match a {
+        [_, _, _y @ ..] => {}
+    }
+    match a {
+        [.., (_x, _)] => {} //~ ERROR use of moved value
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr
new file mode 100644
index 00000000000..67b00c1dd90
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr
@@ -0,0 +1,153 @@
+error[E0382]: use of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-match.rs:13:14
+   |
+LL |         [_, _, _x] => {}
+   |                -- value moved here
+...
+LL |         [.., _y] => {}
+   |              ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
+
+error[E0382]: use of partially moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-match.rs:23:14
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value partially moved here
+...
+LL |         [.., _y] => {}
+   |              ^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-match.rs:33:15
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+...
+LL |         [.., (_y, _)] => {}
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:44:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:55:11
+   |
+LL |         [.., _x] => {}
+   |              -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:66:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:77:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-match.rs:89:11
+   |
+LL |         [_y @ .., _, _] => {}
+   |          -- value moved here
+...
+LL |         [(_x, _), _, _] => {}
+   |           ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _, _] => {}
+   |          +++
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-match.rs:99:15
+   |
+LL |         [_, _, _y @ ..] => {}
+   |                -- value moved here
+...
+LL |         [.., (_x, _)] => {}
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _y @ ..] => {}
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:110:11
+   |
+LL |         [x @ .., _] => {}
+   |          - value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _] => {}
+   |          +++
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs
new file mode 100644
index 00000000000..97db70f34cc
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs
@@ -0,0 +1,115 @@
+// Due to #53114, which causes a "read" of the `_` patterns,
+// the borrow-checker refuses this code, while it should probably be allowed.
+// Once the bug is fixed, the test, which is derived from a
+// passing test for `let` statements, should become check-pass.
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [.., _y, _] => {}
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [.., (_, _y)] => {}
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    match a {
+        [_, _y @ ..] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [(_x, _), _, _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [.., (_x, _)] => {}
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
new file mode 100644
index 00000000000..47429ea3eeb
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
@@ -0,0 +1,138 @@
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:17:11
+   |
+LL |         [_, _, _x] => {}
+   |                -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11
+   |
+LL |         [.., _x] => {}
+   |              -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11
+   |
+LL |         [_, _y @ ..] => {}
+   |             -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, ref _y @ ..] => {}
+   |             +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11
+   |
+LL |         [_y @ .., _] => {}
+   |          -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _] => {}
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11
+   |
+LL |         [x @ .., _, _] => {}
+   |          - value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _, _] => {}
+   |          +++
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs
new file mode 100644
index 00000000000..c91b4286b64
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs
@@ -0,0 +1,67 @@
+// check-pass
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., _y, _] = a;
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (_, _y)] = a;
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    let [_x, _, _] = a;
+    let [_, _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [_y @ .., _] = a;
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [_, _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [_y @ .., _] = a;
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    let [_, _y @ ..] = a;
+    let [(_x, _), _, _] = a;
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    let [_y @ .., _] = a;
+    let [.., (_x, _)] = a;
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _, _] = a;
+    let [_, _y @ ..] = a;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs
new file mode 100644
index 00000000000..604a25cdcc1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs
@@ -0,0 +1,150 @@
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        [.., ref _y] => {} //~ ERROR [E0382]
+    }
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., ref _y] => {} //~ ERROR [E0382]
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., (ref _y, _)] => {} //~ ERROR [E0382]
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [ref _y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [_, _, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [ref _y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [_, _, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _, _] => {}
+    }
+    match a {
+        [(ref _x, _), _, _] => {} //~ ERROR [E0382]
+    }
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    match a {
+        [_, _, _y @ ..] => {}
+    }
+    match a {
+        [.., (ref _x, _)] => {} //~ ERROR [E0382]
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [_, ref _y @ ..] => {}
+    }
+}
+
+// Move + Assign
+
+fn move_out_and_assign_end() {
+    let mut a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    a[2] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_and_assign_end_field() {
+    let mut a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    a[2].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end() {
+    let mut a = array();
+    match a {
+        [_, _, _x @ ..] => {}
+    }
+    a[0] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end_field() {
+    let mut a = array();
+    match a {
+        [_, _, _x @ ..] => {}
+    }
+    a[0].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
new file mode 100644
index 00000000000..bfab13d42d2
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
@@ -0,0 +1,213 @@
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:13:14
+   |
+LL |         [_, _, _x] => {}
+   |                -- value moved here
+...
+LL |         [.., ref _y] => {}
+   |              ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
+
+error[E0382]: borrow of partially moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value partially moved here
+...
+LL |         [.., ref _y] => {}
+   |              ^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
+
+error[E0382]: borrow of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+...
+LL |         [.., (ref _y, _)] => {}
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11
+   |
+LL |         [.., _x] => {}
+   |              -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11
+   |
+LL |         [_y @ .., _, _] => {}
+   |          -- value moved here
+...
+LL |         [(ref _x, _), _, _] => {}
+   |           ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _, _] => {}
+   |          +++
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15
+   |
+LL |         [_, _, _y @ ..] => {}
+   |                -- value moved here
+...
+LL |         [.., (ref _x, _)] => {}
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _y @ ..] => {}
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11
+   |
+LL |         [x @ .., _] => {}
+   |          - value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _] => {}
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5
+   |
+LL |         [_, _, _x] => {}
+   |                -- value partially moved here
+LL |     }
+LL |     a[2] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value partially moved here
+LL |     }
+LL |     a[2].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5
+   |
+LL |         [_, _, _x @ ..] => {}
+   |                -- value partially moved here
+LL |     }
+LL |     a[0] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x @ ..] => {}
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5
+   |
+LL |         [_, _, _x @ ..] => {}
+   |                -- value partially moved here
+LL |     }
+LL |     a[0].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x @ ..] => {}
+   |                +++
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs
new file mode 100644
index 00000000000..017ca90b81a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs
@@ -0,0 +1,115 @@
+// Due to #53114, which causes a "read" of the `_` patterns,
+// the borrow-checker refuses this code, while it should probably be allowed.
+// Once the bug is fixed, the test, which is derived from a
+// passing test for `let` statements, should become check-pass.
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [.., ref _y, _] => {}
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [.., (_, ref _y)] => {}
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [ref _y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [ref _y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    match a {
+        [_, _y @ ..] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [(ref _x, _), _, _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [.., (ref _x, _)] => {}
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of partially moved value
+        [_, ref _y @ ..] => {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
new file mode 100644
index 00000000000..8412c24fe61
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
@@ -0,0 +1,138 @@
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:17:11
+   |
+LL |         [_, _, _x] => {}
+   |                -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11
+   |
+LL |         [.., _x] => {}
+   |              -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11
+   |
+LL |         [_, _y @ ..] => {}
+   |             -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, ref _y @ ..] => {}
+   |             +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11
+   |
+LL |         [_y @ .., _] => {}
+   |          -- value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _] => {}
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11
+   |
+LL |         [x @ .., _, _] => {}
+   |          - value partially moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _, _] => {}
+   |          +++
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs
new file mode 100644
index 00000000000..e3498cef377
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs
@@ -0,0 +1,67 @@
+// check-pass
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., ref _y, _] = a;
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (_, ref _y)] = a;
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    let [_x, _, _] = a;
+    let [_, ref _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [ref _y @ .., _] = a;
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [_, ref _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [ref _y @ .., _] = a;
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    let [_, _y @ ..] = a;
+    let [(ref _x, _), _, _] = a;
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    let [_y @ .., _] = a;
+    let [.., (ref _x, _)] = a;
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _, _] = a;
+    let [_, ref _y @ ..] = a;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use.rs
new file mode 100644
index 00000000000..ad08367a3b5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-use.rs
@@ -0,0 +1,97 @@
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., ref _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., ref _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (ref _y, _)] = a; //~ ERROR [E0382]
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    let [_x, _, _] = a;
+    let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    let [_y @ .., _, _] = a;
+    let [(ref _x, _), _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    let [_, _, _y @ ..] = a;
+    let [.., (ref _x, _)] = a; //~ ERROR [E0382]
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _] = a;
+    let [_, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+// Move + Assign
+
+fn move_out_and_assign_end() {
+    let mut a = array();
+    let [_, _, _x] = a;
+    a[2] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_and_assign_end_field() {
+    let mut a = array();
+    let [_, _, (_x, _)] = a;
+    a[2].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end() {
+    let mut a = array();
+    let [_, _, _x @ ..] = a;
+    a[0] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end_field() {
+    let mut a = array();
+    let [_, _, _x @ ..] = a;
+    a[0].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use.stderr
new file mode 100644
index 00000000000..e2aeaafc63c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array-use.stderr
@@ -0,0 +1,199 @@
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:10:14
+   |
+LL |     let [_, _, _x] = a;
+   |                -- value moved here
+LL |     let [.., ref _y] = a;
+   |              ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
+
+error[E0382]: borrow of partially moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:16:14
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value partially moved here
+LL |     let [.., ref _y] = a;
+   |              ^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
+
+error[E0382]: borrow of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-use.rs:22:15
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value moved here
+LL |     let [.., (ref _y, _)] = a;
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
+
+error[E0382]: borrow of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:30:10
+   |
+LL |     let [_x, _, _] = a;
+   |          -- value partially moved here
+LL |     let [ref _y @ .., _, _] = a;
+   |          ^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _x, _, _] = a;
+   |          +++
+
+error[E0382]: borrow of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:36:16
+   |
+LL |     let [.., _x] = a;
+   |              -- value partially moved here
+LL |     let [_, _, ref _y @ ..] = a;
+   |                ^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., ref _x] = a;
+   |              +++
+
+error[E0382]: borrow of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:42:10
+   |
+LL |     let [(_x, _), _, _] = a;
+   |           -- value partially moved here
+LL |     let [ref _y @ .., _, _] = a;
+   |          ^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [(ref _x, _), _, _] = a;
+   |           +++
+
+error[E0382]: borrow of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:48:16
+   |
+LL |     let [.., (_x, _)] = a;
+   |               -- value partially moved here
+LL |     let [_, _, ref _y @ ..] = a;
+   |                ^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., (ref _x, _)] = a;
+   |               +++
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:54:11
+   |
+LL |     let [_y @ .., _, _] = a;
+   |          -- value moved here
+LL |     let [(ref _x, _), _, _] = a;
+   |           ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _y @ .., _, _] = a;
+   |          +++
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use.rs:60:15
+   |
+LL |     let [_, _, _y @ ..] = a;
+   |                -- value moved here
+LL |     let [.., (ref _x, _)] = a;
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _y @ ..] = a;
+   |                +++
+
+error[E0382]: borrow of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:68:13
+   |
+LL |     let [x @ .., _] = a;
+   |          - value partially moved here
+LL |     let [_, ref _y @ ..] = a;
+   |             ^^^^^^ value borrowed here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref x @ .., _] = a;
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:76:5
+   |
+LL |     let [_, _, _x] = a;
+   |                -- value partially moved here
+LL |     a[2] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:82:5
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value partially moved here
+LL |     a[2].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:88:5
+   |
+LL |     let [_, _, _x @ ..] = a;
+   |                -- value partially moved here
+LL |     a[0] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x @ ..] = a;
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use.rs:94:5
+   |
+LL |     let [_, _, _x @ ..] = a;
+   |                -- value partially moved here
+LL |     a[0].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x @ ..] = a;
+   |                +++
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array.rs b/tests/ui/borrowck/borrowck-move-out-from-array.rs
new file mode 100644
index 00000000000..83755812f4b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array.rs
@@ -0,0 +1,71 @@
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+    let a = array();
+    let [_, _, _x] = a;
+    let [.., _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    let [_, _, (_x, _)] = a;
+    let [.., (_y, _)] = a; //~ ERROR [E0382]
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    let [_x, _, _] = a;
+    let [_y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    let [.., _x] = a;
+    let [_, _, _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    let [(_x, _), _, _] = a;
+    let [_y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    let [.., (_x, _)] = a;
+    let [_, _, _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    let [_y @ .., _, _] = a;
+    let [(_x, _), _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    let [_, _, _y @ ..] = a;
+    let [.., (_x, _)] = a; //~ ERROR [E0382]
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    let [x @ .., _] = a;
+    let [_, _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-from-array.stderr b/tests/ui/borrowck/borrowck-move-out-from-array.stderr
new file mode 100644
index 00000000000..dd456681f57
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-from-array.stderr
@@ -0,0 +1,143 @@
+error[E0382]: use of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array.rs:10:14
+   |
+LL |     let [_, _, _x] = a;
+   |                -- value moved here
+LL |     let [.., _y] = a;
+   |              ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
+
+error[E0382]: use of partially moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array.rs:16:14
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value partially moved here
+LL |     let [.., _y] = a;
+   |              ^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array.rs:22:15
+   |
+LL |     let [_, _, (_x, _)] = a;
+   |                 -- value moved here
+LL |     let [.., (_y, _)] = a;
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:30:10
+   |
+LL |     let [_x, _, _] = a;
+   |          -- value partially moved here
+LL |     let [_y @ .., _, _] = a;
+   |          ^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _x, _, _] = a;
+   |          +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:36:16
+   |
+LL |     let [.., _x] = a;
+   |              -- value partially moved here
+LL |     let [_, _, _y @ ..] = a;
+   |                ^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., ref _x] = a;
+   |              +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:42:10
+   |
+LL |     let [(_x, _), _, _] = a;
+   |           -- value partially moved here
+LL |     let [_y @ .., _, _] = a;
+   |          ^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [(ref _x, _), _, _] = a;
+   |           +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:48:16
+   |
+LL |     let [.., (_x, _)] = a;
+   |               -- value partially moved here
+LL |     let [_, _, _y @ ..] = a;
+   |                ^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., (ref _x, _)] = a;
+   |               +++
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array.rs:54:11
+   |
+LL |     let [_y @ .., _, _] = a;
+   |          -- value moved here
+LL |     let [(_x, _), _, _] = a;
+   |           ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _y @ .., _, _] = a;
+   |          +++
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array.rs:60:15
+   |
+LL |     let [_, _, _y @ ..] = a;
+   |                -- value moved here
+LL |     let [.., (_x, _)] = a;
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _y @ ..] = a;
+   |                +++
+
+error[E0382]: use of partially moved value: `a`
+  --> $DIR/borrowck-move-out-from-array.rs:68:13
+   |
+LL |     let [x @ .., _] = a;
+   |          - value partially moved here
+LL |     let [_, _y @ ..] = a;
+   |             ^^ value used here after partial move
+   |
+   = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref x @ .., _] = a;
+   |          +++
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
new file mode 100644
index 00000000000..0b9e7102cd5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
@@ -0,0 +1,6 @@
+use std::rc::Rc;
+
+pub fn main() {
+    let _x = Rc::new(vec![1, 2]).into_iter();
+    //~^ ERROR [E0507]
+}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
new file mode 100644
index 00000000000..87135f0bb43
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
@@ -0,0 +1,19 @@
+error[E0507]: cannot move out of an `Rc`
+  --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14
+   |
+LL |     let _x = Rc::new(vec![1, 2]).into_iter();
+   |              ^^^^^^^^^^^^^^^^^^^^-----------
+   |              |                   |
+   |              |                   value moved due to this method call
+   |              move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+note: `into_iter` takes ownership of the receiver `self`, which moves value
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |     let _x = Rc::new(vec![1, 2]).clone().into_iter();
+   |                                  ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs
new file mode 100644
index 00000000000..ecb135f68d5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs
@@ -0,0 +1,6 @@
+use std::rc::Rc;
+
+pub fn main() {
+    let _x = *Rc::new("hi".to_string());
+    //~^ ERROR cannot move out of an `Rc`
+}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
new file mode 100644
index 00000000000..599fa1e88df
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr
@@ -0,0 +1,15 @@
+error[E0507]: cannot move out of an `Rc`
+  --> $DIR/borrowck-move-out-of-overloaded-deref.rs:4:14
+   |
+LL |     let _x = *Rc::new("hi".to_string());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -     let _x = *Rc::new("hi".to_string());
+LL +     let _x = Rc::new("hi".to_string());
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.rs b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs
new file mode 100644
index 00000000000..d01fb261894
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs
@@ -0,0 +1,16 @@
+// Ensure that moves out of static items is forbidden
+
+struct Foo {
+    foo: isize,
+}
+
+static BAR: Foo = Foo { foo: 5 };
+
+
+fn test(f: Foo) {
+    let _f = Foo{foo: 4, ..f};
+}
+
+fn main() {
+    test(BAR); //~ ERROR cannot move out of static item `BAR` [E0507]
+}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
new file mode 100644
index 00000000000..edf8c954f81
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
@@ -0,0 +1,9 @@
+error[E0507]: cannot move out of static item `BAR`
+  --> $DIR/borrowck-move-out-of-static-item.rs:15:10
+   |
+LL |     test(BAR);
+   |          ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.fixed b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.fixed
new file mode 100644
index 00000000000..c463c655938
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+#![allow(unused)]
+struct S {f:String}
+impl Drop for S {
+    fn drop(&mut self) { println!("{}", self.f); }
+}
+
+fn move_in_match() {
+    match (S {f:"foo".to_string()}) {
+        //~^ ERROR [E0509]
+        S {f:ref _s} => {}
+    }
+}
+
+fn move_in_let() {
+    let S {f:ref _s} = S {f:"foo".to_string()};
+    //~^ ERROR [E0509]
+}
+
+fn move_in_fn_arg(S {f:ref _s}: S) {
+    //~^ ERROR [E0509]
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs
new file mode 100644
index 00000000000..93183062d61
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+#![allow(unused)]
+struct S {f:String}
+impl Drop for S {
+    fn drop(&mut self) { println!("{}", self.f); }
+}
+
+fn move_in_match() {
+    match (S {f:"foo".to_string()}) {
+        //~^ ERROR [E0509]
+        S {f:_s} => {}
+    }
+}
+
+fn move_in_let() {
+    let S {f:_s} = S {f:"foo".to_string()};
+    //~^ ERROR [E0509]
+}
+
+fn move_in_fn_arg(S {f:_s}: S) {
+    //~^ ERROR [E0509]
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr
new file mode 100644
index 00000000000..58f706c65ff
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr
@@ -0,0 +1,49 @@
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:9:11
+   |
+LL |     match (S {f:"foo".to_string()}) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
+LL |
+LL |         S {f:_s} => {}
+   |              --
+   |              |
+   |              data moved here
+   |              move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |         S {f:ref _s} => {}
+   |              +++
+
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:16:20
+   |
+LL |     let S {f:_s} = S {f:"foo".to_string()};
+   |              --    ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
+   |              |
+   |              data moved here
+   |              move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |     let S {f:ref _s} = S {f:"foo".to_string()};
+   |              +++
+
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:20:19
+   |
+LL | fn move_in_fn_arg(S {f:_s}: S) {
+   |                   ^^^^^--^
+   |                   |    |
+   |                   |    data moved here
+   |                   |    move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+   |                   cannot move out of here
+   |
+help: consider borrowing the pattern binding
+   |
+LL | fn move_in_fn_arg(S {f:ref _s}: S) {
+   |                        +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0509`.
diff --git a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.fixed b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.fixed
new file mode 100644
index 00000000000..bc2ddf85fb4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+#![allow(unused)]
+struct S(String);
+impl Drop for S {
+    fn drop(&mut self) { }
+}
+
+fn move_in_match() {
+    match S("foo".to_string()) {
+        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+        S(ref _s) => {}
+    }
+}
+
+fn move_in_let() {
+    let S(ref _s) = S("foo".to_string());
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+}
+
+fn move_in_fn_arg(S(ref _s): S) {
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs
new file mode 100644
index 00000000000..f050bce8740
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+#![allow(unused)]
+struct S(String);
+impl Drop for S {
+    fn drop(&mut self) { }
+}
+
+fn move_in_match() {
+    match S("foo".to_string()) {
+        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+        S(_s) => {}
+    }
+}
+
+fn move_in_let() {
+    let S(_s) = S("foo".to_string());
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+}
+
+fn move_in_fn_arg(S(_s): S) {
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr
new file mode 100644
index 00000000000..160a1f99f63
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr
@@ -0,0 +1,49 @@
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:9:11
+   |
+LL |     match S("foo".to_string()) {
+   |           ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
+LL |
+LL |         S(_s) => {}
+   |           --
+   |           |
+   |           data moved here
+   |           move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |         S(ref _s) => {}
+   |           +++
+
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:16:17
+   |
+LL |     let S(_s) = S("foo".to_string());
+   |           --    ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
+   |           |
+   |           data moved here
+   |           move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |     let S(ref _s) = S("foo".to_string());
+   |           +++
+
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:20:19
+   |
+LL | fn move_in_fn_arg(S(_s): S) {
+   |                   ^^--^
+   |                   | |
+   |                   | data moved here
+   |                   | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+   |                   cannot move out of here
+   |
+help: consider borrowing the pattern binding
+   |
+LL | fn move_in_fn_arg(S(ref _s): S) {
+   |                     +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0509`.
diff --git a/tests/ui/borrowck/borrowck-move-out-of-vec-tail.rs b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.rs
new file mode 100644
index 00000000000..8ece81a3c84
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.rs
@@ -0,0 +1,33 @@
+// Test that we do not permit moves from &[] matched by a vec pattern.
+
+#[derive(Clone, Debug)]
+struct Foo {
+    string: String
+}
+
+pub fn main() {
+    let x = vec![
+        Foo { string: "foo".to_string() },
+        Foo { string: "bar".to_string() },
+        Foo { string: "baz".to_string() }
+    ];
+    let x: &[Foo] = &x;
+    match *x {
+        [_, ref tail @ ..] => {
+            match tail {
+            //~^ ERROR cannot move out of type `[Foo]`
+                &[Foo { string: a },
+                  Foo { string: b }] => {
+                }
+                _ => {
+                    unreachable!();
+                }
+            }
+            let z = tail[0].clone();
+            println!("{:?}", z);
+        }
+        _ => {
+            unreachable!();
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-move-out-of-vec-tail.stderr b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.stderr
new file mode 100644
index 00000000000..9ff20a1f46a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.stderr
@@ -0,0 +1,21 @@
+error[E0508]: cannot move out of type `[Foo]`, a non-copy slice
+  --> $DIR/borrowck-move-out-of-vec-tail.rs:17:19
+   |
+LL |             match tail {
+   |                   ^^^^ cannot move out of here
+LL |
+LL |                 &[Foo { string: a },
+   |                                 - data moved here
+LL |                   Foo { string: b }] => {
+   |                                 - ...and here
+   |
+   = note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the borrow
+   |
+LL -                 &[Foo { string: a },
+LL +                 [Foo { string: a },
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.rs b/tests/ui/borrowck/borrowck-move-subcomponent.rs
new file mode 100644
index 00000000000..38abd193222
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-subcomponent.rs
@@ -0,0 +1,17 @@
+// Tests that the borrow checker checks all components of a path when moving
+// out.
+
+
+
+struct S {
+  x : Box<isize>
+}
+
+fn f<T>(_: T) {}
+
+fn main() {
+  let a : S = S { x : Box::new(1) };
+  let pb = &a;
+  let S { x: ax } = a;  //~ ERROR cannot move out
+  f(pb);
+}
diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
new file mode 100644
index 00000000000..8c9083fcf13
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `a.x` because it is borrowed
+  --> $DIR/borrowck-move-subcomponent.rs:15:14
+   |
+LL |   let pb = &a;
+   |            -- borrow of `a` occurs here
+LL |   let S { x: ax } = a;
+   |              ^^ move out of `a.x` occurs here
+LL |   f(pb);
+   |     -- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-multiple-borrows-interior-boxes.rs b/tests/ui/borrowck/borrowck-multiple-borrows-interior-boxes.rs
new file mode 100644
index 00000000000..96d2663500e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-multiple-borrows-interior-boxes.rs
@@ -0,0 +1,20 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// Test case from #39963.
+
+#[derive(Clone)]
+struct Foo(Option<Box<Foo>>, Option<Box<Foo>>);
+
+fn test(f: &mut Foo) {
+  match *f {
+    Foo(Some(ref mut left), Some(ref mut right)) => match **left {
+      Foo(Some(ref mut left), Some(ref mut right)) => panic!(),
+      _ => panic!(),
+    },
+    _ => panic!(),
+  }
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-multiple-captures.rs b/tests/ui/borrowck/borrowck-multiple-captures.rs
new file mode 100644
index 00000000000..57b3819ac51
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-multiple-captures.rs
@@ -0,0 +1,61 @@
+use std::thread;
+
+
+fn borrow<T>(_: &T) { }
+
+
+fn different_vars_after_borrows() {
+    let x1: Box<_> = Box::new(1);
+    let p1 = &x1;
+    let x2: Box<_> = Box::new(2);
+    let p2 = &x2;
+    thread::spawn(move|| {
+        //~^ ERROR cannot move out of `x1` because it is borrowed
+        //~| ERROR cannot move out of `x2` because it is borrowed
+        drop(x1);
+        drop(x2);
+    });
+    borrow(&*p1);
+    borrow(&*p2);
+}
+
+fn different_vars_after_moves() {
+    let x1: Box<_> = Box::new(1);
+    drop(x1);
+    let x2: Box<_> = Box::new(2);
+    drop(x2);
+    thread::spawn(move|| {
+        //~^ ERROR use of moved value: `x1`
+        //~| ERROR use of moved value: `x2`
+        drop(x1);
+        drop(x2);
+    });
+}
+
+fn same_var_after_borrow() {
+    let x: Box<_> = Box::new(1);
+    let p = &x;
+    thread::spawn(move|| {
+        //~^ ERROR cannot move out of `x` because it is borrowed
+        drop(x);
+        drop(x); //~ ERROR use of moved value: `x`
+    });
+    borrow(&*p);
+}
+
+fn same_var_after_move() {
+    let x: Box<_> = Box::new(1);
+    drop(x);
+    thread::spawn(move|| {
+        //~^ ERROR use of moved value: `x`
+        drop(x);
+        drop(x); //~ ERROR use of moved value: `x`
+    });
+}
+
+fn main() {
+    different_vars_after_borrows();
+    different_vars_after_moves();
+    same_var_after_borrow();
+    same_var_after_move();
+}
diff --git a/tests/ui/borrowck/borrowck-multiple-captures.stderr b/tests/ui/borrowck/borrowck-multiple-captures.stderr
new file mode 100644
index 00000000000..f94cbc30db4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-multiple-captures.stderr
@@ -0,0 +1,122 @@
+error[E0505]: cannot move out of `x1` because it is borrowed
+  --> $DIR/borrowck-multiple-captures.rs:12:19
+   |
+LL |     let p1 = &x1;
+   |              --- borrow of `x1` occurs here
+...
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ move out of `x1` occurs here
+...
+LL |         drop(x1);
+   |              -- move occurs due to use in closure
+...
+LL |     borrow(&*p1);
+   |            ---- borrow later used here
+
+error[E0505]: cannot move out of `x2` because it is borrowed
+  --> $DIR/borrowck-multiple-captures.rs:12:19
+   |
+LL |     let p2 = &x2;
+   |              --- borrow of `x2` occurs here
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ move out of `x2` occurs here
+...
+LL |         drop(x2);
+   |              -- move occurs due to use in closure
+...
+LL |     borrow(&*p2);
+   |            ---- borrow later used here
+
+error[E0382]: use of moved value: `x1`
+  --> $DIR/borrowck-multiple-captures.rs:27:19
+   |
+LL |     let x1: Box<_> = Box::new(1);
+   |         -- move occurs because `x1` has type `Box<i32>`, which does not implement the `Copy` trait
+LL |     drop(x1);
+   |          -- value moved here
+...
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ value used here after move
+...
+LL |         drop(x1);
+   |              -- use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x1.clone());
+   |            ++++++++
+
+error[E0382]: use of moved value: `x2`
+  --> $DIR/borrowck-multiple-captures.rs:27:19
+   |
+LL |     let x2: Box<_> = Box::new(2);
+   |         -- move occurs because `x2` has type `Box<i32>`, which does not implement the `Copy` trait
+LL |     drop(x2);
+   |          -- value moved here
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ value used here after move
+...
+LL |         drop(x2);
+   |              -- use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x2.clone());
+   |            ++++++++
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrowck-multiple-captures.rs:41:14
+   |
+LL |         drop(x);
+   |              - value moved here
+LL |         drop(x);
+   |              ^ value used here after move
+   |
+   = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/borrowck-multiple-captures.rs:38:19
+   |
+LL |     let p = &x;
+   |             -- borrow of `x` occurs here
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ move out of `x` occurs here
+LL |
+LL |         drop(x);
+   |              - move occurs due to use in closure
+...
+LL |     borrow(&*p);
+   |            --- borrow later used here
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrowck-multiple-captures.rs:52:14
+   |
+LL |         drop(x);
+   |              - value moved here
+LL |         drop(x);
+   |              ^ value used here after move
+   |
+   = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrowck-multiple-captures.rs:49:19
+   |
+LL |     let x: Box<_> = Box::new(1);
+   |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+LL |     drop(x);
+   |          - value moved here
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^ value used here after move
+LL |
+LL |         drop(x);
+   |              - use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x.clone());
+   |           ++++++++
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0382, E0505.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.rs b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.rs
new file mode 100644
index 00000000000..a79a239cbe0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let x: isize = 3;
+    let y: &mut isize = &mut x; //~ ERROR cannot borrow
+    *y = 5;
+    println!("{}", *y);
+}
diff --git a/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr
new file mode 100644
index 00000000000..20528e3f0ee
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25
+   |
+LL |     let y: &mut isize = &mut x;
+   |                         ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: isize = 3;
+   |         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.rs b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.rs
new file mode 100644
index 00000000000..e3d76398bc2
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.rs
@@ -0,0 +1,15 @@
+// Test to ensure we only report an error for the first issued loan that
+// conflicts with a new loan, as opposed to every issued loan.  This keeps us
+// down to O(n) errors (for n problem lines), instead of O(n^2) errors.
+
+fn main() {
+    let mut x = 1;
+    let mut addr = vec![];
+    loop {
+        match 1 {
+            1 => { addr.push(&mut x); } //~ ERROR [E0499]
+            2 => { addr.push(&mut x); } //~ ERROR [E0499]
+            _ => { addr.push(&mut x); } //~ ERROR [E0499]
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
new file mode 100644
index 00000000000..d2b845619c7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
@@ -0,0 +1,35 @@
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-mut-borrow-linear-errors.rs:10:30
+   |
+LL |             1 => { addr.push(&mut x); }
+   |                              ^^^^^^ second mutable borrow occurs here
+LL |             2 => { addr.push(&mut x); }
+LL |             _ => { addr.push(&mut x); }
+   |                    -----------------
+   |                    |         |
+   |                    |         first mutable borrow occurs here
+   |                    first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-mut-borrow-linear-errors.rs:11:30
+   |
+LL |             2 => { addr.push(&mut x); }
+   |                              ^^^^^^ second mutable borrow occurs here
+LL |             _ => { addr.push(&mut x); }
+   |                    -----------------
+   |                    |         |
+   |                    |         first mutable borrow occurs here
+   |                    first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30
+   |
+LL |             _ => { addr.push(&mut x); }
+   |                    ----------^^^^^^-
+   |                    |         |
+   |                    |         `x` was mutably borrowed here in the previous iteration of the loop
+   |                    first borrow used here, in later iteration of loop
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs
new file mode 100644
index 00000000000..6174893bae9
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs
@@ -0,0 +1,28 @@
+// Test that attempt to mutably borrow `&mut` pointer while pointee is
+// borrowed yields an error.
+//
+// Example from compiler/rustc_borrowck/borrowck/README.md
+
+
+
+fn foo<'a>(mut t0: &'a mut isize,
+           mut t1: &'a mut isize) {
+    let p: &isize = &*t0;     // Freezes `*t0`
+    let mut t2 = &mut t0;   //~ ERROR cannot borrow `t0`
+    **t2 += 1;              // Mutates `*t0`
+    p.use_ref();
+}
+
+fn bar<'a>(mut t0: &'a mut isize,
+           mut t1: &'a mut isize) {
+    let p: &mut isize = &mut *t0; // Claims `*t0`
+    let mut t2 = &mut t0;       //~ ERROR cannot borrow `t0`
+    **t2 += 1;                  // Mutates `*t0` but not through `*p`
+    p.use_mut();
+}
+
+fn main() {
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr
new file mode 100644
index 00000000000..ef811b84905
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr
@@ -0,0 +1,26 @@
+error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:11:18
+   |
+LL |     let p: &isize = &*t0;     // Freezes `*t0`
+   |                     ---- immutable borrow occurs here
+LL |     let mut t2 = &mut t0;
+   |                  ^^^^^^^ mutable borrow occurs here
+LL |     **t2 += 1;              // Mutates `*t0`
+LL |     p.use_ref();
+   |     ----------- immutable borrow later used here
+
+error[E0499]: cannot borrow `t0` as mutable more than once at a time
+  --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:19:18
+   |
+LL |     let p: &mut isize = &mut *t0; // Claims `*t0`
+   |                         -------- first mutable borrow occurs here
+LL |     let mut t2 = &mut t0;
+   |                  ^^^^^^^ second mutable borrow occurs here
+LL |     **t2 += 1;                  // Mutates `*t0` but not through `*p`
+LL |     p.use_mut();
+   |     ----------- first borrow later used here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0499, E0502.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.rs b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.rs
new file mode 100644
index 00000000000..8e23571cedc
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.rs
@@ -0,0 +1,8 @@
+fn write(v: &mut [isize]) {
+    v[0] += 1;
+}
+
+fn main() {
+    let v = vec![1, 2, 3];
+    write(&mut v); //~ ERROR cannot borrow
+}
diff --git a/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr
new file mode 100644
index 00000000000..8ab472e64c7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11
+   |
+LL |     write(&mut v);
+   |           ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut v = vec![1, 2, 3];
+   |         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrowck-mut-uniq.rs b/tests/ui/borrowck/borrowck-mut-uniq.rs
new file mode 100644
index 00000000000..255b4995b64
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-uniq.rs
@@ -0,0 +1,32 @@
+// run-pass
+
+use std::mem::swap;
+
+#[derive(Debug)]
+struct Ints {sum: Box<isize>, values: Vec<isize> }
+
+fn add_int(x: &mut Ints, v: isize) {
+    *x.sum += v;
+    let mut values = Vec::new();
+    swap(&mut values, &mut x.values);
+    values.push(v);
+    swap(&mut values, &mut x.values);
+}
+
+fn iter_ints<F>(x: &Ints, mut f: F) -> bool where F: FnMut(&isize) -> bool {
+    let l = x.values.len();
+    (0..l).all(|i| f(&x.values[i]))
+}
+
+pub fn main() {
+    let mut ints: Box<_> = Box::new(Ints {sum: Box::new(0), values: Vec::new()});
+    add_int(&mut *ints, 22);
+    add_int(&mut *ints, 44);
+
+    iter_ints(&*ints, |i| {
+        println!("isize = {:?}", *i);
+        true
+    });
+
+    println!("ints={:?}", ints);
+}
diff --git a/tests/ui/borrowck/borrowck-mut-vec-as-imm-slice.rs b/tests/ui/borrowck/borrowck-mut-vec-as-imm-slice.rs
new file mode 100644
index 00000000000..d2b0c01545e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mut-vec-as-imm-slice.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+
+fn want_slice(v: &[isize]) -> isize {
+    let mut sum = 0;
+    for i in v { sum += *i; }
+    sum
+}
+
+fn has_mut_vec(v: Vec<isize> ) -> isize {
+    want_slice(&v)
+}
+
+pub fn main() {
+    assert_eq!(has_mut_vec(vec![1, 2, 3]), 6);
+}
diff --git a/tests/ui/borrowck/borrowck-mutate-in-guard.rs b/tests/ui/borrowck/borrowck-mutate-in-guard.rs
new file mode 100644
index 00000000000..d80a9e81576
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mutate-in-guard.rs
@@ -0,0 +1,34 @@
+#![feature(if_let_guard)]
+
+enum Enum<'a> {
+    A(&'a isize),
+    B(bool),
+}
+
+fn if_guard() -> isize {
+    let mut n = 42;
+    let mut x = Enum::A(&mut n);
+    match x {
+        Enum::A(_) if { x = Enum::B(false); false } => 1,
+        //~^ ERROR cannot assign `x` in match guard
+        Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
+        //~^ ERROR cannot mutably borrow `x` in match guard
+        Enum::A(p) => *p,
+        Enum::B(_) => 2,
+    }
+}
+
+fn if_let_guard() -> isize {
+    let mut n = 42;
+    let mut x = Enum::A(&mut n);
+    match x {
+        Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+        //~^ ERROR cannot assign `x` in match guard
+        Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+        //~^ ERROR cannot mutably borrow `x` in match guard
+        Enum::A(p) => *p,
+        Enum::B(_) => 2,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-mutate-in-guard.stderr b/tests/ui/borrowck/borrowck-mutate-in-guard.stderr
new file mode 100644
index 00000000000..dbb3272fdc3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-mutate-in-guard.stderr
@@ -0,0 +1,37 @@
+error[E0510]: cannot assign `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:12:25
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
+   |                         ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:14:33
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
+   |                                 ^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot assign `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:25:40
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+LL |         Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+   |                                        ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:27:48
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |         Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+   |                                                ^^^^^^ cannot mutably borrow
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0510`.
diff --git a/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs
new file mode 100644
index 00000000000..f035049d82d
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs
@@ -0,0 +1,20 @@
+struct Node_ {
+    a: Box<Cycle>
+}
+
+enum Cycle {
+    Node(Node_),
+    Empty,
+}
+
+fn main() {
+    let mut x: Box<_> = Box::new(Cycle::Node(Node_ {a: Box::new(Cycle::Empty)}));
+
+    // Create a cycle!
+    match *x {
+      Cycle::Node(ref mut y) => {
+        y.a = x; //~ ERROR cannot move out of
+      }
+      Cycle::Empty => {}
+    };
+}
diff --git a/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr
new file mode 100644
index 00000000000..3462b7610d3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/borrowck-no-cycle-in-exchange-heap.rs:16:15
+   |
+LL |       Cycle::Node(ref mut y) => {
+   |                   --------- borrow of `x.0` occurs here
+LL |         y.a = x;
+   |         ---   ^ move out of `x` occurs here
+   |         |
+   |         borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-object-lifetime.rs b/tests/ui/borrowck/borrowck-object-lifetime.rs
new file mode 100644
index 00000000000..137a9adbc40
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-object-lifetime.rs
@@ -0,0 +1,40 @@
+// Test that borrows that occur due to calls to object methods
+// properly "claim" the object path.
+
+
+
+trait Foo {
+    fn borrowed(&self) -> &();
+    fn mut_borrowed(&mut self) -> &();
+}
+
+fn borrowed_receiver(x: &dyn Foo) {
+    let y = x.borrowed();
+    let z = x.borrowed();
+    z.use_ref();
+    y.use_ref();
+}
+
+fn mut_borrowed_receiver(x: &mut dyn Foo) {
+    let y = x.borrowed();
+    let z = x.mut_borrowed(); //~ ERROR cannot borrow
+    y.use_ref();
+}
+
+fn mut_owned_receiver(mut x: Box<dyn Foo>) {
+    let y = x.borrowed();
+    let z = &mut x; //~ ERROR cannot borrow
+    y.use_ref();
+}
+
+fn imm_owned_receiver(mut x: Box<dyn Foo>) {
+    let y = x.borrowed();
+    let z = &x;
+    z.use_ref();
+    y.use_ref();
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-object-lifetime.stderr b/tests/ui/borrowck/borrowck-object-lifetime.stderr
new file mode 100644
index 00000000000..215ed760ae1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-object-lifetime.stderr
@@ -0,0 +1,23 @@
+error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-object-lifetime.rs:20:13
+   |
+LL |     let y = x.borrowed();
+   |             ------------ immutable borrow occurs here
+LL |     let z = x.mut_borrowed();
+   |             ^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     y.use_ref();
+   |     ----------- immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-object-lifetime.rs:26:13
+   |
+LL |     let y = x.borrowed();
+   |             ------------ immutable borrow occurs here
+LL |     let z = &mut x;
+   |             ^^^^^^ mutable borrow occurs here
+LL |     y.use_ref();
+   |     ----------- immutable borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-or-init.rs b/tests/ui/borrowck/borrowck-or-init.rs
new file mode 100644
index 00000000000..079cf899e6d
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-or-init.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let i: isize;
+
+    println!("{}", false || { i = 5; true });
+    println!("{}", i); //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-or-init.stderr b/tests/ui/borrowck/borrowck-or-init.stderr
new file mode 100644
index 00000000000..16d66bf40d1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-or-init.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `i` is possibly-uninitialized
+  --> $DIR/borrowck-or-init.rs:5:20
+   |
+LL |     let i: isize;
+   |         - binding declared here but left uninitialized
+LL |
+LL |     println!("{}", false || { i = 5; true });
+   |                               ----- binding initialized here in some conditions
+LL |     println!("{}", i);
+   |                    ^ `i` used here but it is possibly-uninitialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-overloaded-call.rs b/tests/ui/borrowck/borrowck-overloaded-call.rs
new file mode 100644
index 00000000000..7b16bf666d0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-call.rs
@@ -0,0 +1,80 @@
+#![feature(fn_traits, unboxed_closures)]
+
+use std::ops::{Fn, FnMut, FnOnce};
+
+struct SFn {
+    x: isize,
+    y: isize,
+}
+
+impl Fn<(isize,)> for SFn {
+    extern "rust-call" fn call(&self, (z,): (isize,)) -> isize {
+        self.x * self.y * z
+    }
+}
+
+impl FnMut<(isize,)> for SFn {
+    extern "rust-call" fn call_mut(&mut self, args: (isize,)) -> isize { self.call(args) }
+}
+
+impl FnOnce<(isize,)> for SFn {
+    type Output = isize;
+    extern "rust-call" fn call_once(self, args: (isize,)) -> isize { self.call(args) }
+}
+
+struct SFnMut {
+    x: isize,
+    y: isize,
+}
+
+impl FnMut<(isize,)> for SFnMut {
+    extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize {
+        self.x * self.y * z
+    }
+}
+
+impl FnOnce<(isize,)> for SFnMut {
+    type Output = isize;
+    extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) }
+}
+
+struct SFnOnce {
+    x: String,
+}
+
+impl FnOnce<(String,)> for SFnOnce {
+    type Output = usize;
+
+    extern "rust-call" fn call_once(self, (z,): (String,)) -> usize {
+        self.x.len() + z.len()
+    }
+}
+
+fn f() {
+    let mut s = SFn {
+        x: 1,
+        y: 2,
+    };
+    let sp = &mut s;
+    s(3);   //~ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+    use_mut(sp);
+}
+fn g() {
+    let s = SFnMut {
+        x: 1,
+        y: 2,
+    };
+    s(3);   //~ ERROR cannot borrow `s` as mutable, as it is not declared as mutable
+}
+
+fn h() {
+    let s = SFnOnce {
+        x: "hello".to_string(),
+    };
+    s(" world".to_string());
+    s(" world".to_string());    //~ ERROR use of moved value: `s`
+}
+
+fn main() {}
+
+fn use_mut<T>(_: &mut T) { }
diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr
new file mode 100644
index 00000000000..723b19f4124
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr
@@ -0,0 +1,36 @@
+error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-overloaded-call.rs:59:5
+   |
+LL |     let sp = &mut s;
+   |              ------ mutable borrow occurs here
+LL |     s(3);
+   |     ^ immutable borrow occurs here
+LL |     use_mut(sp);
+   |             -- mutable borrow later used here
+
+error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-overloaded-call.rs:67:5
+   |
+LL |     s(3);
+   |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut s = SFnMut {
+   |         +++
+
+error[E0382]: use of moved value: `s`
+  --> $DIR/borrowck-overloaded-call.rs:75:5
+   |
+LL |     let s = SFnOnce {
+   |         - move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait
+...
+LL |     s(" world".to_string());
+   |     - value moved here
+LL |     s(" world".to_string());
+   |     ^ value used here after move
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0502, E0596.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs
new file mode 100644
index 00000000000..0e3e01a9332
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs
@@ -0,0 +1,36 @@
+// Check that we properly record borrows when we are doing an
+// overloaded, autoderef of a value obtained via an overloaded index
+// operator. The accounting of the all the implicit things going on
+// here is rather subtle. Issue #20232.
+
+use std::ops::{Deref, Index};
+
+struct MyVec<T> { x: T }
+
+impl<T> Index<usize> for MyVec<T> {
+    type Output = T;
+    fn index(&self, _: usize) -> &T {
+        &self.x
+    }
+}
+
+struct MyPtr<T> { x: T }
+
+impl<T> Deref for MyPtr<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        &self.x
+    }
+}
+
+struct Foo { f: usize }
+
+fn main() {
+    let mut v = MyVec { x: MyPtr { x: Foo { f: 22 } } };
+    let i = &v[0].f;
+    v = MyVec { x: MyPtr { x: Foo { f: 23 } } };
+    //~^ ERROR cannot assign to `v` because it is borrowed
+    read(*i);
+}
+
+fn read(_: usize) { }
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr
new file mode 100644
index 00000000000..5d52e491918
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `v` because it is borrowed
+  --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:31:5
+   |
+LL |     let i = &v[0].f;
+   |              - borrow of `v` occurs here
+LL |     v = MyVec { x: MyPtr { x: Foo { f: 23 } } };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here
+LL |
+LL |     read(*i);
+   |          -- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-autoderef.rs b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.rs
new file mode 100644
index 00000000000..3d3a3afd341
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.rs
@@ -0,0 +1,97 @@
+// Test that we still see borrowck errors of various kinds when using
+// indexing and autoderef in combination.
+
+use std::ops::{Index, IndexMut};
+
+
+
+struct Foo {
+    x: isize,
+    y: isize,
+}
+
+impl<'a> Index<&'a String> for Foo {
+    type Output = isize;
+
+    fn index(&self, z: &String) -> &isize {
+        if *z == "x" {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl<'a> IndexMut<&'a String> for Foo {
+    fn index_mut(&mut self, z: &String) -> &mut isize {
+        if *z == "x" {
+            &mut self.x
+        } else {
+            &mut self.y
+        }
+    }
+}
+
+fn test1(mut f: Box<Foo>, s: String) {
+    let p = &mut f[&s];
+    let q = &f[&s]; //~ ERROR cannot borrow
+    p.use_mut();
+}
+
+fn test2(mut f: Box<Foo>, s: String) {
+    let p = &mut f[&s];
+    let q = &mut f[&s]; //~ ERROR cannot borrow
+    p.use_mut();
+}
+
+struct Bar {
+    foo: Foo
+}
+
+fn test3(mut f: Box<Bar>, s: String) {
+    let p = &mut f.foo[&s];
+    let q = &mut f.foo[&s]; //~ ERROR cannot borrow
+    p.use_mut();
+}
+
+fn test4(mut f: Box<Bar>, s: String) {
+    let p = &f.foo[&s];
+    let q = &f.foo[&s];
+    p.use_ref();
+}
+
+fn test5(mut f: Box<Bar>, s: String) {
+    let p = &f.foo[&s];
+    let q = &mut f.foo[&s]; //~ ERROR cannot borrow
+    p.use_ref();
+}
+
+fn test6(mut f: Box<Bar>, g: Foo, s: String) {
+    let p = &f.foo[&s];
+    f.foo = g; //~ ERROR cannot assign
+    p.use_ref();
+}
+
+fn test7(mut f: Box<Bar>, g: Bar, s: String) {
+    let p = &f.foo[&s];
+    *f = g; //~ ERROR cannot assign
+    p.use_ref();
+}
+
+fn test8(mut f: Box<Bar>, g: Foo, s: String) {
+    let p = &mut f.foo[&s];
+    f.foo = g; //~ ERROR cannot assign
+    p.use_mut();
+}
+
+fn test9(mut f: Box<Bar>, g: Bar, s: String) {
+    let p = &mut f.foo[&s];
+    *f = g; //~ ERROR cannot assign
+    p.use_mut();
+}
+
+fn main() {
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr
new file mode 100644
index 00000000000..087f2ac799e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr
@@ -0,0 +1,84 @@
+error[E0502]: cannot borrow `*f` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:37:14
+   |
+LL |     let p = &mut f[&s];
+   |                  - mutable borrow occurs here
+LL |     let q = &f[&s];
+   |              ^ immutable borrow occurs here
+LL |     p.use_mut();
+   |     ----------- mutable borrow later used here
+
+error[E0499]: cannot borrow `*f` as mutable more than once at a time
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:43:18
+   |
+LL |     let p = &mut f[&s];
+   |                  - first mutable borrow occurs here
+LL |     let q = &mut f[&s];
+   |                  ^ second mutable borrow occurs here
+LL |     p.use_mut();
+   |     ----------- first borrow later used here
+
+error[E0499]: cannot borrow `f.foo` as mutable more than once at a time
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:53:18
+   |
+LL |     let p = &mut f.foo[&s];
+   |                  ----- first mutable borrow occurs here
+LL |     let q = &mut f.foo[&s];
+   |                  ^^^^^ second mutable borrow occurs here
+LL |     p.use_mut();
+   |     ----------- first borrow later used here
+
+error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:65:18
+   |
+LL |     let p = &f.foo[&s];
+   |              ----- immutable borrow occurs here
+LL |     let q = &mut f.foo[&s];
+   |                  ^^^^^ mutable borrow occurs here
+LL |     p.use_ref();
+   |     ----------- immutable borrow later used here
+
+error[E0506]: cannot assign to `f.foo` because it is borrowed
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5
+   |
+LL |     let p = &f.foo[&s];
+   |              ----- borrow of `f.foo` occurs here
+LL |     f.foo = g;
+   |     ^^^^^^^^^ assignment to borrowed `f.foo` occurs here
+LL |     p.use_ref();
+   |     ----------- borrow later used here
+
+error[E0506]: cannot assign to `*f` because it is borrowed
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5
+   |
+LL |     let p = &f.foo[&s];
+   |              ----- borrow of `*f` occurs here
+LL |     *f = g;
+   |     ^^^^^^ assignment to borrowed `*f` occurs here
+LL |     p.use_ref();
+   |     ----------- borrow later used here
+
+error[E0506]: cannot assign to `f.foo` because it is borrowed
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5
+   |
+LL |     let p = &mut f.foo[&s];
+   |                  ----- borrow of `f.foo` occurs here
+LL |     f.foo = g;
+   |     ^^^^^^^^^ assignment to borrowed `f.foo` occurs here
+LL |     p.use_mut();
+   |     ----------- borrow later used here
+
+error[E0506]: cannot assign to `*f` because it is borrowed
+  --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5
+   |
+LL |     let p = &mut f.foo[&s];
+   |                  ----- borrow of `*f` occurs here
+LL |     *f = g;
+   |     ^^^^^^ assignment to borrowed `*f` occurs here
+LL |     p.use_mut();
+   |     ----------- borrow later used here
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0506.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs
new file mode 100644
index 00000000000..344d75cc58f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs
@@ -0,0 +1,22 @@
+use std::ops::Index;
+
+struct MyVec<T> {
+    data: Vec<T>,
+}
+
+impl<T> Index<usize> for MyVec<T> {
+    type Output = T;
+
+    fn index(&self, i: usize) -> &T {
+        &self.data[i]
+    }
+}
+
+
+
+fn main() {
+    let v = MyVec::<Box<_>> { data: vec![Box::new(1), Box::new(2), Box::new(3)] };
+    let good = &v[0]; // Shouldn't fail here
+    let bad = v[0];
+    //~^ ERROR cannot move out of index of `MyVec<Box<i32>>`
+}
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr
new file mode 100644
index 00000000000..f5f4817e9bf
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr
@@ -0,0 +1,14 @@
+error[E0507]: cannot move out of index of `MyVec<Box<i32>>`
+  --> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15
+   |
+LL |     let bad = v[0];
+   |               ^^^^ move occurs because value has type `Box<i32>`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |     let bad = &v[0];
+   |               +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-index.rs b/tests/ui/borrowck/borrowck-overloaded-index-move-index.rs
new file mode 100644
index 00000000000..00f44831456
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-move-index.rs
@@ -0,0 +1,68 @@
+use std::ops::{Index, IndexMut};
+
+struct Foo {
+    x: isize,
+    y: isize,
+}
+
+impl Index<String> for Foo {
+    type Output = isize;
+
+    fn index(&self, z: String) -> &isize {
+        if z == "x" {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl IndexMut<String> for Foo {
+    fn index_mut(&mut self, z: String) -> &mut isize {
+        if z == "x" {
+            &mut self.x
+        } else {
+            &mut self.y
+        }
+    }
+}
+
+struct Bar {
+    x: isize,
+}
+
+impl Index<isize> for Bar {
+    type Output = isize;
+
+    fn index<'a>(&'a self, z: isize) -> &'a isize {
+        &self.x
+    }
+}
+
+fn main() {
+    let mut f = Foo {
+        x: 1,
+        y: 2,
+    };
+    let mut s = "hello".to_string();
+    let rs = &mut s;
+
+    println!("{}", f[s]);
+    //~^ ERROR cannot move out of `s` because it is borrowed
+
+    f[s] = 10;
+    //~^ ERROR cannot move out of `s` because it is borrowed
+    //~| ERROR use of moved value: `s`
+
+    let s = Bar {
+        x: 1,
+    };
+    let i = 2;
+    let _j = &i;
+    println!("{}", s[i]); // no error, i is copy
+    println!("{}", s[i]);
+
+    use_mut(rs);
+}
+
+fn use_mut<T>(_: &mut T) { }
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr
new file mode 100644
index 00000000000..fb0e274c291
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr
@@ -0,0 +1,45 @@
+error[E0505]: cannot move out of `s` because it is borrowed
+  --> $DIR/borrowck-overloaded-index-move-index.rs:50:22
+   |
+LL |     let rs = &mut s;
+   |              ------ borrow of `s` occurs here
+LL |
+LL |     println!("{}", f[s]);
+   |                      ^ move out of `s` occurs here
+...
+LL |     use_mut(rs);
+   |             -- borrow later used here
+
+error[E0505]: cannot move out of `s` because it is borrowed
+  --> $DIR/borrowck-overloaded-index-move-index.rs:53:7
+   |
+LL |     let rs = &mut s;
+   |              ------ borrow of `s` occurs here
+...
+LL |     f[s] = 10;
+   |       ^ move out of `s` occurs here
+...
+LL |     use_mut(rs);
+   |             -- borrow later used here
+
+error[E0382]: use of moved value: `s`
+  --> $DIR/borrowck-overloaded-index-move-index.rs:53:7
+   |
+LL |     let mut s = "hello".to_string();
+   |         ----- move occurs because `s` has type `String`, which does not implement the `Copy` trait
+...
+LL |     println!("{}", f[s]);
+   |                      - value moved here
+...
+LL |     f[s] = 10;
+   |       ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     println!("{}", f[s.clone()]);
+   |                       ++++++++
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0505.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-ref-index.rs b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.rs
new file mode 100644
index 00000000000..8adafaa8e93
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.rs
@@ -0,0 +1,59 @@
+use std::ops::{Index, IndexMut};
+
+struct Foo {
+    x: isize,
+    y: isize,
+}
+
+impl<'a> Index<&'a String> for Foo {
+    type Output = isize;
+
+    fn index(&self, z: &String) -> &isize {
+        if *z == "x" {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl<'a> IndexMut<&'a String> for Foo {
+    fn index_mut(&mut self, z: &String) -> &mut isize {
+        if *z == "x" {
+            &mut self.x
+        } else {
+            &mut self.y
+        }
+    }
+}
+
+struct Bar {
+    x: isize,
+}
+
+impl Index<isize> for Bar {
+    type Output = isize;
+
+    fn index<'a>(&'a self, z: isize) -> &'a isize {
+        &self.x
+    }
+}
+
+fn main() {
+    let mut f = Foo {
+        x: 1,
+        y: 2,
+    };
+    let mut s = "hello".to_string();
+    let rs = &mut s;
+    println!("{}", f[&s]);
+    //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+    f[&s] = 10;
+    //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+    let s = Bar {
+        x: 1,
+    };
+    s[2] = 20;
+    //~^ ERROR cannot assign to data in an index of `Bar`
+    drop(rs);
+}
diff --git a/tests/ui/borrowck/borrowck-overloaded-index-ref-index.stderr b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.stderr
new file mode 100644
index 00000000000..2f92c1ebe5e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.stderr
@@ -0,0 +1,35 @@
+error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-overloaded-index-ref-index.rs:49:22
+   |
+LL |     let rs = &mut s;
+   |              ------ mutable borrow occurs here
+LL |     println!("{}", f[&s]);
+   |                      ^^ immutable borrow occurs here
+...
+LL |     drop(rs);
+   |          -- mutable borrow later used here
+
+error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-overloaded-index-ref-index.rs:51:7
+   |
+LL |     let rs = &mut s;
+   |              ------ mutable borrow occurs here
+...
+LL |     f[&s] = 10;
+   |       ^^ immutable borrow occurs here
+...
+LL |     drop(rs);
+   |          -- mutable borrow later used here
+
+error[E0594]: cannot assign to data in an index of `Bar`
+  --> $DIR/borrowck-overloaded-index-ref-index.rs:56:5
+   |
+LL |     s[2] = 20;
+   |     ^^^^^^^^^ cannot assign
+   |
+   = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Bar`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0502, E0594.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-1.rs b/tests/ui/borrowck/borrowck-partial-reinit-1.rs
new file mode 100644
index 00000000000..4e695158154
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-1.rs
@@ -0,0 +1,39 @@
+struct Test;
+
+struct Test2 {
+    b: Option<Test>,
+}
+
+struct Test3(Option<Test>);
+
+impl Drop for Test {
+    fn drop(&mut self) {
+        println!("dropping!");
+    }
+}
+
+impl Drop for Test2 {
+    fn drop(&mut self) {}
+}
+
+impl Drop for Test3 {
+    fn drop(&mut self) {}
+}
+
+fn stuff() {
+    let mut t = Test2 { b: None };
+    let u = Test;
+    drop(t);
+    t.b = Some(u);
+    //~^ ERROR assign of moved value: `t`
+
+    let mut t = Test3(None);
+    let u = Test;
+    drop(t);
+    t.0 = Some(u);
+    //~^ ERROR assign of moved value: `t`
+}
+
+fn main() {
+    stuff()
+}
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-1.stderr b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr
new file mode 100644
index 00000000000..65f2bd6cfbd
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr
@@ -0,0 +1,25 @@
+error[E0382]: assign of moved value: `t`
+  --> $DIR/borrowck-partial-reinit-1.rs:27:5
+   |
+LL |     let mut t = Test2 { b: None };
+   |         ----- move occurs because `t` has type `Test2`, which does not implement the `Copy` trait
+LL |     let u = Test;
+LL |     drop(t);
+   |          - value moved here
+LL |     t.b = Some(u);
+   |     ^^^ value assigned here after move
+
+error[E0382]: assign of moved value: `t`
+  --> $DIR/borrowck-partial-reinit-1.rs:33:5
+   |
+LL |     let mut t = Test3(None);
+   |         ----- move occurs because `t` has type `Test3`, which does not implement the `Copy` trait
+LL |     let u = Test;
+LL |     drop(t);
+   |          - value moved here
+LL |     t.0 = Some(u);
+   |     ^^^ value assigned here after move
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-2.rs b/tests/ui/borrowck/borrowck-partial-reinit-2.rs
new file mode 100644
index 00000000000..06cd322e77e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-2.rs
@@ -0,0 +1,23 @@
+struct Test {
+    a: isize,
+    b: Option<Box<Test>>,
+}
+
+impl Drop for Test {
+    fn drop(&mut self) {
+        println!("Dropping {}", self.a);
+    }
+}
+
+fn stuff() {
+    let mut t = Test { a: 1, b: None};
+    let mut u = Test { a: 2, b: Some(Box::new(t))};
+    t.b = Some(Box::new(u));
+    //~^ ERROR assign of moved value: `t`
+    println!("done");
+}
+
+fn main() {
+    stuff();
+    println!("Hello, world!")
+}
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-2.stderr b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr
new file mode 100644
index 00000000000..36a871fbb12
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr
@@ -0,0 +1,13 @@
+error[E0382]: assign of moved value: `t`
+  --> $DIR/borrowck-partial-reinit-2.rs:15:5
+   |
+LL |     let mut t = Test { a: 1, b: None};
+   |         ----- move occurs because `t` has type `Test`, which does not implement the `Copy` trait
+LL |     let mut u = Test { a: 2, b: Some(Box::new(t))};
+   |                                               - value moved here
+LL |     t.b = Some(Box::new(u));
+   |     ^^^ value assigned here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-3.rs b/tests/ui/borrowck/borrowck-partial-reinit-3.rs
new file mode 100644
index 00000000000..ca484315ba5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-3.rs
@@ -0,0 +1,13 @@
+use std::mem;
+
+struct Test { f: usize }
+impl Drop for Test {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    let mut x = (Test { f: 2 }, Test { f: 4 });
+    mem::drop(x.0);
+    x.0.f = 3;
+    //~^ ERROR assign of moved value: `x.0`
+}
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-3.stderr b/tests/ui/borrowck/borrowck-partial-reinit-3.stderr
new file mode 100644
index 00000000000..05f5411eed6
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-3.stderr
@@ -0,0 +1,13 @@
+error[E0382]: assign of moved value: `x.0`
+  --> $DIR/borrowck-partial-reinit-3.rs:11:5
+   |
+LL |     mem::drop(x.0);
+   |               --- value moved here
+LL |     x.0.f = 3;
+   |     ^^^^^^^^^ value assigned here after move
+   |
+   = note: move occurs because `x.0` has type `Test`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-4.rs b/tests/ui/borrowck/borrowck-partial-reinit-4.rs
new file mode 100644
index 00000000000..a43a1936678
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-4.rs
@@ -0,0 +1,22 @@
+struct Test;
+
+struct Test2(Option<Test>);
+
+impl Drop for Test {
+    fn drop(&mut self) {
+        println!("dropping!");
+    }
+}
+
+impl Drop for Test2 {
+    fn drop(&mut self) {}
+}
+
+fn stuff() {
+    let mut x : (Test2, Test2);
+    (x.0).0 = Some(Test); //~ ERROR E0381
+}
+
+fn main() {
+    stuff()
+}
diff --git a/tests/ui/borrowck/borrowck-partial-reinit-4.stderr b/tests/ui/borrowck/borrowck-partial-reinit-4.stderr
new file mode 100644
index 00000000000..d12a482cb69
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-partial-reinit-4.stderr
@@ -0,0 +1,13 @@
+error[E0381]: assigned binding `x.0` isn't fully initialized
+  --> $DIR/borrowck-partial-reinit-4.rs:17:5
+   |
+LL |     let mut x : (Test2, Test2);
+   |         ----- binding declared here but left uninitialized
+LL |     (x.0).0 = Some(Test);
+   |     ^^^^^^^ `x.0` assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-pat-enum.rs b/tests/ui/borrowck/borrowck-pat-enum.rs
new file mode 100644
index 00000000000..7f9c5544d0b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-pat-enum.rs
@@ -0,0 +1,39 @@
+// run-pass
+#![allow(dead_code)]
+// ignore-pretty issue #37199
+
+fn match_ref(v: Option<isize>) -> isize {
+    match v {
+      Some(ref i) => {
+        *i
+      }
+      None => {0}
+    }
+}
+
+fn match_ref_unused(v: Option<isize>) {
+    match v {
+      Some(_) => {}
+      None => {}
+    }
+}
+
+fn impure(_i: isize) {
+}
+
+fn match_imm_reg(v: &Option<isize>) {
+    match *v {
+      Some(ref i) => {impure(*i)} // OK because immutable
+      None => {}
+    }
+}
+
+fn match_mut_reg(v: &mut Option<isize>) {
+    match *v {
+      Some(ref i) => {impure(*i)} // OK, frozen
+      None => {}
+    }
+}
+
+pub fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-pat-reassign-binding.rs b/tests/ui/borrowck/borrowck-pat-reassign-binding.rs
new file mode 100644
index 00000000000..f02c46fb8f0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-pat-reassign-binding.rs
@@ -0,0 +1,15 @@
+fn main() {
+    let mut x: Option<isize> = None;
+    match x {
+      None => {
+          // Note: on this branch, no borrow has occurred.
+          x = Some(0);
+      }
+      Some(ref i) => {
+          // But on this branch, `i` is an outstanding borrow
+          x = Some(*i+1); //~ ERROR cannot assign to `x` because it is borrowed
+          drop(i);
+      }
+    }
+    x.clone(); // just to prevent liveness warnings
+}
diff --git a/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr b/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr
new file mode 100644
index 00000000000..9e65ccf5a19
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/borrowck-pat-reassign-binding.rs:10:11
+   |
+LL |       Some(ref i) => {
+   |            ----- borrow of `x` occurs here
+LL |           // But on this branch, `i` is an outstanding borrow
+LL |           x = Some(*i+1);
+   |           ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+LL |           drop(i);
+   |                - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-pat-reassign-no-binding.rs b/tests/ui/borrowck/borrowck-pat-reassign-no-binding.rs
new file mode 100644
index 00000000000..1362fd8ce4c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-pat-reassign-no-binding.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+pub fn main() {
+    let mut x = None;
+    match x {
+      None => {
+        // It is ok to reassign x here, because there is in
+        // fact no outstanding loan of x!
+        x = Some(0);
+      }
+      Some(_) => { }
+    }
+    assert_eq!(x, Some(0));
+}
diff --git a/tests/ui/borrowck/borrowck-reborrow-from-mut.rs b/tests/ui/borrowck/borrowck-reborrow-from-mut.rs
new file mode 100644
index 00000000000..eef83c5ac1e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-reborrow-from-mut.rs
@@ -0,0 +1,99 @@
+struct Foo {
+  bar1: Bar,
+  bar2: Bar
+}
+
+struct Bar {
+  int1: isize,
+  int2: isize,
+}
+
+fn borrow_same_field_twice_mut_mut(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1;
+    let _bar2 = &mut foo.bar1;  //~ ERROR cannot borrow
+    use_mut(_bar1);
+}
+fn borrow_same_field_twice_mut_imm(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1;
+    let _bar2 = &foo.bar1;  //~ ERROR cannot borrow
+    use_mut(_bar1);
+}
+fn borrow_same_field_twice_imm_mut(foo: &mut Foo) {
+    let _bar1 = &foo.bar1;
+    let _bar2 = &mut foo.bar1;  //~ ERROR cannot borrow
+    use_imm(_bar1);
+}
+fn borrow_same_field_twice_imm_imm(foo: &mut Foo) {
+    let _bar1 = &foo.bar1;
+    let _bar2 = &foo.bar1;
+    use_imm(_bar1);
+}
+fn borrow_both_mut(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1;
+    let _bar2 = &mut foo.bar2;
+    use_mut(_bar1);
+}
+fn borrow_both_mut_pattern(foo: &mut Foo) {
+    match *foo {
+        Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } =>
+        { use_mut(_bar1); use_mut(_bar2); }
+    }
+}
+fn borrow_var_and_pattern(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1;
+    match *foo {
+        Foo { bar1: ref mut _bar1, bar2: _ } => {}
+        //~^ ERROR cannot borrow
+    }
+    use_mut(_bar1);
+}
+fn borrow_mut_and_base_imm(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1.int1;
+    let _foo1 = &foo.bar1; //~ ERROR cannot borrow
+    let _foo2 = &*foo; //~ ERROR cannot borrow
+    use_mut(_bar1);
+}
+fn borrow_mut_and_base_mut(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1.int1;
+    let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
+    use_mut(_bar1);
+}
+fn borrow_mut_and_base_mut2(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1.int1;
+    let _foo2 = &mut *foo; //~ ERROR cannot borrow
+    use_mut(_bar1);
+}
+fn borrow_imm_and_base_mut(foo: &mut Foo) {
+    let _bar1 = &foo.bar1.int1;
+    let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow
+    use_imm(_bar1);
+}
+fn borrow_imm_and_base_mut2(foo: &mut Foo) {
+    let _bar1 = &foo.bar1.int1;
+    let _foo2 = &mut *foo; //~ ERROR cannot borrow
+    use_imm(_bar1);
+}
+fn borrow_imm_and_base_imm(foo: &mut Foo) {
+    let _bar1 = &foo.bar1.int1;
+    let _foo1 = &foo.bar1;
+    let _foo2 = &*foo;
+    use_imm(_bar1);
+}
+fn borrow_mut_and_imm(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1;
+    let _foo1 = &foo.bar2;
+    use_mut(_bar1);
+}
+fn borrow_mut_from_imm(foo: &Foo) {
+    let _bar1 = &mut foo.bar1; //~ ERROR cannot borrow
+}
+
+fn borrow_long_path_both_mut(foo: &mut Foo) {
+    let _bar1 = &mut foo.bar1.int1;
+    let _foo1 = &mut foo.bar2.int2;
+    use_mut(_bar1);
+}
+fn main() {}
+
+fn use_mut<T>(_: &mut T) { }
+fn use_imm<T>(_: &T) { }
diff --git a/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr b/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr
new file mode 100644
index 00000000000..d9590e446c7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr
@@ -0,0 +1,119 @@
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-reborrow-from-mut.rs:13:17
+   |
+LL |     let _bar1 = &mut foo.bar1;
+   |                 ------------- first mutable borrow occurs here
+LL |     let _bar2 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |     use_mut(_bar1);
+   |             ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-reborrow-from-mut.rs:18:17
+   |
+LL |     let _bar1 = &mut foo.bar1;
+   |                 ------------- mutable borrow occurs here
+LL |     let _bar2 = &foo.bar1;
+   |                 ^^^^^^^^^ immutable borrow occurs here
+LL |     use_mut(_bar1);
+   |             ----- mutable borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-reborrow-from-mut.rs:23:17
+   |
+LL |     let _bar1 = &foo.bar1;
+   |                 --------- immutable borrow occurs here
+LL |     let _bar2 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     use_imm(_bar1);
+   |             ----- immutable borrow later used here
+
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-reborrow-from-mut.rs:45:21
+   |
+LL |     let _bar1 = &mut foo.bar1;
+   |                 ------------- first mutable borrow occurs here
+LL |     match *foo {
+LL |         Foo { bar1: ref mut _bar1, bar2: _ } => {}
+   |                     ^^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     use_mut(_bar1);
+   |             ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-reborrow-from-mut.rs:52:17
+   |
+LL |     let _bar1 = &mut foo.bar1.int1;
+   |                 ------------------ mutable borrow occurs here
+LL |     let _foo1 = &foo.bar1;
+   |                 ^^^^^^^^^ immutable borrow occurs here
+LL |     let _foo2 = &*foo;
+LL |     use_mut(_bar1);
+   |             ----- mutable borrow later used here
+
+error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-reborrow-from-mut.rs:53:17
+   |
+LL |     let _bar1 = &mut foo.bar1.int1;
+   |                 ------------------ mutable borrow occurs here
+LL |     let _foo1 = &foo.bar1;
+LL |     let _foo2 = &*foo;
+   |                 ^^^^^ immutable borrow occurs here
+LL |     use_mut(_bar1);
+   |             ----- mutable borrow later used here
+
+error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
+  --> $DIR/borrowck-reborrow-from-mut.rs:58:17
+   |
+LL |     let _bar1 = &mut foo.bar1.int1;
+   |                 ------------------ first mutable borrow occurs here
+LL |     let _foo1 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |     use_mut(_bar1);
+   |             ----- first borrow later used here
+
+error[E0499]: cannot borrow `*foo` as mutable more than once at a time
+  --> $DIR/borrowck-reborrow-from-mut.rs:63:17
+   |
+LL |     let _bar1 = &mut foo.bar1.int1;
+   |                 ------------------ first mutable borrow occurs here
+LL |     let _foo2 = &mut *foo;
+   |                 ^^^^^^^^^ second mutable borrow occurs here
+LL |     use_mut(_bar1);
+   |             ----- first borrow later used here
+
+error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-reborrow-from-mut.rs:68:17
+   |
+LL |     let _bar1 = &foo.bar1.int1;
+   |                 -------------- immutable borrow occurs here
+LL |     let _foo1 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     use_imm(_bar1);
+   |             ----- immutable borrow later used here
+
+error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-reborrow-from-mut.rs:73:17
+   |
+LL |     let _bar1 = &foo.bar1.int1;
+   |                 -------------- immutable borrow occurs here
+LL |     let _foo2 = &mut *foo;
+   |                 ^^^^^^^^^ mutable borrow occurs here
+LL |     use_imm(_bar1);
+   |             ----- immutable borrow later used here
+
+error[E0596]: cannot borrow `foo.bar1` as mutable, as it is behind a `&` reference
+  --> $DIR/borrowck-reborrow-from-mut.rs:88:17
+   |
+LL |     let _bar1 = &mut foo.bar1;
+   |                 ^^^^^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn borrow_mut_from_imm(foo: &mut Foo) {
+   |                             ~~~~~~~~
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0596.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.rs b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.rs
new file mode 100644
index 00000000000..779cb3bbec1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.rs
@@ -0,0 +1,22 @@
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'a> {
+    pointer: &'a mut isize
+}
+
+fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> {
+    S { pointer: &mut *p.pointer }
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+    let mut x = 1;
+
+    {
+        let mut y = S { pointer: &mut x };
+        let z = copy_borrowed_ptr(&mut y);
+        *y.pointer += 1;
+        *z.pointer += 1;
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr
new file mode 100644
index 00000000000..f28c42ce2d5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:9:5
+   |
+LL | fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> {
+   |                      -- -- lifetime `'b` defined here
+   |                      |
+   |                      lifetime `'a` defined here
+LL |     S { pointer: &mut *p.pointer }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/borrowck/borrowck-ref-mut-of-imm.rs b/tests/ui/borrowck/borrowck-ref-mut-of-imm.rs
new file mode 100644
index 00000000000..ae5bb8591f9
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-ref-mut-of-imm.rs
@@ -0,0 +1,10 @@
+fn destructure(x: Option<isize>) -> isize {
+    match x {
+      None => 0,
+      Some(ref mut v) => *v //~ ERROR cannot borrow
+    }
+}
+
+fn main() {
+    assert_eq!(destructure(Some(22)), 22);
+}
diff --git a/tests/ui/borrowck/borrowck-ref-mut-of-imm.stderr b/tests/ui/borrowck/borrowck-ref-mut-of-imm.stderr
new file mode 100644
index 00000000000..5cfd81bd004
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-ref-mut-of-imm.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
+  --> $DIR/borrowck-ref-mut-of-imm.rs:4:12
+   |
+LL |       Some(ref mut v) => *v
+   |            ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn destructure(mut x: Option<isize>) -> isize {
+   |                +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/borrowck-reinit.rs b/tests/ui/borrowck/borrowck-reinit.rs
new file mode 100644
index 00000000000..866b3a2a8af
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-reinit.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mut x = Box::new(0);
+    let _u = x; // error shouldn't note this move
+    x = Box::new(1);
+    drop(x);
+    let _ = (1,x); //~ ERROR use of moved value: `x`
+}
diff --git a/tests/ui/borrowck/borrowck-reinit.stderr b/tests/ui/borrowck/borrowck-reinit.stderr
new file mode 100644
index 00000000000..f785900d53f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-reinit.stderr
@@ -0,0 +1,19 @@
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrowck-reinit.rs:6:16
+   |
+LL |     let mut x = Box::new(0);
+   |         ----- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+...
+LL |     drop(x);
+   |          - value moved here
+LL |     let _ = (1,x);
+   |                ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x.clone());
+   |           ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs
new file mode 100644
index 00000000000..6f323d91227
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs
@@ -0,0 +1,44 @@
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+fn main() { #![rustc_error] // rust-lang/rust#49855
+    // Original borrow ends at end of function
+    let mut x = 1;
+    let y = &mut x;
+    //~^ mutable borrow occurs here
+    let z = &x; //~ ERROR cannot borrow
+    //~^ immutable borrow occurs here
+    z.use_ref();
+    y.use_mut();
+}
+
+fn foo() {
+    match true {
+        true => {
+            // Original borrow ends at end of match arm
+            let mut x = 1;
+            let y = &x;
+            //~^ immutable borrow occurs here
+            let z = &mut x; //~ ERROR cannot borrow
+            //~^ mutable borrow occurs here
+            z.use_mut();
+            y.use_ref();
+        }
+        false => ()
+    }
+}
+
+fn bar() {
+    // Original borrow ends at end of closure
+    || {
+        let mut x = 1;
+        let y = &mut x;
+        //~^ first mutable borrow occurs here
+        let z = &mut x; //~ ERROR cannot borrow
+        //~^ second mutable borrow occurs here
+        z.use_mut();
+        y.use_mut();
+    };
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr
new file mode 100644
index 00000000000..d05996413dd
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr
@@ -0,0 +1,40 @@
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-report-with-custom-diagnostic.rs:8:13
+   |
+LL |     let y = &mut x;
+   |             ------ mutable borrow occurs here
+LL |
+LL |     let z = &x;
+   |             ^^ immutable borrow occurs here
+...
+LL |     y.use_mut();
+   |     ----------- mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:21
+   |
+LL |             let y = &x;
+   |                     -- immutable borrow occurs here
+LL |
+LL |             let z = &mut x;
+   |                     ^^^^^^ mutable borrow occurs here
+...
+LL |             y.use_ref();
+   |             ----------- immutable borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:17
+   |
+LL |         let y = &mut x;
+   |                 ------ first mutable borrow occurs here
+LL |
+LL |         let z = &mut x;
+   |                 ^^^^^^ second mutable borrow occurs here
+...
+LL |         y.use_mut();
+   |         ----------- first borrow later used here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0499, E0502.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs
new file mode 100644
index 00000000000..75e5e7fd421
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs
@@ -0,0 +1,10 @@
+// Check that when we clone a `&T` pointer we properly relate the
+// lifetime of the pointer which results to the pointer being cloned.
+// Bugs in method resolution have sometimes broken this connection.
+// Issue #19261.
+
+fn leak<'a, T>(x: T) -> &'a T {
+    (&x).clone() //~ ERROR cannot return value referencing function parameter `x`
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr
new file mode 100644
index 00000000000..d54449ac4ad
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr
@@ -0,0 +1,12 @@
+error[E0515]: cannot return value referencing function parameter `x`
+  --> $DIR/borrowck-return-variable-on-stack-via-clone.rs:7:5
+   |
+LL |     (&x).clone()
+   |     ----^^^^^^^^
+   |     |
+   |     returns a value referencing data owned by the current function
+   |     `x` is borrowed here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/borrowck-return.rs b/tests/ui/borrowck/borrowck-return.rs
new file mode 100644
index 00000000000..a63ffcff732
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-return.rs
@@ -0,0 +1,6 @@
+fn f() -> isize {
+    let x: isize;
+    return x; //~ ERROR E0381
+}
+
+fn main() { f(); }
diff --git a/tests/ui/borrowck/borrowck-return.stderr b/tests/ui/borrowck/borrowck-return.stderr
new file mode 100644
index 00000000000..9799357c9ca
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-return.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-return.rs:3:12
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     return x;
+   |            ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-rvalues-mutable.rs b/tests/ui/borrowck/borrowck-rvalues-mutable.rs
new file mode 100644
index 00000000000..c4695c942e1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-rvalues-mutable.rs
@@ -0,0 +1,34 @@
+// run-pass
+
+struct Counter {
+    value: usize
+}
+
+impl Counter {
+    fn new(v: usize) -> Counter {
+        Counter {value: v}
+    }
+
+    fn inc<'a>(&'a mut self) -> &'a mut Counter {
+        self.value += 1;
+        self
+    }
+
+    fn get(&self) -> usize {
+        self.value
+    }
+
+    fn get_and_inc(&mut self) -> usize {
+        let v = self.value;
+        self.value += 1;
+        v
+    }
+}
+
+pub fn main() {
+    let v = Counter::new(22).get_and_inc();
+    assert_eq!(v, 22);
+
+    let v = Counter::new(22).inc().inc().get();
+    assert_eq!(v, 24);
+}
diff --git a/tests/ui/borrowck/borrowck-scope-of-deref-issue-4666.rs b/tests/ui/borrowck/borrowck-scope-of-deref-issue-4666.rs
new file mode 100644
index 00000000000..e89332ae31a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-scope-of-deref-issue-4666.rs
@@ -0,0 +1,42 @@
+// run-pass
+// Tests that the scope of the pointer returned from `get()` is
+// limited to the deref operation itself, and does not infect the
+// block as a whole.
+
+
+struct Box {
+    x: usize
+}
+
+impl Box {
+    fn get(&self) -> &usize {
+        &self.x
+    }
+    fn set(&mut self, x: usize) {
+        self.x = x;
+    }
+}
+
+fn fun1() {
+    // in the past, borrow checker behaved differently when
+    // init and decl of `v` were distinct
+    let v;
+    let mut a_box = Box {x: 0};
+    a_box.set(22);
+    v = *a_box.get();
+    a_box.set(v+1);
+    assert_eq!(23, *a_box.get());
+}
+
+fn fun2() {
+    let mut a_box = Box {x: 0};
+    a_box.set(22);
+    let v = *a_box.get();
+    a_box.set(v+1);
+    assert_eq!(23, *a_box.get());
+}
+
+pub fn main() {
+    fun1();
+    fun2();
+}
diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs
new file mode 100644
index 00000000000..a8e56f648e2
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs
@@ -0,0 +1,64 @@
+// check-pass
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_ok(s: &mut [i32; 4]) {
+    let [ref first, ref second, _, ref fourth, ..] = *s;
+    let [_, _, ref mut third, ..] = *s;
+    nop(&[first, second, third, fourth]);
+}
+
+fn const_index_from_end_ok(s: &mut [i32; 4]) {
+    let [.., ref fourth, ref third, _, ref first] = *s;
+    let [.., ref mut second, _] = *s;
+    nop(&[first, second, third, fourth]);
+}
+
+fn const_index_mixed(s: &mut [i32; 6]) {
+    let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+
+    let [ref mut from_begin0, ..] = *s;
+    nop(&[from_begin0, from_end1, from_end3, from_end4]);
+    let [_, ref mut from_begin1, ..] = *s;
+    nop(&[from_begin1, from_end1, from_end3, from_end4]);
+
+    let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+
+    let [.., ref mut from_end1] = *s;
+    nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
+    let [.., ref mut from_end2, _] = *s;
+    nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
+    let [.., ref mut from_end4, _, _, _] = *s;
+    nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
+}
+
+fn const_index_and_subslice_ok(s: &mut [i32; 4]) {
+    let [ref first, ref second, ..] = *s;
+    let [_, _, ref mut tail @ ..] = *s;
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn const_index_and_subslice_from_end_ok(s: &mut [i32; 4]) {
+    let [.., ref second, ref first] = *s;
+    let [ref mut tail @ .., _, _] = *s;
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn subslices(s: &mut [i32; 4]) {
+    let [_, _, ref s1 @ ..] = *s;
+    let [ref mut s2 @ .., _, _] = *s;
+    nop_subslice(s1);
+    nop_subslice(s2);
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    const_index_ok(&mut v);
+    const_index_from_end_ok(&mut v);
+    const_index_and_subslice_ok(&mut v);
+    const_index_and_subslice_from_end_ok(&mut v);
+    subslices(&mut v);
+}
diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs
new file mode 100644
index 00000000000..6b210d73228
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs
@@ -0,0 +1,58 @@
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_err(s: &mut [i32; 4]) {
+    let [ref first, ref second, ..] = *s;
+    let [_, ref mut  second2, ref mut third, ..] = *s; //~ERROR
+    nop(&[first, second, second2, third]);
+}
+
+fn const_index_from_end_err(s: &mut [i32; 4]) {
+    let [.., ref fourth, ref third, _, ref first] = *s;
+    let [.., ref mut third2, _, _] = *s; //~ERROR
+    nop(&[first, third, third2, fourth]);
+}
+
+fn const_index_mixed(s: &mut [i32; 6]) {
+    let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+
+    let [_, _, ref mut from_begin2, ..] = *s; //~ERROR
+    nop(&[from_begin2, from_end1, from_end3, from_end4]);
+    let [_, _, _, ref mut from_begin3, ..] = *s; //~ERROR
+    nop(&[from_begin3, from_end1, from_end3, from_end4]);
+
+    let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+
+    let [.., ref mut from_end3, _,  _] = *s; //~ERROR
+    nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+}
+
+fn const_index_and_subslice_err(s: &mut [i32; 4]) {
+    let [ref first, ref second, ..] = *s;
+    let [_, ref mut tail @ ..] = *s; //~ERROR
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn const_index_and_subslice_from_end_err(s: &mut [i32; 4]) {
+    let [.., ref second, ref first] = *s;
+    let [ref mut tail @ .., _] = *s; //~ERROR
+    nop(&[first, second]);
+    nop_subslice(tail);
+}
+
+fn subslices_overlap(s: &mut [i32; 4]) {
+    let [_,  ref s1 @ ..] = *s;
+    let [ref mut s2 @ .., _, _] = *s; //~ERROR
+    nop_subslice(s1);
+    nop_subslice(s2);
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    const_index_err(&mut v);
+    const_index_from_end_err(&mut v);
+    const_index_and_subslice_err(&mut v);
+    const_index_and_subslice_from_end_err(&mut v);
+    subslices_overlap(&mut v);
+}
diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
new file mode 100644
index 00000000000..f4324110ccb
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
@@ -0,0 +1,86 @@
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:6:13
+   |
+LL |     let [ref first, ref second, ..] = *s;
+   |                     ---------- immutable borrow occurs here
+LL |     let [_, ref mut  second2, ref mut third, ..] = *s;
+   |             ^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, second, second2, third]);
+   |                  ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:12:14
+   |
+LL |     let [.., ref fourth, ref third, _, ref first] = *s;
+   |                          --------- immutable borrow occurs here
+LL |     let [.., ref mut third2, _, _] = *s;
+   |              ^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, third, third2, fourth]);
+   |                  ----- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:19:16
+   |
+LL |     let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+   |                 ------------- immutable borrow occurs here
+LL |
+LL |     let [_, _, ref mut from_begin2, ..] = *s;
+   |                ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[from_begin2, from_end1, from_end3, from_end4]);
+   |                                              --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:21:19
+   |
+LL |     let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+   |                                ------------- immutable borrow occurs here
+...
+LL |     let [_, _, _, ref mut from_begin3, ..] = *s;
+   |                   ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[from_begin3, from_end1, from_end3, from_end4]);
+   |                                   --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:26:14
+   |
+LL |     let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+   |                                               --------------- immutable borrow occurs here
+LL |
+LL |     let [.., ref mut from_end3, _,  _] = *s;
+   |              ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+   |                                     ----------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:32:13
+   |
+LL |     let [ref first, ref second, ..] = *s;
+   |                     ---------- immutable borrow occurs here
+LL |     let [_, ref mut tail @ ..] = *s;
+   |             ^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, second]);
+   |                  ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:39:10
+   |
+LL |     let [.., ref second, ref first] = *s;
+   |              ---------- immutable borrow occurs here
+LL |     let [ref mut tail @ .., _] = *s;
+   |          ^^^^^^^^^^^^ mutable borrow occurs here
+LL |     nop(&[first, second]);
+   |                  ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-array.rs:46:10
+   |
+LL |     let [_,  ref s1 @ ..] = *s;
+   |              ------ immutable borrow occurs here
+LL |     let [ref mut s2 @ .., _, _] = *s;
+   |          ^^^^^^^^^^ mutable borrow occurs here
+LL |     nop_subslice(s1);
+   |                  -- immutable borrow later used here
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs
new file mode 100644
index 00000000000..4367596c6ea
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+fn mut_head_tail<'a, A>(v: &'a mut [A]) -> Option<(&'a mut A, &'a mut [A])> {
+    match *v {
+        [ref mut head, ref mut tail @ ..] => {
+            Some((head, tail))
+        }
+        [] => None
+    }
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    match mut_head_tail(&mut v) {
+        None => {},
+        Some((h,t)) => {
+            *h = 1000;
+            t.reverse();
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs
new file mode 100644
index 00000000000..6390dc3a91a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs
@@ -0,0 +1,59 @@
+// check-pass
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_ok(s: &mut [i32]) {
+    if let [ref first, ref second, _, ref fourth, ..] = *s {
+        if let [_, _, ref mut third, ..] = *s {
+            nop(&[first, second, third, fourth]);
+        }
+    }
+}
+
+fn const_index_from_end_ok(s: &mut [i32]) {
+    if let [.., ref fourth, ref third, _, ref first] = *s {
+        if let [.., ref mut second, _] = *s {
+            nop(&[first, second, third, fourth]);
+        }
+    }
+}
+
+fn const_index_mixed(s: &mut [i32]) {
+    if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
+        if let [ref mut from_begin0, ..] = *s {
+            nop(&[from_begin0, from_end1, from_end3, from_end4]);
+        }
+    }
+    if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
+        if let [.., ref mut from_end1] = *s {
+            nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
+        }
+    }
+}
+
+fn const_index_and_subslice_ok(s: &mut [i32]) {
+    if let [ref first, ref second, ..] = *s {
+        if let [_, _, ref mut tail @ ..] = *s {
+            nop(&[first, second]);
+            nop_subslice(tail);
+        }
+    }
+}
+
+fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
+    if let [.., ref second, ref first] = *s {
+        if let [ref mut tail @ .., _, _] = *s {
+            nop(&[first, second]);
+            nop_subslice(tail);
+        }
+    }
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    const_index_ok(&mut v);
+    const_index_from_end_ok(&mut v);
+    const_index_and_subslice_ok(&mut v);
+    const_index_and_subslice_from_end_ok(&mut v);
+}
diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
new file mode 100644
index 00000000000..0e1c90a1cd8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
@@ -0,0 +1,79 @@
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_err(s: &mut [i32]) {
+    if let [ref first, ref second, ..] = *s {
+        if let [_, ref mut  second2, ref mut third, ..] = *s { //~ERROR
+            nop(&[first, second, second2, third]);
+        }
+    }
+}
+
+fn const_index_from_end_err(s: &mut [i32]) {
+    if let [.., ref fourth, ref third, _, ref first] = *s {
+        if let [.., ref mut third2, _, _] = *s { //~ERROR
+            nop(&[first, third, third2, fourth]);
+        }
+    }
+}
+
+fn const_index_mixed(s: &mut [i32]) {
+    if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
+        if let [_, ref mut from_begin1, ..] = *s { //~ERROR
+            nop(&[from_begin1, from_end1, from_end3, from_end4]);
+        }
+        if let [_, _, ref mut from_begin2, ..] = *s { //~ERROR
+            nop(&[from_begin2, from_end1, from_end3, from_end4]);
+        }
+        if let [_, _, _, ref mut from_begin3, ..] = *s { //~ERROR
+            nop(&[from_begin3, from_end1, from_end3, from_end4]);
+        }
+    }
+    if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
+        if let [.., ref mut from_end2, _] = *s { //~ERROR
+            nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
+        }
+        if let [.., ref mut from_end3, _,  _] = *s { //~ERROR
+            nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+        }
+        if let [.., ref mut from_end4, _, _, _] = *s { //~ERROR
+            nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
+        }
+    }
+}
+
+fn const_index_and_subslice_err(s: &mut [i32]) {
+    if let [ref first, ref second, ..] = *s {
+        if let [_, ref mut tail @ ..] = *s { //~ERROR
+            nop(&[first, second]);
+            nop_subslice(tail);
+        }
+    }
+}
+
+fn const_index_and_subslice_from_end_err(s: &mut [i32]) {
+    if let [.., ref second, ref first] = *s {
+        if let [ref mut tail @ .., _] = *s { //~ERROR
+            nop(&[first, second]);
+            nop_subslice(tail);
+        }
+    }
+}
+
+fn subslices(s: &mut [i32]) {
+    if let [_, _, _, ref s1 @ ..] = *s {
+        if let [ref mut s2 @ .., _, _, _] = *s { //~ERROR
+            nop_subslice(s1);
+            nop_subslice(s2);
+        }
+    }
+}
+
+fn main() {
+    let mut v = [1,2,3,4];
+    const_index_err(&mut v);
+    const_index_from_end_err(&mut v);
+    const_index_and_subslice_err(&mut v);
+    const_index_and_subslice_from_end_err(&mut v);
+    subslices(&mut v);
+}
diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
new file mode 100644
index 00000000000..f9a63bd49dd
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
@@ -0,0 +1,117 @@
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:6:20
+   |
+LL |     if let [ref first, ref second, ..] = *s {
+   |                        ---------- immutable borrow occurs here
+LL |         if let [_, ref mut  second2, ref mut third, ..] = *s {
+   |                    ^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[first, second, second2, third]);
+   |                          ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:14:21
+   |
+LL |     if let [.., ref fourth, ref third, _, ref first] = *s {
+   |                             --------- immutable borrow occurs here
+LL |         if let [.., ref mut third2, _, _] = *s {
+   |                     ^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[first, third, third2, fourth]);
+   |                          ----- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:22:20
+   |
+LL |     if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
+   |                    ------------- immutable borrow occurs here
+LL |         if let [_, ref mut from_begin1, ..] = *s {
+   |                    ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[from_begin1, from_end1, from_end3, from_end4]);
+   |                                                      --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:25:23
+   |
+LL |     if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
+   |                                   ------------- immutable borrow occurs here
+...
+LL |         if let [_, _, ref mut from_begin2, ..] = *s {
+   |                       ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[from_begin2, from_end1, from_end3, from_end4]);
+   |                                           --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:28:26
+   |
+LL |     if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
+   |                                   ------------- immutable borrow occurs here
+...
+LL |         if let [_, _, _, ref mut from_begin3, ..] = *s {
+   |                          ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[from_begin3, from_end1, from_end3, from_end4]);
+   |                                           --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:33:21
+   |
+LL |     if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
+   |                                                  --------------- immutable borrow occurs here
+LL |         if let [.., ref mut from_end2, _] = *s {
+   |                     ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
+   |                                             ----------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:36:21
+   |
+LL |     if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
+   |                                                  --------------- immutable borrow occurs here
+...
+LL |         if let [.., ref mut from_end3, _,  _] = *s {
+   |                     ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+   |                                             ----------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:39:21
+   |
+LL |     if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
+   |                              --------------- immutable borrow occurs here
+...
+LL |         if let [.., ref mut from_end4, _, _, _] = *s {
+   |                     ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
+   |                                ----------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:47:20
+   |
+LL |     if let [ref first, ref second, ..] = *s {
+   |                        ---------- immutable borrow occurs here
+LL |         if let [_, ref mut tail @ ..] = *s {
+   |                    ^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[first, second]);
+   |                          ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:56:17
+   |
+LL |     if let [.., ref second, ref first] = *s {
+   |                 ---------- immutable borrow occurs here
+LL |         if let [ref mut tail @ .., _] = *s {
+   |                 ^^^^^^^^^^^^ mutable borrow occurs here
+LL |             nop(&[first, second]);
+   |                          ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:65:17
+   |
+LL |     if let [_, _, _, ref s1 @ ..] = *s {
+   |                      ------ immutable borrow occurs here
+LL |         if let [ref mut s2 @ .., _, _, _] = *s {
+   |                 ^^^^^^^^^^ mutable borrow occurs here
+LL |             nop_subslice(s1);
+   |                          -- immutable borrow later used here
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-static-item-in-fn.rs b/tests/ui/borrowck/borrowck-static-item-in-fn.rs
new file mode 100644
index 00000000000..5f4379325a5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-static-item-in-fn.rs
@@ -0,0 +1,9 @@
+// run-pass
+#![allow(dead_code)]
+// Regression test for issue #7740
+
+// pretty-expanded FIXME #23616
+
+pub fn main() {
+    static A: &'static char = &'A';
+}
diff --git a/tests/ui/borrowck/borrowck-storage-dead.rs b/tests/ui/borrowck/borrowck-storage-dead.rs
new file mode 100644
index 00000000000..fe984461042
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-storage-dead.rs
@@ -0,0 +1,24 @@
+fn ok() {
+    loop {
+        let _x = 1;
+    }
+}
+
+fn also_ok() {
+    loop {
+        let _x = String::new();
+    }
+}
+
+fn fail() {
+    loop {
+        let x: i32;
+        let _ = x + 1; //~ERROR [E0381]
+    }
+}
+
+fn main() {
+    ok();
+    also_ok();
+    fail();
+}
diff --git a/tests/ui/borrowck/borrowck-storage-dead.stderr b/tests/ui/borrowck/borrowck-storage-dead.stderr
new file mode 100644
index 00000000000..3a413153acd
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-storage-dead.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-storage-dead.rs:16:17
+   |
+LL |         let x: i32;
+   |             - binding declared here but left uninitialized
+LL |         let _ = x + 1;
+   |                 ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let x: i32 = 0;
+   |                    +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs
new file mode 100644
index 00000000000..1f6ed6d46aa
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs
@@ -0,0 +1,21 @@
+// Issue 4691: Ensure that functional-struct-update can only copy, not
+// move, when the struct implements Drop.
+
+struct B;
+struct S { a: isize, b: B }
+impl Drop for S { fn drop(&mut self) { } }
+
+struct T { a: isize, mv: Box<isize> }
+impl Drop for T { fn drop(&mut self) { } }
+
+fn f(s0:S) {
+    let _s2 = S{a: 2, ..s0};
+    //~^ ERROR [E0509]
+}
+
+fn g(s0:T) {
+    let _s2 = T{a: 2, ..s0};
+    //~^ ERROR [E0509]
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr
new file mode 100644
index 00000000000..af32f279100
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr
@@ -0,0 +1,21 @@
+error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:12:15
+   |
+LL |     let _s2 = S{a: 2, ..s0};
+   |               ^^^^^^^^^^^^^
+   |               |
+   |               cannot move out of here
+   |               move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
+
+error[E0509]: cannot move out of type `T`, which implements the `Drop` trait
+  --> $DIR/borrowck-struct-update-with-dtor.rs:17:15
+   |
+LL |     let _s2 = T{a: 2, ..s0};
+   |               ^^^^^^^^^^^^^
+   |               |
+   |               cannot move out of here
+   |               move occurs because `s0.mv` has type `Box<isize>`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0509`.
diff --git a/tests/ui/borrowck/borrowck-swap-mut-base-ptr.rs b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.rs
new file mode 100644
index 00000000000..8170323efc5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.rs
@@ -0,0 +1,22 @@
+// Test that attempt to swap `&mut` pointer while pointee is borrowed
+// yields an error.
+//
+// Example from compiler/rustc_borrowck/borrowck/README.md
+
+use std::mem::swap;
+
+
+
+fn foo<'a>(mut t0: &'a mut isize,
+           mut t1: &'a mut isize) {
+    let p: &isize = &*t0;     // Freezes `*t0`
+    swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0`
+    *t1 = 22;
+    p.use_ref();
+}
+
+fn main() {
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-swap-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.stderr
new file mode 100644
index 00000000000..b39215b9aab
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.stderr
@@ -0,0 +1,14 @@
+error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-swap-mut-base-ptr.rs:13:10
+   |
+LL |     let p: &isize = &*t0;     // Freezes `*t0`
+   |                     ---- immutable borrow occurs here
+LL |     swap(&mut t0, &mut t1);
+   |          ^^^^^^^ mutable borrow occurs here
+LL |     *t1 = 22;
+LL |     p.use_ref();
+   |     ----------- immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs
new file mode 100644
index 00000000000..1cf8d187c25
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs
@@ -0,0 +1,9 @@
+#![feature(thread_local)]
+
+#[thread_local]
+static FOO: u8 = 3;
+
+fn assert_static(_t: &'static u8) {}
+fn main() {
+     assert_static(&FOO); //~ ERROR [E0712]
+}
diff --git a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr
new file mode 100644
index 00000000000..26453b42fa9
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr
@@ -0,0 +1,11 @@
+error[E0712]: thread-local variable borrowed past end of function
+  --> $DIR/borrowck-thread-local-static-borrow-outlives-fn.rs:8:20
+   |
+LL |      assert_static(&FOO);
+   |                    ^^^^ thread-local variables cannot be borrowed beyond the end of the function
+LL | }
+   | - end of enclosing function is here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0712`.
diff --git a/tests/ui/borrowck/borrowck-trait-lifetime.rs b/tests/ui/borrowck/borrowck-trait-lifetime.rs
new file mode 100644
index 00000000000..8a6dfe76d60
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-trait-lifetime.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![allow(unused_imports)]
+// This test verifies that casting from the same lifetime on a value
+// to the same lifetime on a trait succeeds. See issue #10766.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+use std::marker;
+
+fn main() {
+    trait T { fn foo(&self) {} }
+
+    fn f<'a, V: T>(v: &'a V) -> &'a dyn T {
+        v as &'a dyn T
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-unary-move.rs b/tests/ui/borrowck/borrowck-unary-move.rs
new file mode 100644
index 00000000000..3b4c0731fc5
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-unary-move.rs
@@ -0,0 +1,11 @@
+fn foo(x: Box<isize>) -> isize {
+    let y = &*x;
+    free(x); //~ ERROR cannot move out of `x` because it is borrowed
+    *y
+}
+
+fn free(_x: Box<isize>) {
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-unary-move.stderr b/tests/ui/borrowck/borrowck-unary-move.stderr
new file mode 100644
index 00000000000..aab225ed4a4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-unary-move.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/borrowck-unary-move.rs:3:10
+   |
+LL |     let y = &*x;
+   |             --- borrow of `*x` occurs here
+LL |     free(x);
+   |          ^ move out of `x` occurs here
+LL |     *y
+   |     -- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/borrowck-unboxed-closures.rs b/tests/ui/borrowck/borrowck-unboxed-closures.rs
new file mode 100644
index 00000000000..f0048dd7de0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-unboxed-closures.rs
@@ -0,0 +1,17 @@
+fn a<F:Fn(isize, isize) -> isize>(mut f: F) {
+    let g = &mut f;
+    f(1, 2);    //~ ERROR cannot borrow `f` as immutable
+    use_mut(g);
+}
+fn b<F:FnMut(isize, isize) -> isize>(f: F) {
+    f(1, 2);    //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable
+}
+
+fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
+    f(1, 2);
+    f(1, 2);    //~ ERROR use of moved value
+}
+
+fn main() {}
+
+fn use_mut<T>(_: &mut T) { }
diff --git a/tests/ui/borrowck/borrowck-unboxed-closures.stderr b/tests/ui/borrowck/borrowck-unboxed-closures.stderr
new file mode 100644
index 00000000000..3634676463c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-unboxed-closures.stderr
@@ -0,0 +1,45 @@
+error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-unboxed-closures.rs:3:5
+   |
+LL |     let g = &mut f;
+   |             ------ mutable borrow occurs here
+LL |     f(1, 2);
+   |     ^ immutable borrow occurs here
+LL |     use_mut(g);
+   |             - mutable borrow later used here
+
+error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
+  --> $DIR/borrowck-unboxed-closures.rs:7:5
+   |
+LL |     f(1, 2);
+   |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn b<F:FnMut(isize, isize) -> isize>(mut f: F) {
+   |                                      +++
+
+error[E0382]: use of moved value: `f`
+  --> $DIR/borrowck-unboxed-closures.rs:12:5
+   |
+LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
+   |                                       - move occurs because `f` has type `F`, which does not implement the `Copy` trait
+LL |     f(1, 2);
+   |     ------- `f` moved due to this call
+LL |     f(1, 2);
+   |     ^ value used here after move
+   |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/borrowck-unboxed-closures.rs:11:5
+   |
+LL |     f(1, 2);
+   |     ^
+help: consider further restricting this bound
+   |
+LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) {
+   |                                      ++++++
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0502, E0596.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-uninit-after-item.rs b/tests/ui/borrowck/borrowck-uninit-after-item.rs
new file mode 100644
index 00000000000..e97ce6aa407
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-after-item.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let bar;
+    fn baz(_x: isize) { }
+    baz(bar); //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-uninit-after-item.stderr b/tests/ui/borrowck/borrowck-uninit-after-item.stderr
new file mode 100644
index 00000000000..071598b42ee
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-after-item.stderr
@@ -0,0 +1,17 @@
+error[E0381]: used binding `bar` isn't initialized
+  --> $DIR/borrowck-uninit-after-item.rs:4:9
+   |
+LL |     let bar;
+   |         --- binding declared here but left uninitialized
+LL |     fn baz(_x: isize) { }
+LL |     baz(bar);
+   |         ^^^ `bar` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let bar = 0;
+   |             +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-uninit-field-access.rs b/tests/ui/borrowck/borrowck-uninit-field-access.rs
new file mode 100644
index 00000000000..bc931eef93a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-field-access.rs
@@ -0,0 +1,30 @@
+// Check that do not allow access to fields of uninitialized or moved
+// structs.
+
+#[derive(Default)]
+struct Point {
+    x: isize,
+    y: isize,
+}
+
+#[derive(Default)]
+struct Line {
+    origin: Point,
+    middle: Point,
+    target: Point,
+}
+
+impl Line { fn consume(self) { } }
+
+fn main() {
+    let mut a: Point;
+    let _ = a.x + 1; //~ ERROR [E0381]
+
+    let mut line1 = Line::default();
+    let _moved = line1.origin;
+    let _ = line1.origin.x + 1; //~ ERROR [E0382]
+
+    let mut line2 = Line::default();
+    let _moved = (line2.origin, line2.middle);
+    line2.consume(); //~ ERROR [E0382]
+}
diff --git a/tests/ui/borrowck/borrowck-uninit-field-access.stderr b/tests/ui/borrowck/borrowck-uninit-field-access.stderr
new file mode 100644
index 00000000000..f0f4ad704b7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-field-access.stderr
@@ -0,0 +1,37 @@
+error[E0381]: used binding `a` isn't initialized
+  --> $DIR/borrowck-uninit-field-access.rs:21:13
+   |
+LL |     let mut a: Point;
+   |         ----- binding declared here but left uninitialized
+LL |     let _ = a.x + 1;
+   |             ^^^ `a.x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut a: Point = Default::default();
+   |                      ++++++++++++++++++++
+
+error[E0382]: use of moved value: `line1.origin`
+  --> $DIR/borrowck-uninit-field-access.rs:25:13
+   |
+LL |     let _moved = line1.origin;
+   |                  ------------ value moved here
+LL |     let _ = line1.origin.x + 1;
+   |             ^^^^^^^^^^^^^^ value used here after move
+   |
+   = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait
+
+error[E0382]: use of partially moved value: `line2`
+  --> $DIR/borrowck-uninit-field-access.rs:29:5
+   |
+LL |     let _moved = (line2.origin, line2.middle);
+   |                                 ------------ value partially moved here
+LL |     line2.consume();
+   |     ^^^^^ value used here after partial move
+   |
+   = note: partial move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0381, E0382.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-uninit-in-assignop.rs b/tests/ui/borrowck/borrowck-uninit-in-assignop.rs
new file mode 100644
index 00000000000..92c3692bd2f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-in-assignop.rs
@@ -0,0 +1,34 @@
+// Tests that the use of uninitialized variable in assignment operator
+// expression is detected.
+
+pub fn main() {
+    let x: isize;
+    x += 1; //~ ERROR E0381
+
+    let x: isize;
+    x -= 1; //~ ERROR E0381
+
+    let x: isize;
+    x *= 1; //~ ERROR E0381
+
+    let x: isize;
+    x /= 1; //~ ERROR E0381
+
+    let x: isize;
+    x %= 1; //~ ERROR E0381
+
+    let x: isize;
+    x ^= 1; //~ ERROR E0381
+
+    let x: isize;
+    x &= 1; //~ ERROR E0381
+
+    let x: isize;
+    x |= 1; //~ ERROR E0381
+
+    let x: isize;
+    x <<= 1; //~ ERROR E0381
+
+    let x: isize;
+    x >>= 1; //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
new file mode 100644
index 00000000000..fdbb451bde4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
@@ -0,0 +1,133 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:6:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x += 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:9:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x -= 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:12:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x *= 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:15:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x /= 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:18:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x %= 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:21:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x ^= 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:24:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x &= 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:27:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x |= 1;
+   |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:30:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x <<= 1;
+   |     ^^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-in-assignop.rs:33:5
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     x >>= 1;
+   |     ^^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-uninit-ref-chain.rs b/tests/ui/borrowck/borrowck-uninit-ref-chain.rs
new file mode 100644
index 00000000000..c36b9707d22
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-ref-chain.rs
@@ -0,0 +1,33 @@
+struct S<X, Y> {
+    x: X,
+    y: Y,
+}
+
+fn main() {
+    let x: &&Box<i32>;
+    let _y = &**x; //~ ERROR [E0381]
+
+    let x: &&S<i32, i32>;
+    let _y = &**x; //~ ERROR [E0381]
+
+    let x: &&i32;
+    let _y = &**x; //~ ERROR [E0381]
+
+
+    let mut a: S<i32, i32>;
+    a.x = 0; //~ ERROR [E0381]
+    let _b = &a.x;
+
+    let mut a: S<&&i32, &&i32>;
+    a.x = &&0; //~ ERROR [E0381]
+    let _b = &**a.x;
+
+
+    let mut a: S<i32, i32>;
+    a.x = 0; //~ ERROR [E0381]
+    let _b = &a.y;
+
+    let mut a: S<&&i32, &&i32>;
+    a.x = &&0; //~ ERROR [E0381]
+    let _b = &**a.y;
+}
diff --git a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
new file mode 100644
index 00000000000..73fded7545c
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
@@ -0,0 +1,82 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-ref-chain.rs:8:14
+   |
+LL |     let x: &&Box<i32>;
+   |         - binding declared here but left uninitialized
+LL |     let _y = &**x;
+   |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&Box<i32> = todo!();
+   |                       +++++++++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-ref-chain.rs:11:14
+   |
+LL |     let x: &&S<i32, i32>;
+   |         - binding declared here but left uninitialized
+LL |     let _y = &**x;
+   |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&S<i32, i32> = todo!();
+   |                          +++++++++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit-ref-chain.rs:14:14
+   |
+LL |     let x: &&i32;
+   |         - binding declared here but left uninitialized
+LL |     let _y = &**x;
+   |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&i32 = todo!();
+   |                  +++++++++
+
+error[E0381]: partially assigned binding `a` isn't fully initialized
+  --> $DIR/borrowck-uninit-ref-chain.rs:18:5
+   |
+LL |     let mut a: S<i32, i32>;
+   |         ----- binding declared here but left uninitialized
+LL |     a.x = 0;
+   |     ^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `a` isn't fully initialized
+  --> $DIR/borrowck-uninit-ref-chain.rs:22:5
+   |
+LL |     let mut a: S<&&i32, &&i32>;
+   |         ----- binding declared here but left uninitialized
+LL |     a.x = &&0;
+   |     ^^^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `a` isn't fully initialized
+  --> $DIR/borrowck-uninit-ref-chain.rs:27:5
+   |
+LL |     let mut a: S<i32, i32>;
+   |         ----- binding declared here but left uninitialized
+LL |     a.x = 0;
+   |     ^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `a` isn't fully initialized
+  --> $DIR/borrowck-uninit-ref-chain.rs:31:5
+   |
+LL |     let mut a: S<&&i32, &&i32>;
+   |         ----- binding declared here but left uninitialized
+LL |     a.x = &&0;
+   |     ^^^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-uninit.rs b/tests/ui/borrowck/borrowck-uninit.rs
new file mode 100644
index 00000000000..5d0ebabb008
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit.rs
@@ -0,0 +1,6 @@
+fn foo(x: isize) { println!("{}", x); }
+
+fn main() {
+    let x: isize;
+    foo(x); //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-uninit.stderr b/tests/ui/borrowck/borrowck-uninit.stderr
new file mode 100644
index 00000000000..eeafc4ce191
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uninit.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-uninit.rs:5:9
+   |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     foo(x);
+   |         ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-union-borrow-nested.rs b/tests/ui/borrowck/borrowck-union-borrow-nested.rs
new file mode 100644
index 00000000000..b3a6670fa48
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-borrow-nested.rs
@@ -0,0 +1,31 @@
+#[derive(Clone, Copy)]
+struct S {
+    a: u8,
+    b: u16,
+}
+
+#[derive(Clone, Copy)]
+union U {
+    s: S,
+    c: u32,
+}
+
+fn main() {
+    unsafe {
+        {
+            let mut u = U { s: S { a: 0, b: 1 } };
+            let ra = &mut u.s.a;
+            let b = u.s.b; // OK
+            ra.use_mut();
+        }
+        {
+            let mut u = U { s: S { a: 0, b: 1 } };
+            let ra = &mut u.s.a;
+            let b = u.c; //~ ERROR cannot use `u.c` because it was mutably borrowed
+            ra.use_mut();
+        }
+    }
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-union-borrow-nested.stderr b/tests/ui/borrowck/borrowck-union-borrow-nested.stderr
new file mode 100644
index 00000000000..4bd7d54cffe
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-borrow-nested.stderr
@@ -0,0 +1,13 @@
+error[E0503]: cannot use `u.c` because it was mutably borrowed
+  --> $DIR/borrowck-union-borrow-nested.rs:24:21
+   |
+LL |             let ra = &mut u.s.a;
+   |                      ---------- borrow of `u.s.a` occurs here
+LL |             let b = u.c;
+   |                     ^^^ use of borrowed `u.s.a`
+LL |             ra.use_mut();
+   |             ------------ borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0503`.
diff --git a/tests/ui/borrowck/borrowck-union-borrow.rs b/tests/ui/borrowck/borrowck-union-borrow.rs
new file mode 100644
index 00000000000..f01915398a4
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-borrow.rs
@@ -0,0 +1,96 @@
+#[derive(Clone, Copy)]
+union U {
+    a: u8,
+    b: u64,
+}
+
+fn main() {
+    unsafe {
+        let mut u = U { b: 0 };
+        // Imm borrow, same field
+        {
+            let ra = &u.a;
+            let ra2 = &u.a; // OK
+            drop(ra);
+        }
+        {
+            let ra = &u.a;
+            let a = u.a; // OK
+            drop(ra);
+        }
+        {
+            let ra = &u.a;
+            let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
+            drop(ra);
+        }
+        {
+            let ra = &u.a;
+            u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
+            drop(ra);
+        }
+        // Imm borrow, other field
+        {
+            let ra = &u.a;
+            let rb = &u.b; // OK
+            drop(ra);
+        }
+        {
+            let ra = &u.a;
+            let b = u.b; // OK
+            drop(ra);
+        }
+        {
+            let ra = &u.a;
+            let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`)
+            drop(ra);
+        }
+        {
+            let ra = &u.a;
+            u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
+            drop(ra);
+        }
+        // Mut borrow, same field
+        {
+            let rma = &mut u.a;
+            let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
+            drop(rma);
+        }
+        {
+            let ra = &mut u.a;
+            let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
+            drop(ra);
+        }
+        {
+            let rma = &mut u.a;
+            let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
+            drop(rma);
+        }
+        {
+            let rma = &mut u.a;
+            u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
+            drop(rma);
+        }
+        // Mut borrow, other field
+        {
+            let rma = &mut u.a;
+            let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`)
+            drop(rma);
+        }
+        {
+            let ra = &mut u.a;
+            let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
+
+            drop(ra);
+        }
+        {
+            let rma = &mut u.a;
+            let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
+            drop(rma);
+        }
+        {
+            let rma = &mut u.a;
+            u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
+            drop(rma);
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-union-borrow.stderr b/tests/ui/borrowck/borrowck-union-borrow.stderr
new file mode 100644
index 00000000000..090c7b6b51a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-borrow.stderr
@@ -0,0 +1,131 @@
+error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-union-borrow.rs:23:23
+   |
+LL |             let ra = &u.a;
+   |                      ---- immutable borrow occurs here
+LL |             let rma = &mut u.a;
+   |                       ^^^^^^^^ mutable borrow occurs here
+LL |             drop(ra);
+   |                  -- immutable borrow later used here
+
+error[E0506]: cannot assign to `u.a` because it is borrowed
+  --> $DIR/borrowck-union-borrow.rs:28:13
+   |
+LL |             let ra = &u.a;
+   |                      ---- borrow of `u.a` occurs here
+LL |             u.a = 1;
+   |             ^^^^^^^ assignment to borrowed `u.a` occurs here
+LL |             drop(ra);
+   |                  -- borrow later used here
+
+error[E0502]: cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`)
+  --> $DIR/borrowck-union-borrow.rs:44:23
+   |
+LL |             let ra = &u.a;
+   |                      ---- immutable borrow occurs here (via `u.a`)
+LL |             let rmb = &mut u.b;
+   |                       ^^^^^^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
+LL |             drop(ra);
+   |                  -- immutable borrow later used here
+   |
+   = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
+
+error[E0506]: cannot assign to `u.b` because it is borrowed
+  --> $DIR/borrowck-union-borrow.rs:49:13
+   |
+LL |             let ra = &u.a;
+   |                      ---- borrow of `u.b` occurs here
+LL |             u.b = 1;
+   |             ^^^^^^^ assignment to borrowed `u.b` occurs here
+LL |             drop(ra);
+   |                  -- borrow later used here
+
+error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-union-borrow.rs:55:22
+   |
+LL |             let rma = &mut u.a;
+   |                       -------- mutable borrow occurs here
+LL |             let ra = &u.a;
+   |                      ^^^^ immutable borrow occurs here
+LL |             drop(rma);
+   |                  --- mutable borrow later used here
+
+error[E0503]: cannot use `u.a` because it was mutably borrowed
+  --> $DIR/borrowck-union-borrow.rs:60:21
+   |
+LL |             let ra = &mut u.a;
+   |                      -------- borrow of `u.a` occurs here
+LL |             let a = u.a;
+   |                     ^^^ use of borrowed `u.a`
+LL |             drop(ra);
+   |                  -- borrow later used here
+
+error[E0499]: cannot borrow `u.a` as mutable more than once at a time
+  --> $DIR/borrowck-union-borrow.rs:65:24
+   |
+LL |             let rma = &mut u.a;
+   |                       -------- first mutable borrow occurs here
+LL |             let rma2 = &mut u.a;
+   |                        ^^^^^^^^ second mutable borrow occurs here
+LL |             drop(rma);
+   |                  --- first borrow later used here
+
+error[E0506]: cannot assign to `u.a` because it is borrowed
+  --> $DIR/borrowck-union-borrow.rs:70:13
+   |
+LL |             let rma = &mut u.a;
+   |                       -------- borrow of `u.a` occurs here
+LL |             u.a = 1;
+   |             ^^^^^^^ assignment to borrowed `u.a` occurs here
+LL |             drop(rma);
+   |                  --- borrow later used here
+
+error[E0502]: cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`)
+  --> $DIR/borrowck-union-borrow.rs:76:22
+   |
+LL |             let rma = &mut u.a;
+   |                       -------- mutable borrow occurs here (via `u.a`)
+LL |             let rb = &u.b;
+   |                      ^^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
+LL |             drop(rma);
+   |                  --- mutable borrow later used here
+   |
+   = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
+
+error[E0503]: cannot use `u.b` because it was mutably borrowed
+  --> $DIR/borrowck-union-borrow.rs:81:21
+   |
+LL |             let ra = &mut u.a;
+   |                      -------- borrow of `u.a` occurs here
+LL |             let b = u.b;
+   |                     ^^^ use of borrowed `u.a`
+LL |
+LL |             drop(ra);
+   |                  -- borrow later used here
+
+error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time
+  --> $DIR/borrowck-union-borrow.rs:87:24
+   |
+LL |             let rma = &mut u.a;
+   |                       -------- first mutable borrow occurs here (via `u.a`)
+LL |             let rmb2 = &mut u.b;
+   |                        ^^^^^^^^ second mutable borrow occurs here (via `u.b`)
+LL |             drop(rma);
+   |                  --- first borrow later used here
+   |
+   = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
+
+error[E0506]: cannot assign to `u.b` because it is borrowed
+  --> $DIR/borrowck-union-borrow.rs:92:13
+   |
+LL |             let rma = &mut u.a;
+   |                       -------- borrow of `u.b` occurs here
+LL |             u.b = 1;
+   |             ^^^^^^^ assignment to borrowed `u.b` occurs here
+LL |             drop(rma);
+   |                  --- borrow later used here
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0503, E0506.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-union-move-assign.rs b/tests/ui/borrowck/borrowck-union-move-assign.rs
new file mode 100644
index 00000000000..4c96ccdb25a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-move-assign.rs
@@ -0,0 +1,32 @@
+use std::mem::ManuallyDrop;
+
+// Non-copy
+struct A;
+struct B;
+
+union U {
+    a: ManuallyDrop<A>,
+    b: ManuallyDrop<B>,
+}
+
+fn main() {
+    unsafe {
+        {
+            let mut u = U { a: ManuallyDrop::new(A) };
+            let a = u.a;
+            let a = u.a; //~ ERROR use of moved value: `u`
+        }
+        {
+            let mut u = U { a: ManuallyDrop::new(A) };
+            let a = u.a;
+            u.a = ManuallyDrop::new(A);
+            let a = u.a; // OK
+        }
+        {
+            let mut u = U { a: ManuallyDrop::new(A) };
+            let a = u.a;
+            u.b = ManuallyDrop::new(B);
+            let a = u.a; // OK
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-union-move-assign.stderr b/tests/ui/borrowck/borrowck-union-move-assign.stderr
new file mode 100644
index 00000000000..af6f6fac408
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-move-assign.stderr
@@ -0,0 +1,13 @@
+error[E0382]: use of moved value: `u`
+  --> $DIR/borrowck-union-move-assign.rs:17:21
+   |
+LL |             let mut u = U { a: ManuallyDrop::new(A) };
+   |                 ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait
+LL |             let a = u.a;
+   |                     --- value moved here
+LL |             let a = u.a;
+   |                     ^^^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-union-move.rs b/tests/ui/borrowck/borrowck-union-move.rs
new file mode 100644
index 00000000000..510547ad5bb
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-move.rs
@@ -0,0 +1,86 @@
+use std::mem::ManuallyDrop;
+
+#[derive(Clone, Copy)]
+struct Copy;
+struct NonCopy;
+
+union Unn {
+    n1: ManuallyDrop<NonCopy>,
+    n2: ManuallyDrop<NonCopy>,
+}
+union Ucc {
+    c1: Copy,
+    c2: Copy,
+}
+union Ucn {
+    c: Copy,
+    n: ManuallyDrop<NonCopy>,
+}
+
+fn main() {
+    unsafe {
+        // 2 NonCopy
+        {
+            let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
+            let a = u.n1;
+            let a = u.n1; //~ ERROR use of moved value: `u`
+        }
+        {
+            let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
+            let a = u.n1;
+            let a = u; //~ ERROR use of moved value: `u`
+        }
+        {
+            let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
+            let a = u.n1;
+            let a = u.n2; //~ ERROR use of moved value: `u`
+        }
+        // 2 Copy
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u.c1; // OK
+        }
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u; // OK
+        }
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u.c2; // OK
+        }
+        // 1 Copy, 1 NonCopy
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u.c; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u.n; //~ ERROR use of moved value: `u`
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u.c; //~ ERROR use of moved value: `u`
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u.n; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u; //~ ERROR use of moved value: `u`
+        }
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-union-move.stderr b/tests/ui/borrowck/borrowck-union-move.stderr
new file mode 100644
index 00000000000..731607fbdd1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-move.stderr
@@ -0,0 +1,63 @@
+error[E0382]: use of moved value: `u`
+  --> $DIR/borrowck-union-move.rs:26:21
+   |
+LL |             let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
+   |                 ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
+LL |             let a = u.n1;
+   |                     ---- value moved here
+LL |             let a = u.n1;
+   |                     ^^^^ value used here after move
+
+error[E0382]: use of moved value: `u`
+  --> $DIR/borrowck-union-move.rs:31:21
+   |
+LL |             let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
+   |                 ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
+LL |             let a = u.n1;
+   |                     ---- value moved here
+LL |             let a = u;
+   |                     ^ value used here after move
+
+error[E0382]: use of moved value: `u`
+  --> $DIR/borrowck-union-move.rs:36:21
+   |
+LL |             let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
+   |                 ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
+LL |             let a = u.n1;
+   |                     ---- value moved here
+LL |             let a = u.n2;
+   |                     ^^^^ value used here after move
+
+error[E0382]: use of moved value: `u`
+  --> $DIR/borrowck-union-move.rs:63:21
+   |
+LL |             let mut u = Ucn { c: Copy };
+   |                 ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
+LL |             let a = u.n;
+   |                     --- value moved here
+LL |             let a = u.n;
+   |                     ^^^ value used here after move
+
+error[E0382]: use of moved value: `u`
+  --> $DIR/borrowck-union-move.rs:68:21
+   |
+LL |             let mut u = Ucn { c: Copy };
+   |                 ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
+LL |             let a = u.n;
+   |                     --- value moved here
+LL |             let a = u.c;
+   |                     ^^^ value used here after move
+
+error[E0382]: use of moved value: `u`
+  --> $DIR/borrowck-union-move.rs:83:21
+   |
+LL |             let mut u = Ucn { c: Copy };
+   |                 ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
+LL |             let a = u.n;
+   |                     --- value moved here
+LL |             let a = u;
+   |                     ^ value used here after move
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/borrowck-union-uninitialized.rs b/tests/ui/borrowck/borrowck-union-uninitialized.rs
new file mode 100644
index 00000000000..bbe9f22aac3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-uninitialized.rs
@@ -0,0 +1,18 @@
+struct S {
+    a: u8,
+}
+
+union U {
+    a: u8,
+}
+
+fn main() {
+    unsafe {
+        let mut s: S;
+        let mut u: U;
+        s.a = 0; //~ ERROR E0381
+        u.a = 0; //~ ERROR E0381
+        let sa = s.a;
+        let ua = u.a;
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-union-uninitialized.stderr b/tests/ui/borrowck/borrowck-union-uninitialized.stderr
new file mode 100644
index 00000000000..b7ff5f3955e
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-union-uninitialized.stderr
@@ -0,0 +1,25 @@
+error[E0381]: partially assigned binding `s` isn't fully initialized
+  --> $DIR/borrowck-union-uninitialized.rs:13:9
+   |
+LL |         let mut s: S;
+   |             ----- binding declared here but left uninitialized
+LL |         let mut u: U;
+LL |         s.a = 0;
+   |         ^^^^^^^ `s` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `u` isn't fully initialized
+  --> $DIR/borrowck-union-uninitialized.rs:14:9
+   |
+LL |         let mut u: U;
+   |             ----- binding declared here but left uninitialized
+LL |         s.a = 0;
+LL |         u.a = 0;
+   |         ^^^^^^^ `u` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-uniq-via-lend.rs b/tests/ui/borrowck/borrowck-uniq-via-lend.rs
new file mode 100644
index 00000000000..25d3e0b5486
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uniq-via-lend.rs
@@ -0,0 +1,61 @@
+fn borrow(_v: &isize) {}
+
+
+
+
+
+fn local() {
+    let mut v: Box<_> = Box::new(3);
+    borrow(&*v);
+}
+
+fn local_rec() {
+    struct F { f: Box<isize> }
+    let mut v = F {f: Box::new(3)};
+    borrow(&*v.f);
+}
+
+fn local_recs() {
+    struct F { f: G }
+    struct G { g: H }
+    struct H { h: Box<isize> }
+    let mut v = F {f: G {g: H {h: Box::new(3)}}};
+    borrow(&*v.f.g.h);
+}
+
+fn aliased_imm() {
+    let mut v: Box<_> = Box::new(3);
+    let w = &v;
+    borrow(&*v);
+    w.use_ref();
+}
+
+fn aliased_mut() {
+    let mut v: Box<_> = Box::new(3);
+    let w = &mut v;
+    borrow(&*v); //~ ERROR cannot borrow `*v`
+    w.use_mut();
+}
+
+fn aliased_other() {
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
+    let x = &mut w;
+    borrow(&*v);
+    x.use_mut();
+}
+
+fn aliased_other_reassign() {
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
+    let mut x = &mut w;
+    x = &mut v;
+    borrow(&*v); //~ ERROR cannot borrow `*v`
+    x.use_mut();
+}
+
+fn main() {
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-uniq-via-lend.stderr b/tests/ui/borrowck/borrowck-uniq-via-lend.stderr
new file mode 100644
index 00000000000..6dbe4c74b58
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uniq-via-lend.stderr
@@ -0,0 +1,23 @@
+error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-uniq-via-lend.rs:36:12
+   |
+LL |     let w = &mut v;
+   |             ------ mutable borrow occurs here
+LL |     borrow(&*v);
+   |            ^^^ immutable borrow occurs here
+LL |     w.use_mut();
+   |     ----------- mutable borrow later used here
+
+error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-uniq-via-lend.rs:53:12
+   |
+LL |     x = &mut v;
+   |         ------ mutable borrow occurs here
+LL |     borrow(&*v);
+   |            ^^^ immutable borrow occurs here
+LL |     x.use_mut();
+   |     ----------- mutable borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/borrowck-uniq-via-ref.rs b/tests/ui/borrowck/borrowck-uniq-via-ref.rs
new file mode 100644
index 00000000000..bdf7cc57a53
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-uniq-via-ref.rs
@@ -0,0 +1,49 @@
+// run-pass
+#![allow(dead_code)]
+
+// pretty-expanded FIXME #23616
+
+struct Rec {
+    f: Box<isize>,
+}
+
+struct Outer {
+    f: Inner
+}
+
+struct Inner {
+    g: Innermost
+}
+
+struct Innermost {
+    h: Box<isize>,
+}
+
+fn borrow(_v: &isize) {}
+
+fn box_mut(v: &mut Box<isize>) {
+    borrow(&**v); // OK: &mut -> &imm
+}
+
+fn box_mut_rec(v: &mut Rec) {
+    borrow(&*v.f); // OK: &mut -> &imm
+}
+
+fn box_mut_recs(v: &mut Outer) {
+    borrow(&*v.f.g.h); // OK: &mut -> &imm
+}
+
+fn box_imm(v: &Box<isize>) {
+    borrow(&**v); // OK
+}
+
+fn box_imm_rec(v: &Rec) {
+    borrow(&*v.f); // OK
+}
+
+fn box_imm_recs(v: &Outer) {
+    borrow(&*v.f.g.h); // OK
+}
+
+pub fn main() {
+}
diff --git a/tests/ui/borrowck/borrowck-univariant-enum.rs b/tests/ui/borrowck/borrowck-univariant-enum.rs
new file mode 100644
index 00000000000..c78e9475233
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-univariant-enum.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![allow(non_camel_case_types)]
+
+use std::cell::Cell;
+
+#[derive(Copy, Clone)]
+enum newtype {
+    newvar(isize)
+}
+
+pub fn main() {
+
+    // Test that borrowck treats enums with a single variant
+    // specially.
+
+    let x = &Cell::new(5);
+    let y = &Cell::new(newtype::newvar(3));
+    let z = match y.get() {
+      newtype::newvar(b) => {
+        x.set(x.get() + 1);
+        x.get() * b
+      }
+    };
+    assert_eq!(z, 18);
+}
diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
new file mode 100644
index 00000000000..adc7dfd541f
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+// Test file taken from issue 45129 (https://github.com/rust-lang/rust/issues/45129)
+
+struct Foo { x: [usize; 2] }
+
+static mut SFOO: Foo = Foo { x: [23, 32] };
+
+impl Foo {
+    fn x(&mut self) -> &mut usize { &mut self.x[0] }
+}
+
+fn main() {
+    unsafe {
+        let sfoo: *mut Foo = &mut SFOO;
+        let x = (*sfoo).x();
+        (*sfoo).x[1] += 1;
+        *x += 1;
+    }
+}
diff --git a/tests/ui/borrowck/borrowck-unused-mut-locals.rs b/tests/ui/borrowck/borrowck-unused-mut-locals.rs
new file mode 100644
index 00000000000..23ef975cbbc
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-unused-mut-locals.rs
@@ -0,0 +1,47 @@
+// run-pass
+#![allow(dead_code)]
+#![deny(unused_mut)]
+
+#[derive(Debug)]
+struct A {}
+
+fn init_a() -> A {
+    A {}
+}
+
+#[derive(Debug)]
+struct B<'a> {
+    ed: &'a mut A,
+}
+
+fn init_b<'a>(ed: &'a mut A) -> B<'a> {
+    B { ed }
+}
+
+#[derive(Debug)]
+struct C<'a> {
+    pd: &'a mut B<'a>,
+}
+
+fn init_c<'a>(pd: &'a mut B<'a>) -> C<'a> {
+    C { pd }
+}
+
+#[derive(Debug)]
+struct D<'a> {
+    sd: &'a mut C<'a>,
+}
+
+fn init_d<'a>(sd: &'a mut C<'a>) -> D<'a> {
+    D { sd }
+}
+
+fn main() {
+    let mut a = init_a();
+    let mut b = init_b(&mut a);
+    let mut c = init_c(&mut b);
+
+    let d = init_d(&mut c);
+
+    println!("{:?}", d)
+}
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
new file mode 100644
index 00000000000..d30b1de5cd0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
@@ -0,0 +1,9 @@
+fn test() {
+    let w: &mut [isize];
+    w[5] = 0; //~ ERROR [E0381]
+
+    let mut w: &mut [isize];
+    w[5] = 0; //~ ERROR [E0381]
+}
+
+fn main() { test(); }
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
new file mode 100644
index 00000000000..18e808f10d0
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
@@ -0,0 +1,29 @@
+error[E0381]: used binding `w` isn't initialized
+  --> $DIR/borrowck-use-in-index-lvalue.rs:3:5
+   |
+LL |     let w: &mut [isize];
+   |         - binding declared here but left uninitialized
+LL |     w[5] = 0;
+   |     ^^^^ `*w` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let w: &mut [isize] = todo!();
+   |                         +++++++++
+
+error[E0381]: used binding `w` isn't initialized
+  --> $DIR/borrowck-use-in-index-lvalue.rs:6:5
+   |
+LL |     let mut w: &mut [isize];
+   |         ----- binding declared here but left uninitialized
+LL |     w[5] = 0;
+   |     ^^^^ `*w` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut w: &mut [isize] = todo!();
+   |                             +++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs
new file mode 100644
index 00000000000..1cf763f66fd
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs
@@ -0,0 +1,49 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct A { a: isize, b: Box<isize> }
+
+fn field_copy_after_field_borrow() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let p = &mut x.b;
+    drop(x.a);
+    **p = 3;
+}
+
+fn fu_field_copy_after_field_borrow() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let p = &mut x.b;
+    let y = A { b: Box::new(3), .. x };
+    drop(y);
+    **p = 4;
+}
+
+fn field_deref_after_field_borrow() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let p = &mut x.a;
+    drop(*x.b);
+    *p = 3;
+}
+
+fn field_move_after_field_borrow() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let p = &mut x.a;
+    drop(x.b);
+    *p = 3;
+}
+
+fn fu_field_move_after_field_borrow() {
+    let mut x = A { a: 1, b: Box::new(2) };
+    let p = &mut x.a;
+    let y = A { a: 3, .. x };
+    drop(y);
+    *p = 4;
+}
+
+fn main() {
+    field_copy_after_field_borrow();
+    fu_field_copy_after_field_borrow();
+    field_deref_after_field_borrow();
+    field_move_after_field_borrow();
+    fu_field_move_after_field_borrow();
+}
diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow.rs b/tests/ui/borrowck/borrowck-use-mut-borrow.rs
new file mode 100644
index 00000000000..94f88395ff9
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-mut-borrow.rs
@@ -0,0 +1,86 @@
+#[derive(Copy, Clone)]
+struct A { a: isize, b: isize }
+
+struct B { a: isize, b: Box<isize> }
+
+
+
+fn var_copy_after_var_borrow() {
+    let mut x: isize = 1;
+    let p = &mut x;
+    drop(x); //~ ERROR cannot use `x` because it was mutably borrowed
+    *p = 2;
+}
+
+fn var_copy_after_field_borrow() {
+    let mut x = A { a: 1, b: 2 };
+    let p = &mut x.a;
+    drop(x); //~ ERROR cannot use `x` because it was mutably borrowed
+    *p = 3;
+}
+
+fn field_copy_after_var_borrow() {
+    let mut x = A { a: 1, b: 2 };
+    let p = &mut x;
+    drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed
+    p.a = 3;
+}
+
+fn field_copy_after_field_borrow() {
+    let mut x = A { a: 1, b: 2 };
+    let p = &mut x.a;
+    drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed
+    *p = 3;
+}
+
+fn fu_field_copy_after_var_borrow() {
+    let mut x = A { a: 1, b: 2 };
+    let p = &mut x;
+    let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed
+    drop(y);
+    p.a = 4;
+}
+
+fn fu_field_copy_after_field_borrow() {
+    let mut x = A { a: 1, b: 2 };
+    let p = &mut x.a;
+    let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed
+    drop(y);
+    *p = 4;
+}
+
+fn var_deref_after_var_borrow() {
+    let mut x: Box<isize> = Box::new(1);
+    let p = &mut x;
+    drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed
+    **p = 2;
+}
+
+fn field_deref_after_var_borrow() {
+    let mut x = B { a: 1, b: Box::new(2) };
+    let p = &mut x;
+    drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed
+    p.a = 3;
+}
+
+fn field_deref_after_field_borrow() {
+    let mut x = B { a: 1, b: Box::new(2) };
+    let p = &mut x.b;
+    drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed
+    **p = 3;
+}
+
+fn main() {
+    var_copy_after_var_borrow();
+    var_copy_after_field_borrow();
+
+    field_copy_after_var_borrow();
+    field_copy_after_field_borrow();
+
+    fu_field_copy_after_var_borrow();
+    fu_field_copy_after_field_borrow();
+
+    var_deref_after_var_borrow();
+    field_deref_after_var_borrow();
+    field_deref_after_field_borrow();
+}
diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow.stderr b/tests/ui/borrowck/borrowck-use-mut-borrow.stderr
new file mode 100644
index 00000000000..91d69c51e81
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-mut-borrow.stderr
@@ -0,0 +1,95 @@
+error[E0503]: cannot use `x` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:11:10
+   |
+LL |     let p = &mut x;
+   |             ------ borrow of `x` occurs here
+LL |     drop(x);
+   |          ^ use of borrowed `x`
+LL |     *p = 2;
+   |     ------ borrow later used here
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:18:10
+   |
+LL |     let p = &mut x.a;
+   |             -------- borrow of `x.a` occurs here
+LL |     drop(x);
+   |          ^ use of borrowed `x.a`
+LL |     *p = 3;
+   |     ------ borrow later used here
+
+error[E0503]: cannot use `x.a` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:25:10
+   |
+LL |     let p = &mut x;
+   |             ------ borrow of `x` occurs here
+LL |     drop(x.a);
+   |          ^^^ use of borrowed `x`
+LL |     p.a = 3;
+   |     ------- borrow later used here
+
+error[E0503]: cannot use `x.a` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:32:10
+   |
+LL |     let p = &mut x.a;
+   |             -------- borrow of `x.a` occurs here
+LL |     drop(x.a);
+   |          ^^^ use of borrowed `x.a`
+LL |     *p = 3;
+   |     ------ borrow later used here
+
+error[E0503]: cannot use `x.a` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:39:13
+   |
+LL |     let p = &mut x;
+   |             ------ borrow of `x` occurs here
+LL |     let y = A { b: 3, .. x };
+   |             ^^^^^^^^^^^^^^^^ use of borrowed `x`
+LL |     drop(y);
+LL |     p.a = 4;
+   |     ------- borrow later used here
+
+error[E0503]: cannot use `x.a` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:47:13
+   |
+LL |     let p = &mut x.a;
+   |             -------- borrow of `x.a` occurs here
+LL |     let y = A { b: 3, .. x };
+   |             ^^^^^^^^^^^^^^^^ use of borrowed `x.a`
+LL |     drop(y);
+LL |     *p = 4;
+   |     ------ borrow later used here
+
+error[E0503]: cannot use `*x` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:55:10
+   |
+LL |     let p = &mut x;
+   |             ------ borrow of `x` occurs here
+LL |     drop(*x);
+   |          ^^ use of borrowed `x`
+LL |     **p = 2;
+   |     ------- borrow later used here
+
+error[E0503]: cannot use `*x.b` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:62:10
+   |
+LL |     let p = &mut x;
+   |             ------ borrow of `x` occurs here
+LL |     drop(*x.b);
+   |          ^^^^ use of borrowed `x`
+LL |     p.a = 3;
+   |     ------- borrow later used here
+
+error[E0503]: cannot use `*x.b` because it was mutably borrowed
+  --> $DIR/borrowck-use-mut-borrow.rs:69:10
+   |
+LL |     let p = &mut x.b;
+   |             -------- borrow of `x.b` occurs here
+LL |     drop(*x.b);
+   |          ^^^^ use of borrowed `x.b`
+LL |     **p = 3;
+   |     ------- borrow later used here
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0503`.
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
new file mode 100644
index 00000000000..3ce72161814
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
@@ -0,0 +1,10 @@
+// Variation on `borrowck-use-uninitialized-in-cast` in which we do a
+// trait cast from an uninitialized source. Issue #20791.
+
+trait Foo { fn dummy(&self) { } }
+impl Foo for i32 { }
+
+fn main() {
+    let x: &i32;
+    let y = x as *const dyn Foo; //~ ERROR [E0381]
+}
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
new file mode 100644
index 00000000000..55f3ff553c1
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13
+   |
+LL |     let x: &i32;
+   |         - binding declared here but left uninitialized
+LL |     let y = x as *const dyn Foo;
+   |             ^ `*x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &i32 = todo!();
+   |                 +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
new file mode 100644
index 00000000000..a355a546dc6
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
@@ -0,0 +1,8 @@
+// Check that we detect unused values that are cast to other things.
+// The problem was specified to casting to `*`, as creating unsafe
+// pointers was not being fully checked. Issue #20791.
+
+fn main() {
+    let x: &i32;
+    let y = x as *const i32; //~ ERROR [E0381]
+}
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
new file mode 100644
index 00000000000..ea3d0d3ef51
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13
+   |
+LL |     let x: &i32;
+   |         - binding declared here but left uninitialized
+LL |     let y = x as *const i32;
+   |             ^ `*x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &i32 = todo!();
+   |                 +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-element-loan.rs b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.rs
new file mode 100644
index 00000000000..cd853b83363
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.rs
@@ -0,0 +1,31 @@
+fn a<'a>() -> &'a [isize] {
+    let vec = vec![1, 2, 3, 4];
+    let vec: &[isize] = &vec;
+    let tail = match vec {
+        &[_, ref tail @ ..] => tail,
+        _ => panic!("a")
+    };
+    tail //~ ERROR cannot return value referencing local variable `vec`
+}
+
+fn b<'a>() -> &'a [isize] {
+    let vec = vec![1, 2, 3, 4];
+    let vec: &[isize] = &vec;
+    let init = match vec {
+        &[ref init @ .., _] => init,
+        _ => panic!("b")
+    };
+    init //~ ERROR cannot return value referencing local variable `vec`
+}
+
+fn c<'a>() -> &'a [isize] {
+    let vec = vec![1, 2, 3, 4];
+    let vec: &[isize] = &vec;
+    let slice = match vec {
+        &[_, ref slice @ .., _] => slice,
+        _ => panic!("c")
+    };
+    slice //~ ERROR cannot return value referencing local variable `vec`
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-element-loan.stderr b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.stderr
new file mode 100644
index 00000000000..170982b1693
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.stderr
@@ -0,0 +1,30 @@
+error[E0515]: cannot return value referencing local variable `vec`
+  --> $DIR/borrowck-vec-pattern-element-loan.rs:8:5
+   |
+LL |     let vec: &[isize] = &vec;
+   |                         ---- `vec` is borrowed here
+...
+LL |     tail
+   |     ^^^^ returns a value referencing data owned by the current function
+
+error[E0515]: cannot return value referencing local variable `vec`
+  --> $DIR/borrowck-vec-pattern-element-loan.rs:18:5
+   |
+LL |     let vec: &[isize] = &vec;
+   |                         ---- `vec` is borrowed here
+...
+LL |     init
+   |     ^^^^ returns a value referencing data owned by the current function
+
+error[E0515]: cannot return value referencing local variable `vec`
+  --> $DIR/borrowck-vec-pattern-element-loan.rs:28:5
+   |
+LL |     let vec: &[isize] = &vec;
+   |                         ---- `vec` is borrowed here
+...
+LL |     slice
+   |     ^^^^^ returns a value referencing data owned by the current function
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs
new file mode 100644
index 00000000000..05859c95d17
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs
@@ -0,0 +1,12 @@
+fn a() {
+    let mut v = vec![1, 2, 3];
+    let vb: &mut [isize] = &mut v;
+    match vb {
+        &mut [_a, ref tail @ ..] => {
+            v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
+        }
+        _ => {}
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr
new file mode 100644
index 00000000000..eb0f24b9b7a
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr
@@ -0,0 +1,15 @@
+error[E0499]: cannot borrow `v` as mutable more than once at a time
+  --> $DIR/borrowck-vec-pattern-loan-from-mut.rs:6:13
+   |
+LL |     let vb: &mut [isize] = &mut v;
+   |                            ------ first mutable borrow occurs here
+...
+LL |             v.push(tail[0] + tail[1]);
+   |             ^^^^^^^-------^^^^^^^^^^^
+   |             |      |
+   |             |      first borrow later used here
+   |             second mutable borrow occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-move-tail.rs b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.rs
new file mode 100644
index 00000000000..9b8ba2ea8ad
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.rs
@@ -0,0 +1,11 @@
+fn main() {
+    let mut a = [1, 2, 3, 4];
+    let t = match a {
+        [1, 2, ref tail @ ..] => tail,
+        _ => unreachable!()
+    };
+    println!("t[0]: {}", t[0]);
+    a[2] = 0; //~ ERROR cannot assign to `a[_]` because it is borrowed
+    println!("t[0]: {}", t[0]);
+    t[0];
+}
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
new file mode 100644
index 00000000000..0ac7df944d7
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `a[_]` because it is borrowed
+  --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5
+   |
+LL |         [1, 2, ref tail @ ..] => tail,
+   |                -------- borrow of `a[_]` occurs here
+...
+LL |     a[2] = 0;
+   |     ^^^^^^^^ assignment to borrowed `a[_]` occurs here
+LL |     println!("t[0]: {}", t[0]);
+   |                          ---- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
new file mode 100644
index 00000000000..0e9284a2cad
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
@@ -0,0 +1,94 @@
+#![feature(box_patterns)]
+
+
+fn a() {
+    let mut vec = [Box::new(1), Box::new(2), Box::new(3)];
+    match vec {
+        [box ref _a, _, _] => {
+        //~^ NOTE borrow of `vec[_]` occurs here
+            vec[0] = Box::new(4); //~ ERROR cannot assign
+            //~^ NOTE assignment to borrowed `vec[_]` occurs here
+            _a.use_ref();
+            //~^ NOTE borrow later used here
+        }
+    }
+}
+
+fn b() {
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
+    let vec: &mut [Box<isize>] = &mut vec;
+    match vec {
+        &mut [ref _b @ ..] => {
+        //~^ borrow of `vec[_]` occurs here
+            vec[0] = Box::new(4); //~ ERROR cannot assign
+            //~^ NOTE assignment to borrowed `vec[_]` occurs here
+            _b.use_ref();
+            //~^ NOTE borrow later used here
+        }
+    }
+}
+
+fn c() {
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
+    let vec: &mut [Box<isize>] = &mut vec;
+    match vec {
+        //~^ ERROR cannot move out
+        //~| NOTE cannot move out
+        &mut [_a,
+        //~^ NOTE data moved here
+        //~| NOTE move occurs because `_a` has type
+        //~| HELP consider removing the mutable borrow
+            ..
+        ] => {
+        }
+        _ => {}
+    }
+    let a = vec[0]; //~ ERROR cannot move out
+    //~| NOTE cannot move out of here
+    //~| NOTE move occurs because
+    //~| HELP consider borrowing here
+}
+
+fn d() {
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
+    let vec: &mut [Box<isize>] = &mut vec;
+    match vec {
+        //~^ ERROR cannot move out
+        //~| NOTE cannot move out
+        &mut [
+        //~^ HELP consider removing the mutable borrow
+         _b] => {}
+        //~^ NOTE data moved here
+        //~| NOTE move occurs because `_b` has type
+        _ => {}
+    }
+    let a = vec[0]; //~ ERROR cannot move out
+    //~| NOTE cannot move out of here
+    //~| NOTE move occurs because
+    //~| HELP consider borrowing here
+}
+
+fn e() {
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
+    let vec: &mut [Box<isize>] = &mut vec;
+    match vec {
+        //~^ ERROR cannot move out
+        //~| NOTE cannot move out
+        //~| NOTE move occurs because these variables have types
+        &mut [_a, _b, _c] => {}
+        //~^ NOTE data moved here
+        //~| NOTE and here
+        //~| NOTE and here
+        //~| HELP consider removing the mutable borrow
+        _ => {}
+    }
+    let a = vec[0]; //~ ERROR cannot move out
+    //~| NOTE cannot move out of here
+    //~| NOTE move occurs because
+    //~| HELP consider borrowing here
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
new file mode 100644
index 00000000000..0dc5e64e4ff
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
@@ -0,0 +1,125 @@
+error[E0506]: cannot assign to `vec[_]` because it is borrowed
+  --> $DIR/borrowck-vec-pattern-nesting.rs:9:13
+   |
+LL |         [box ref _a, _, _] => {
+   |              ------ borrow of `vec[_]` occurs here
+LL |
+LL |             vec[0] = Box::new(4);
+   |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
+LL |
+LL |             _a.use_ref();
+   |             ------------ borrow later used here
+
+error[E0506]: cannot assign to `vec[_]` because it is borrowed
+  --> $DIR/borrowck-vec-pattern-nesting.rs:23:13
+   |
+LL |         &mut [ref _b @ ..] => {
+   |               ------ borrow of `vec[_]` occurs here
+LL |
+LL |             vec[0] = Box::new(4);
+   |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
+LL |
+LL |             _b.use_ref();
+   |             ------------ borrow later used here
+
+error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
+  --> $DIR/borrowck-vec-pattern-nesting.rs:34:11
+   |
+LL |     match vec {
+   |           ^^^ cannot move out of here
+...
+LL |         &mut [_a,
+   |               --
+   |               |
+   |               data moved here
+   |               move occurs because `_a` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider removing the mutable borrow
+   |
+LL -         &mut [_a,
+LL +         [_a,
+   |
+
+error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
+  --> $DIR/borrowck-vec-pattern-nesting.rs:46:13
+   |
+LL |     let a = vec[0];
+   |             ^^^^^^
+   |             |
+   |             cannot move out of here
+   |             move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |     let a = &vec[0];
+   |             +
+
+error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
+  --> $DIR/borrowck-vec-pattern-nesting.rs:55:11
+   |
+LL |     match vec {
+   |           ^^^ cannot move out of here
+...
+LL |          _b] => {}
+   |          --
+   |          |
+   |          data moved here
+   |          move occurs because `_b` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider removing the mutable borrow
+   |
+LL -         &mut [
+LL +         [
+   |
+
+error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
+  --> $DIR/borrowck-vec-pattern-nesting.rs:65:13
+   |
+LL |     let a = vec[0];
+   |             ^^^^^^
+   |             |
+   |             cannot move out of here
+   |             move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |     let a = &vec[0];
+   |             +
+
+error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
+  --> $DIR/borrowck-vec-pattern-nesting.rs:74:11
+   |
+LL |     match vec {
+   |           ^^^ cannot move out of here
+...
+LL |         &mut [_a, _b, _c] => {}
+   |               --  --  -- ...and here
+   |               |   |
+   |               |   ...and here
+   |               data moved here
+   |
+   = note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+   |
+LL -         &mut [_a, _b, _c] => {}
+LL +         [_a, _b, _c] => {}
+   |
+
+error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
+  --> $DIR/borrowck-vec-pattern-nesting.rs:85:13
+   |
+LL |     let a = vec[0];
+   |             ^^^^^^
+   |             |
+   |             cannot move out of here
+   |             move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |     let a = &vec[0];
+   |             +
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0506, E0508.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs
new file mode 100644
index 00000000000..39872825cd2
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs
@@ -0,0 +1,14 @@
+fn a<'a>() -> &'a isize {
+    let vec = vec![1, 2, 3, 4];
+    let vec: &[isize] = &vec;
+    let tail = match vec {
+        &[_a, ref tail @ ..] => &tail[0],
+        _ => panic!("foo")
+    };
+    tail //~ ERROR cannot return value referencing local variable `vec`
+}
+
+fn main() {
+    let fifth = a();
+    println!("{}", *fifth);
+}
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr
new file mode 100644
index 00000000000..7e21c55f21b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr
@@ -0,0 +1,12 @@
+error[E0515]: cannot return value referencing local variable `vec`
+  --> $DIR/borrowck-vec-pattern-tail-element-loan.rs:8:5
+   |
+LL |     let vec: &[isize] = &vec;
+   |                         ---- `vec` is borrowed here
+...
+LL |     tail
+   |     ^^^^ returns a value referencing data owned by the current function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/borrowck-while-break.rs b/tests/ui/borrowck/borrowck-while-break.rs
new file mode 100644
index 00000000000..7100b713031
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-while-break.rs
@@ -0,0 +1,12 @@
+fn test(cond: bool) {
+    let v;
+    while cond {
+        v = 3;
+        break;
+    }
+    println!("{}", v); //~ ERROR E0381
+}
+
+fn main() {
+    test(true);
+}
diff --git a/tests/ui/borrowck/borrowck-while-break.stderr b/tests/ui/borrowck/borrowck-while-break.stderr
new file mode 100644
index 00000000000..13143d436df
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-while-break.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `v` is possibly-uninitialized
+  --> $DIR/borrowck-while-break.rs:7:20
+   |
+LL |     let v;
+   |         - binding declared here but left uninitialized
+LL |     while cond {
+   |           ---- if this condition isn't met and the `while` loop runs 0 times, `v` is not initialized
+...
+LL |     println!("{}", v);
+   |                    ^ `v` used here but it is possibly-uninitialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-while-cond.rs b/tests/ui/borrowck/borrowck-while-cond.rs
new file mode 100644
index 00000000000..62a9bdd2020
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-while-cond.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let x: bool;
+    while x { } //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/borrowck-while-cond.stderr b/tests/ui/borrowck/borrowck-while-cond.stderr
new file mode 100644
index 00000000000..5d019498956
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-while-cond.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/borrowck-while-cond.rs:3:11
+   |
+LL |     let x: bool;
+   |         - binding declared here but left uninitialized
+LL |     while x { }
+   |           ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: bool = false;
+   |                 +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/borrowck-while.rs b/tests/ui/borrowck/borrowck-while.rs
new file mode 100644
index 00000000000..f49a778eb6b
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-while.rs
@@ -0,0 +1,7 @@
+fn f() -> isize {
+    let mut x: isize;
+    while 1 == 1 { x = 10; }
+    return x; //~ ERROR E0381
+}
+
+fn main() { f(); }
diff --git a/tests/ui/borrowck/borrowck-while.stderr b/tests/ui/borrowck/borrowck-while.stderr
new file mode 100644
index 00000000000..c45235990c3
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-while.stderr
@@ -0,0 +1,13 @@
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/borrowck-while.rs:4:12
+   |
+LL |     let mut x: isize;
+   |         ----- binding declared here but left uninitialized
+LL |     while 1 == 1 { x = 10; }
+   |           ------ if this condition isn't met and the `while` loop runs 0 times, `x` is not initialized
+LL |     return x;
+   |            ^ `x` used here but it is possibly-uninitialized
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.rs b/tests/ui/borrowck/copy-suggestion-region-vid.rs
new file mode 100644
index 00000000000..dff95283459
--- /dev/null
+++ b/tests/ui/borrowck/copy-suggestion-region-vid.rs
@@ -0,0 +1,17 @@
+pub struct DataStruct();
+
+pub struct HelperStruct<'n> {
+    pub helpers: [Vec<&'n i64>; 2],
+    pub is_empty: bool,
+}
+
+impl DataStruct {
+    pub fn f(&self) -> HelperStruct {
+        let helpers = [vec![], vec![]];
+
+        HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+        //~^ ERROR borrow of moved value
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.stderr b/tests/ui/borrowck/copy-suggestion-region-vid.stderr
new file mode 100644
index 00000000000..1685acf8718
--- /dev/null
+++ b/tests/ui/borrowck/copy-suggestion-region-vid.stderr
@@ -0,0 +1,14 @@
+error[E0382]: borrow of moved value: `helpers`
+  --> $DIR/copy-suggestion-region-vid.rs:12:43
+   |
+LL |         let helpers = [vec![], vec![]];
+   |             ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait
+LL |
+LL |         HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+   |                        -------            ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
+   |                        |
+   |                        value moved here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/disallow-possibly-uninitialized.rs b/tests/ui/borrowck/disallow-possibly-uninitialized.rs
new file mode 100644
index 00000000000..17de40d5ba9
--- /dev/null
+++ b/tests/ui/borrowck/disallow-possibly-uninitialized.rs
@@ -0,0 +1,22 @@
+// Test that we don't allow partial initialization.
+// This may be relaxed in the future (see #54987).
+
+fn main() {
+    let mut t: (u64, u64);
+    t.0 = 1;
+    //~^ ERROR E0381
+    t.1 = 1;
+
+    let mut t: (u64, u64);
+    t.1 = 1;
+    //~^ ERROR E0381
+    t.0 = 1;
+
+    let mut t: (u64, u64);
+    t.0 = 1;
+    //~^ ERROR E0381
+
+    let mut t: (u64,);
+    t.0 = 1;
+    //~^ ERROR E0381
+}
diff --git a/tests/ui/borrowck/disallow-possibly-uninitialized.stderr b/tests/ui/borrowck/disallow-possibly-uninitialized.stderr
new file mode 100644
index 00000000000..9a84c6fefae
--- /dev/null
+++ b/tests/ui/borrowck/disallow-possibly-uninitialized.stderr
@@ -0,0 +1,43 @@
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/disallow-possibly-uninitialized.rs:6:5
+   |
+LL |     let mut t: (u64, u64);
+   |         ----- binding declared here but left uninitialized
+LL |     t.0 = 1;
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/disallow-possibly-uninitialized.rs:11:5
+   |
+LL |     let mut t: (u64, u64);
+   |         ----- binding declared here but left uninitialized
+LL |     t.1 = 1;
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/disallow-possibly-uninitialized.rs:16:5
+   |
+LL |     let mut t: (u64, u64);
+   |         ----- binding declared here but left uninitialized
+LL |     t.0 = 1;
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/disallow-possibly-uninitialized.rs:20:5
+   |
+LL |     let mut t: (u64,);
+   |         ----- binding declared here but left uninitialized
+LL |     t.0 = 1;
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs
new file mode 100644
index 00000000000..524459291f8
--- /dev/null
+++ b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs
@@ -0,0 +1,8 @@
+fn main() {
+    let mut vec: Vec<i32> = Vec::new();
+    let closure = move || {
+        vec.clear();
+        let mut iter = vec.iter();
+        move || { iter.next() } //~ ERROR captured variable cannot escape `FnMut` closure bod
+    };
+}
diff --git a/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr
new file mode 100644
index 00000000000..78ca090feb7
--- /dev/null
+++ b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr
@@ -0,0 +1,18 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs:6:9
+   |
+LL |     let mut vec: Vec<i32> = Vec::new();
+   |         ------- variable defined here
+LL |     let closure = move || {
+   |                         - inferred to be a `FnMut` closure
+LL |         vec.clear();
+   |         --- variable captured here
+LL |         let mut iter = vec.iter();
+LL |         move || { iter.next() }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = 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/tests/ui/borrowck/fsu-moves-and-copies.rs b/tests/ui/borrowck/fsu-moves-and-copies.rs
new file mode 100644
index 00000000000..85e0a840a19
--- /dev/null
+++ b/tests/ui/borrowck/fsu-moves-and-copies.rs
@@ -0,0 +1,95 @@
+// run-pass
+
+#![allow(non_camel_case_types)]
+#![allow(stable_features)]
+// Issue 4691: Ensure that functional-struct-updates operates
+// correctly and moves rather than copy when appropriate.
+
+#![feature(core)]
+
+struct ncint { v: isize }
+fn ncint(v: isize) -> ncint { ncint { v: v } }
+
+struct NoFoo { copied: isize, nocopy: ncint, }
+impl NoFoo {
+    fn new(x:isize,y:isize) -> NoFoo { NoFoo { copied: x, nocopy: ncint(y) } }
+}
+
+struct MoveFoo { copied: isize, moved: Box<isize>, }
+impl MoveFoo {
+    fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: Box::new(y) } }
+}
+
+struct DropNoFoo { inner: NoFoo }
+impl DropNoFoo {
+    fn new(x:isize,y:isize) -> DropNoFoo { DropNoFoo { inner: NoFoo::new(x,y) } }
+}
+impl Drop for DropNoFoo { fn drop(&mut self) { } }
+
+struct DropMoveFoo { inner: MoveFoo }
+impl DropMoveFoo {
+    fn new(x:isize,y:isize) -> DropMoveFoo { DropMoveFoo { inner: MoveFoo::new(x,y) } }
+}
+impl Drop for DropMoveFoo { fn drop(&mut self) { } }
+
+
+fn test0() {
+    // just copy implicitly copyable fields from `f`, no moves
+    // (and thus it is okay that these are Drop; compare against
+    // test ui/borrowck/borrowck-struct-update-with-dtor.rs).
+
+    // Case 1: Nocopyable
+    let f = DropNoFoo::new(1, 2);
+    let b = DropNoFoo { inner: NoFoo { nocopy: ncint(3), ..f.inner }};
+    let c = DropNoFoo { inner: NoFoo { nocopy: ncint(4), ..f.inner }};
+    assert_eq!(f.inner.copied,    1);
+    assert_eq!(f.inner.nocopy.v, 2);
+
+    assert_eq!(b.inner.copied,    1);
+    assert_eq!(b.inner.nocopy.v, 3);
+
+    assert_eq!(c.inner.copied,    1);
+    assert_eq!(c.inner.nocopy.v, 4);
+
+    // Case 2: Owned
+    let f = DropMoveFoo::new(5, 6);
+    let b = DropMoveFoo { inner: MoveFoo { moved: Box::new(7), ..f.inner }};
+    let c = DropMoveFoo { inner: MoveFoo { moved: Box::new(8), ..f.inner }};
+    assert_eq!(f.inner.copied,    5);
+    assert_eq!(*f.inner.moved,    6);
+
+    assert_eq!(b.inner.copied,    5);
+    assert_eq!(*b.inner.moved,    7);
+
+    assert_eq!(c.inner.copied,    5);
+    assert_eq!(*c.inner.moved,    8);
+}
+
+fn test1() {
+    // copying move-by-default fields from `f`, so it moves:
+    let f = MoveFoo::new(11, 12);
+
+    let b = MoveFoo {moved: Box::new(13), ..f};
+    let c = MoveFoo {copied: 14, ..f};
+    assert_eq!(b.copied,    11);
+    assert_eq!(*b.moved,    13);
+    assert_eq!(c.copied,    14);
+    assert_eq!(*c.moved,    12);
+}
+
+fn test2() {
+    // move non-copyable field
+    let f = NoFoo::new(21, 22);
+    let b = NoFoo {nocopy: ncint(23), ..f};
+    let c = NoFoo {copied: 24, ..f};
+    assert_eq!(b.copied,    21);
+    assert_eq!(b.nocopy.v, 23);
+    assert_eq!(c.copied,    24);
+    assert_eq!(c.nocopy.v, 22);
+}
+
+pub fn main() {
+    test0();
+    test1();
+    test2();
+}
diff --git a/tests/ui/borrowck/immut-function-arguments.rs b/tests/ui/borrowck/immut-function-arguments.rs
new file mode 100644
index 00000000000..242a33e8216
--- /dev/null
+++ b/tests/ui/borrowck/immut-function-arguments.rs
@@ -0,0 +1,9 @@
+fn f(y: Box<isize>) {
+    *y = 5; //~ ERROR cannot assign
+}
+
+fn g() {
+    let _frob = |q: Box<isize>| { *q = 2; }; //~ ERROR cannot assign
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/immut-function-arguments.stderr b/tests/ui/borrowck/immut-function-arguments.stderr
new file mode 100644
index 00000000000..d5392e7d66f
--- /dev/null
+++ b/tests/ui/borrowck/immut-function-arguments.stderr
@@ -0,0 +1,25 @@
+error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable
+  --> $DIR/immut-function-arguments.rs:2:5
+   |
+LL |     *y = 5;
+   |     ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn f(mut y: Box<isize>) {
+   |      +++
+
+error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable
+  --> $DIR/immut-function-arguments.rs:6:35
+   |
+LL |     let _frob = |q: Box<isize>| { *q = 2; };
+   |                                   ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let _frob = |mut q: Box<isize>| { *q = 2; };
+   |                  +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/immutable-arg.rs b/tests/ui/borrowck/immutable-arg.rs
new file mode 100644
index 00000000000..2352d1bbe64
--- /dev/null
+++ b/tests/ui/borrowck/immutable-arg.rs
@@ -0,0 +1,6 @@
+fn foo(_x: u32) {
+    _x = 4;
+    //~^ ERROR cannot assign to immutable argument `_x`
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/immutable-arg.stderr b/tests/ui/borrowck/immutable-arg.stderr
new file mode 100644
index 00000000000..bddb0633a0b
--- /dev/null
+++ b/tests/ui/borrowck/immutable-arg.stderr
@@ -0,0 +1,11 @@
+error[E0384]: cannot assign to immutable argument `_x`
+  --> $DIR/immutable-arg.rs:2:5
+   |
+LL | fn foo(_x: u32) {
+   |        -- help: consider making this binding mutable: `mut _x`
+LL |     _x = 4;
+   |     ^^^^^^ cannot assign to immutable argument
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0384`.
diff --git a/tests/ui/borrowck/index-mut-help-with-impl.rs b/tests/ui/borrowck/index-mut-help-with-impl.rs
new file mode 100644
index 00000000000..44b57c4a038
--- /dev/null
+++ b/tests/ui/borrowck/index-mut-help-with-impl.rs
@@ -0,0 +1,10 @@
+// When mutably indexing a type that implements `Index` and `IndexMut` but
+// `Index::index` is being used specifically, the normal special help message
+// should not mention a missing `IndexMut` impl.
+
+fn main() {
+    use std::ops::Index;
+
+    let v = String::from("dinosaur");
+    Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR
+}
diff --git a/tests/ui/borrowck/index-mut-help-with-impl.stderr b/tests/ui/borrowck/index-mut-help-with-impl.stderr
new file mode 100644
index 00000000000..69dca7e7b56
--- /dev/null
+++ b/tests/ui/borrowck/index-mut-help-with-impl.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/index-mut-help-with-impl.rs:9:5
+   |
+LL |     Index::index(&v, 1..2).make_ascii_uppercase();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/index-mut-help.rs b/tests/ui/borrowck/index-mut-help.rs
new file mode 100644
index 00000000000..35266e113a6
--- /dev/null
+++ b/tests/ui/borrowck/index-mut-help.rs
@@ -0,0 +1,13 @@
+// When mutably indexing a type that implements `Index` but not `IndexMut`, a
+// special 'help' message is added to the output.
+use std::collections::HashMap;
+
+
+fn main() {
+    let mut map = HashMap::new();
+    map.insert("peter", "23".to_string());
+
+    map["peter"].clear();           //~ ERROR
+    map["peter"] = "0".to_string(); //~ ERROR
+    let _ = &mut map["peter"];      //~ ERROR
+}
diff --git a/tests/ui/borrowck/index-mut-help.stderr b/tests/ui/borrowck/index-mut-help.stderr
new file mode 100644
index 00000000000..f42d7e01554
--- /dev/null
+++ b/tests/ui/borrowck/index-mut-help.stderr
@@ -0,0 +1,41 @@
+error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable
+  --> $DIR/index-mut-help.rs:10:5
+   |
+LL |     map["peter"].clear();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
+help: to modify a `HashMap<&str, String>` use `.get_mut()`
+   |
+LL |     map.get_mut("peter").map(|val| val.clear());
+   |        ~~~~~~~~~       ~~~~~~~~~~~~~~~        +
+
+error[E0594]: cannot assign to data in an index of `HashMap<&str, String>`
+  --> $DIR/index-mut-help.rs:11:5
+   |
+LL |     map["peter"] = "0".to_string();
+   |     ^^^^^^^^^^^^ cannot assign
+   |
+   = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
+help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
+   |
+LL |     map.insert("peter", "0".to_string());
+   |        ~~~~~~~~       ~                +
+LL |     map.get_mut("peter").map(|val| { *val = "0".to_string(); });
+   |        ~~~~~~~~~       ~~~~~~~~~~~~~~~~~~                  ++++
+LL |     let val = map.entry("peter").or_insert("0".to_string());
+   |     +++++++++    ~~~~~~~       ~~~~~~~~~~~~               +
+
+error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable
+  --> $DIR/index-mut-help.rs:12:13
+   |
+LL |     let _ = &mut map["peter"];
+   |             ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
+   = help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/issue-101119.rs b/tests/ui/borrowck/issue-101119.rs
new file mode 100644
index 00000000000..64e52eaac06
--- /dev/null
+++ b/tests/ui/borrowck/issue-101119.rs
@@ -0,0 +1,16 @@
+struct State;
+
+fn once(_: impl FnOnce()) {}
+
+fn fill_memory_blocks_mt(state: &mut State) {
+    loop {
+        once(move || {
+            //~^ ERROR use of moved value: `state`
+            fill_segment(state);
+        });
+    }
+}
+
+fn fill_segment(_: &mut State) {}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr
new file mode 100644
index 00000000000..a22afdc6764
--- /dev/null
+++ b/tests/ui/borrowck/issue-101119.stderr
@@ -0,0 +1,15 @@
+error[E0382]: use of moved value: `state`
+  --> $DIR/issue-101119.rs:7:14
+   |
+LL | fn fill_memory_blocks_mt(state: &mut State) {
+   |                          ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait
+LL |     loop {
+LL |         once(move || {
+   |              ^^^^^^^ value moved into closure here, in previous iteration of loop
+LL |
+LL |             fill_segment(state);
+   |                          ----- use occurs due to use in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/issue-102209.rs b/tests/ui/borrowck/issue-102209.rs
new file mode 100644
index 00000000000..37628bff7df
--- /dev/null
+++ b/tests/ui/borrowck/issue-102209.rs
@@ -0,0 +1,28 @@
+use std::marker::PhantomData;
+
+pub struct NfaBuilder<'brand> {
+    brand: PhantomData<&'brand mut &'brand mut ()>,
+}
+
+impl NfaBuilder<'_> {
+    pub fn with<R, F: FnOnce(NfaBuilder<'_>) -> R>(f: F) -> R {
+        Brand::with(|brand| {
+            f(Self { brand: brand.lt })
+            //~^ ERROR lifetime may not live long enough
+            //~| ERROR lifetime may not live long enough
+        })
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct Brand<'brand> {
+    lt: PhantomData<&'brand mut &'brand mut ()>,
+}
+
+impl Brand<'_> {
+    pub fn with<R, F: FnOnce(Brand<'_>) -> R>(f: F) -> R {
+        f(Self { lt: PhantomData })
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-102209.stderr b/tests/ui/borrowck/issue-102209.stderr
new file mode 100644
index 00000000000..351de8217b2
--- /dev/null
+++ b/tests/ui/borrowck/issue-102209.stderr
@@ -0,0 +1,22 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-102209.rs:10:29
+   |
+LL | impl NfaBuilder<'_> {
+   |                 -- lifetime `'2` appears in the `impl`'s self type
+LL |     pub fn with<R, F: FnOnce(NfaBuilder<'_>) -> R>(f: F) -> R {
+LL |         Brand::with(|brand| {
+   |                      ----- has type `Brand<'1>`
+LL |             f(Self { brand: brand.lt })
+   |                             ^^^^^^^^ this usage requires that `'1` must outlive `'2`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-102209.rs:10:29
+   |
+LL | impl NfaBuilder<'_> {
+   |                 -- lifetime `'1` appears in the `impl`'s self type
+...
+LL |             f(Self { brand: brand.lt })
+   |                             ^^^^^^^^ this usage requires that `'1` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/borrowck/issue-103095.rs b/tests/ui/borrowck/issue-103095.rs
new file mode 100644
index 00000000000..0340f39243f
--- /dev/null
+++ b/tests/ui/borrowck/issue-103095.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+trait FnOnceForGenericRef<T>: FnOnce(&T) -> Self::FnOutput {
+    type FnOutput;
+}
+
+impl<T, R, F: FnOnce(&T) -> R> FnOnceForGenericRef<T> for F {
+    type FnOutput = R;
+}
+
+struct Data<T, D: FnOnceForGenericRef<T>> {
+    value: Option<T>,
+    output: Option<D::FnOutput>,
+}
+
+impl<T, D: FnOnceForGenericRef<T>> Data<T, D> {
+    fn new(value: T, f: D) -> Self {
+        let output = f(&value);
+        Self {
+            value: Some(value),
+            output: Some(output),
+        }
+    }
+}
+
+fn test() {
+    Data::new(String::new(), |_| {});
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-103250.rs b/tests/ui/borrowck/issue-103250.rs
new file mode 100644
index 00000000000..46565f61ca9
--- /dev/null
+++ b/tests/ui/borrowck/issue-103250.rs
@@ -0,0 +1,37 @@
+// edition:2021
+
+type TranslateFn = Box<dyn Fn(String, String) -> String>;
+
+pub struct DeviceCluster {
+    devices: Vec<Device>,
+}
+
+impl DeviceCluster {
+    pub async fn do_something(&mut self) -> Result<String, Box<dyn std::error::Error>> {
+        let mut last_error: Box<dyn std::error::Error>;
+
+        for device in &mut self.devices {
+            match device.do_something().await {
+                Ok(info) => {
+                    return Ok(info);
+                }
+                Err(e) => {}
+            }
+        }
+
+        Err(last_error)
+        //~^ ERROR used binding `last_error` isn't initialized
+    }
+}
+
+pub struct Device {
+    translate_fn: Option<TranslateFn>,
+}
+
+impl Device {
+    pub async fn do_something(&mut self) -> Result<String, Box<dyn std::error::Error>> {
+        Ok(String::from(""))
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-103250.stderr b/tests/ui/borrowck/issue-103250.stderr
new file mode 100644
index 00000000000..4a237835222
--- /dev/null
+++ b/tests/ui/borrowck/issue-103250.stderr
@@ -0,0 +1,17 @@
+error[E0381]: used binding `last_error` isn't initialized
+  --> $DIR/issue-103250.rs:22:13
+   |
+LL |         let mut last_error: Box<dyn std::error::Error>;
+   |             -------------- binding declared here but left uninitialized
+...
+LL |         Err(last_error)
+   |             ^^^^^^^^^^ `last_error` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let mut last_error: Box<dyn std::error::Error> = todo!();
+   |                                                        +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/issue-103624.rs b/tests/ui/borrowck/issue-103624.rs
new file mode 100644
index 00000000000..f1fa95f9246
--- /dev/null
+++ b/tests/ui/borrowck/issue-103624.rs
@@ -0,0 +1,31 @@
+// edition:2021
+
+struct StructA {
+    b: StructB,
+}
+
+async fn spawn_blocking<T>(f: impl (Fn() -> T) + Send + Sync + 'static) -> T {
+    todo!()
+}
+
+impl StructA {
+    async fn foo(&self) {
+        let bar = self.b.bar().await;
+        spawn_blocking(move || {
+            //~^ ERROR borrowed data escapes outside of associated function
+            self.b;
+            //~^ ERROR cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure
+        })
+        .await;
+    }
+}
+
+struct StructB {}
+
+impl StructB {
+    async fn bar(&self) -> Option<u8> {
+        None
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr
new file mode 100644
index 00000000000..e6a35dd8801
--- /dev/null
+++ b/tests/ui/borrowck/issue-103624.stderr
@@ -0,0 +1,35 @@
+error[E0507]: cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure
+  --> $DIR/issue-103624.rs:16:13
+   |
+LL |     async fn foo(&self) {
+   |                  ----- captured outer variable
+LL |         let bar = self.b.bar().await;
+LL |         spawn_blocking(move || {
+   |                        ------- captured by this `Fn` closure
+LL |
+LL |             self.b;
+   |             ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
+
+error[E0521]: borrowed data escapes outside of associated function
+  --> $DIR/issue-103624.rs:14:9
+   |
+LL |       async fn foo(&self) {
+   |                    -----
+   |                    |
+   |                    `self` is a reference that is only valid in the associated function body
+   |                    let's call the lifetime of this reference `'1`
+LL |           let bar = self.b.bar().await;
+LL | /         spawn_blocking(move || {
+LL | |
+LL | |             self.b;
+LL | |
+LL | |         })
+   | |          ^
+   | |          |
+   | |__________`self` escapes the associated function body here
+   |            argument requires that `'1` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0507, E0521.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-104639-lifetime-order.rs b/tests/ui/borrowck/issue-104639-lifetime-order.rs
new file mode 100644
index 00000000000..db1f8f8d588
--- /dev/null
+++ b/tests/ui/borrowck/issue-104639-lifetime-order.rs
@@ -0,0 +1,10 @@
+// edition:2018
+// check-pass
+
+#![allow(dead_code)]
+async fn fail<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass<'a, 'c, 'b>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass2<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, 'c: 'a, {}
+async fn pass3<'a, 'b, 'c>(_: &'static str) where 'a: 'b, 'b: 'c, 'c: 'a, {}
+
+fn main() { }
diff --git a/tests/ui/borrowck/issue-10876.rs b/tests/ui/borrowck/issue-10876.rs
new file mode 100644
index 00000000000..22eaa119f24
--- /dev/null
+++ b/tests/ui/borrowck/issue-10876.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+enum Nat {
+    S(Box<Nat>),
+    Z
+}
+fn test(x: &mut Nat) {
+    let mut p = &mut *x;
+    loop {
+        match p {
+            &mut Nat::Z => break,
+            &mut Nat::S(ref mut n) => p = &mut *n
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-11493.fixed b/tests/ui/borrowck/issue-11493.fixed
new file mode 100644
index 00000000000..139bd9a0739
--- /dev/null
+++ b/tests/ui/borrowck/issue-11493.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let x = Some(3);
+    let binding = id(5);
+    let y = x.as_ref().unwrap_or(&binding);  //~ ERROR
+    let _ = &y;
+}
diff --git a/tests/ui/borrowck/issue-11493.rs b/tests/ui/borrowck/issue-11493.rs
new file mode 100644
index 00000000000..cb77f89fb2b
--- /dev/null
+++ b/tests/ui/borrowck/issue-11493.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let x = Some(3);
+    let y = x.as_ref().unwrap_or(&id(5));  //~ ERROR
+    let _ = &y;
+}
diff --git a/tests/ui/borrowck/issue-11493.stderr b/tests/ui/borrowck/issue-11493.stderr
new file mode 100644
index 00000000000..2720b09b0fc
--- /dev/null
+++ b/tests/ui/borrowck/issue-11493.stderr
@@ -0,0 +1,19 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-11493.rs:6:35
+   |
+LL |     let y = x.as_ref().unwrap_or(&id(5));
+   |                                   ^^^^^ - temporary value is freed at the end of this statement
+   |                                   |
+   |                                   creates a temporary value which is freed while still in use
+LL |     let _ = &y;
+   |             -- borrow later used here
+   |
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~     let binding = id(5);
+LL ~     let y = x.as_ref().unwrap_or(&binding);
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/borrowck/issue-17263.rs b/tests/ui/borrowck/issue-17263.rs
new file mode 100644
index 00000000000..4f560b065f1
--- /dev/null
+++ b/tests/ui/borrowck/issue-17263.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+struct Foo { a: isize, b: isize }
+
+fn main() {
+    let mut x: Box<_> = Box::new(Foo { a: 1, b: 2 });
+    let (a, b) = (&mut x.a, &mut x.b);
+
+    let mut foo: Box<_> = Box::new(Foo { a: 1, b: 2 });
+    let (c, d) = (&mut foo.a, &foo.b);
+
+    // We explicitly use the references created above to illustrate that the
+    // borrow checker is accepting this code *not* because of artificially
+    // short lifetimes, but rather because it understands that all the
+    // references are of disjoint parts of memory.
+    use_imm(d);
+    use_mut(c);
+    use_mut(b);
+    use_mut(a);
+}
+
+fn use_mut<T>(_: &mut T) { }
+fn use_imm<T>(_: &T) { }
diff --git a/tests/ui/borrowck/issue-17545.rs b/tests/ui/borrowck/issue-17545.rs
new file mode 100644
index 00000000000..ced6fff315f
--- /dev/null
+++ b/tests/ui/borrowck/issue-17545.rs
@@ -0,0 +1,10 @@
+#![feature(fn_traits)]
+
+fn id<T>(x: T) -> T { x }
+
+pub fn foo<'a, F: Fn(&'a ())>(bar: F) {
+    bar.call((
+        &id(()), //~ ERROR temporary value dropped while borrowed
+    ));
+}
+fn main() {}
diff --git a/tests/ui/borrowck/issue-17545.stderr b/tests/ui/borrowck/issue-17545.stderr
new file mode 100644
index 00000000000..3ae7e64d202
--- /dev/null
+++ b/tests/ui/borrowck/issue-17545.stderr
@@ -0,0 +1,16 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-17545.rs:7:10
+   |
+LL |   pub fn foo<'a, F: Fn(&'a ())>(bar: F) {
+   |              -- lifetime `'a` defined here
+LL | /     bar.call((
+LL | |         &id(()),
+   | |          ^^^^^^ creates a temporary value which is freed while still in use
+LL | |     ));
+   | |      -- temporary value is freed at the end of this statement
+   | |______|
+   |        argument requires that borrow lasts for `'a`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/borrowck/issue-17718-static-move.rs b/tests/ui/borrowck/issue-17718-static-move.rs
new file mode 100644
index 00000000000..015487a06aa
--- /dev/null
+++ b/tests/ui/borrowck/issue-17718-static-move.rs
@@ -0,0 +1,7 @@
+struct Foo;
+const INIT: Foo = Foo;
+static FOO: Foo = INIT;
+
+fn main() {
+    let _a = FOO; //~ ERROR: cannot move out of static item
+}
diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr
new file mode 100644
index 00000000000..65aea5b1834
--- /dev/null
+++ b/tests/ui/borrowck/issue-17718-static-move.stderr
@@ -0,0 +1,14 @@
+error[E0507]: cannot move out of static item `FOO`
+  --> $DIR/issue-17718-static-move.rs:6:14
+   |
+LL |     let _a = FOO;
+   |              ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |     let _a = &FOO;
+   |              +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs
new file mode 100644
index 00000000000..c3f136f2876
--- /dev/null
+++ b/tests/ui/borrowck/issue-20801.rs
@@ -0,0 +1,37 @@
+// We used to ICE when moving out of a `*mut T` or `*const T`.
+
+struct T(u8);
+
+static mut GLOBAL_MUT_T: T = T(0);
+
+static GLOBAL_T: T = T(0);
+
+fn imm_ref() -> &'static T {
+    unsafe { &GLOBAL_T }
+}
+
+fn mut_ref() -> &'static mut T {
+    unsafe { &mut GLOBAL_MUT_T }
+}
+
+fn mut_ptr() -> *mut T {
+    unsafe { core::ptr::null_mut() }
+}
+
+fn const_ptr() -> *const T {
+    unsafe { core::ptr::null() }
+}
+
+pub fn main() {
+    let a = unsafe { *mut_ref() };
+    //~^ ERROR cannot move out of a mutable reference
+
+    let b = unsafe { *imm_ref() };
+    //~^ ERROR cannot move out of a shared reference
+
+    let c = unsafe { *mut_ptr() };
+    //~^ ERROR cannot move out of a raw pointer
+
+    let d = unsafe { *const_ptr() };
+    //~^ ERROR cannot move out of a raw pointer
+}
diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr
new file mode 100644
index 00000000000..215bf010063
--- /dev/null
+++ b/tests/ui/borrowck/issue-20801.stderr
@@ -0,0 +1,51 @@
+error[E0507]: cannot move out of a mutable reference
+  --> $DIR/issue-20801.rs:26:22
+   |
+LL |     let a = unsafe { *mut_ref() };
+   |                      ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -     let a = unsafe { *mut_ref() };
+LL +     let a = unsafe { mut_ref() };
+   |
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/issue-20801.rs:29:22
+   |
+LL |     let b = unsafe { *imm_ref() };
+   |                      ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -     let b = unsafe { *imm_ref() };
+LL +     let b = unsafe { imm_ref() };
+   |
+
+error[E0507]: cannot move out of a raw pointer
+  --> $DIR/issue-20801.rs:32:22
+   |
+LL |     let c = unsafe { *mut_ptr() };
+   |                      ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -     let c = unsafe { *mut_ptr() };
+LL +     let c = unsafe { mut_ptr() };
+   |
+
+error[E0507]: cannot move out of a raw pointer
+  --> $DIR/issue-20801.rs:35:22
+   |
+LL |     let d = unsafe { *const_ptr() };
+   |                      ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -     let d = unsafe { *const_ptr() };
+LL +     let d = unsafe { const_ptr() };
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs b/tests/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs
new file mode 100644
index 00000000000..d45aaa843fb
--- /dev/null
+++ b/tests/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs
@@ -0,0 +1,30 @@
+// run-pass
+// This is largely checking that we now accept code where temp values
+// are borrowing from the input parameters (the `foo` case below).
+//
+// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs
+//
+// (The `foo2` case is just for parity with the above test, which
+//  shows what happens when you move the `y`-binding to the inside of
+//  the inner block.)
+
+use std::cell::RefCell;
+
+fn foo(x: RefCell<String>) -> String {
+    x.borrow().clone()
+}
+
+fn foo2(x: RefCell<String>) -> String {
+    let y = x;
+    let ret = {
+        y.borrow().clone()
+    };
+    ret
+}
+
+pub fn main() {
+    let r = RefCell::new(format!("data"));
+    assert_eq!(foo(r), "data");
+    let r = RefCell::new(format!("data"));
+    assert_eq!(foo2(r), "data");
+}
diff --git a/tests/ui/borrowck/issue-24267-flow-exit.rs b/tests/ui/borrowck/issue-24267-flow-exit.rs
new file mode 100644
index 00000000000..c419c5840d9
--- /dev/null
+++ b/tests/ui/borrowck/issue-24267-flow-exit.rs
@@ -0,0 +1,19 @@
+// Ensure that we reject code when a nonlocal exit (`break`,
+// `continue`) causes us to pop over a needed assignment.
+
+pub fn main() {
+    foo1();
+    foo2();
+}
+
+pub fn foo1() {
+    let x: i32;
+    loop { x = break; }
+    println!("{}", x); //~ ERROR E0381
+}
+
+pub fn foo2() {
+    let x: i32;
+    for _ in 0..10 { x = continue; }
+    println!("{}", x); //~ ERROR E0381
+}
diff --git a/tests/ui/borrowck/issue-24267-flow-exit.stderr b/tests/ui/borrowck/issue-24267-flow-exit.stderr
new file mode 100644
index 00000000000..58d1c8c0f73
--- /dev/null
+++ b/tests/ui/borrowck/issue-24267-flow-exit.stderr
@@ -0,0 +1,33 @@
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/issue-24267-flow-exit.rs:12:20
+   |
+LL |     let x: i32;
+   |         - binding declared here but left uninitialized
+LL |     loop { x = break; }
+LL |     println!("{}", x);
+   |                    ^ `x` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/issue-24267-flow-exit.rs:18:20
+   |
+LL |     let x: i32;
+   |         - binding declared here but left uninitialized
+LL |     for _ in 0..10 { x = continue; }
+LL |     println!("{}", x);
+   |                    ^ `x` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/issue-25793.rs b/tests/ui/borrowck/issue-25793.rs
new file mode 100644
index 00000000000..6c8dacc2248
--- /dev/null
+++ b/tests/ui/borrowck/issue-25793.rs
@@ -0,0 +1,26 @@
+#![feature(rustc_attrs)]
+macro_rules! width(
+    ($this:expr) => {
+        $this.width.unwrap()
+        //~^ ERROR cannot use `self.width` because it was mutably borrowed
+    }
+);
+
+struct HasInfo {
+    width: Option<usize>
+}
+
+impl HasInfo {
+    fn get_size(&mut self, n: usize) -> usize {
+        n
+    }
+
+    fn get_other(&mut self) -> usize {
+        let r = &mut *self;
+        r.get_size(width!(self))
+    }
+    // Above is like `self.get_size(width!(self))`, but it
+    // deliberately avoids NLL's two phase borrow feature.
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/issue-25793.stderr b/tests/ui/borrowck/issue-25793.stderr
new file mode 100644
index 00000000000..da3412f112d
--- /dev/null
+++ b/tests/ui/borrowck/issue-25793.stderr
@@ -0,0 +1,18 @@
+error[E0503]: cannot use `self.width` because it was mutably borrowed
+  --> $DIR/issue-25793.rs:4:9
+   |
+LL |         $this.width.unwrap()
+   |         ^^^^^^^^^^^ use of borrowed `*self`
+...
+LL |         let r = &mut *self;
+   |                 ---------- borrow of `*self` occurs here
+LL |         r.get_size(width!(self))
+   |           -------- ------------ in this macro invocation
+   |           |
+   |           borrow later used by call
+   |
+   = note: this error originates in the macro `width` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0503`.
diff --git a/tests/ui/borrowck/issue-28934.rs b/tests/ui/borrowck/issue-28934.rs
new file mode 100644
index 00000000000..1e48878f632
--- /dev/null
+++ b/tests/ui/borrowck/issue-28934.rs
@@ -0,0 +1,25 @@
+// Regression test: issue had to do with "givens" in region inference,
+// which were not being considered during the contraction phase.
+
+// run-fail
+// error-pattern:explicit panic
+// ignore-emscripten no processes
+
+struct Parser<'i: 't, 't>(&'i u8, &'t u8);
+
+impl<'i, 't> Parser<'i, 't> {
+    fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()>
+        where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T
+    {
+        panic!()
+    }
+
+    fn expect_exhausted(&mut self) -> Result<(), ()> {
+        Ok(())
+    }
+}
+
+fn main() {
+    let x = 0u8;
+    Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap();
+}
diff --git a/tests/ui/borrowck/issue-29166.rs b/tests/ui/borrowck/issue-29166.rs
new file mode 100644
index 00000000000..ca819ba39a2
--- /dev/null
+++ b/tests/ui/borrowck/issue-29166.rs
@@ -0,0 +1,21 @@
+// run-pass
+// This test ensures that vec.into_iter does not overconstrain element lifetime.
+
+pub fn main() {
+    original_report();
+    revision_1();
+    revision_2();
+}
+
+fn original_report() {
+    drop(vec![&()].into_iter())
+}
+
+fn revision_1() {
+    // below is what above `vec!` expands into at time of this writing.
+    drop(<[_]>::into_vec(::std::boxed::Box::new([&()])).into_iter())
+}
+
+fn revision_2() {
+    drop((match (Vec::new(), &()) { (mut v, b) => { v.push(b); v } }).into_iter())
+}
diff --git a/tests/ui/borrowck/issue-31287-drop-in-guard.rs b/tests/ui/borrowck/issue-31287-drop-in-guard.rs
new file mode 100644
index 00000000000..5b824adc6e2
--- /dev/null
+++ b/tests/ui/borrowck/issue-31287-drop-in-guard.rs
@@ -0,0 +1,15 @@
+#![feature(if_let_guard)]
+
+fn main() {
+    let a = Some("...".to_owned());
+    let b = match a {
+        Some(_) if { drop(a); false } => None,
+        x => x, //~ ERROR use of moved value: `a`
+    };
+
+    let a = Some("...".to_owned());
+    let b = match a {
+        Some(_) if let Some(()) = { drop(a); None } => None,
+        x => x, //~ ERROR use of moved value: `a`
+    };
+}
diff --git a/tests/ui/borrowck/issue-31287-drop-in-guard.stderr b/tests/ui/borrowck/issue-31287-drop-in-guard.stderr
new file mode 100644
index 00000000000..18f371c2073
--- /dev/null
+++ b/tests/ui/borrowck/issue-31287-drop-in-guard.stderr
@@ -0,0 +1,35 @@
+error[E0382]: use of moved value: `a`
+  --> $DIR/issue-31287-drop-in-guard.rs:7:9
+   |
+LL |     let a = Some("...".to_owned());
+   |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL |     let b = match a {
+LL |         Some(_) if { drop(a); false } => None,
+   |                           - value moved here
+LL |         x => x,
+   |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if { drop(a.clone()); false } => None,
+   |                            ++++++++
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/issue-31287-drop-in-guard.rs:13:9
+   |
+LL |     let a = Some("...".to_owned());
+   |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL |     let b = match a {
+LL |         Some(_) if let Some(()) = { drop(a); None } => None,
+   |                                          - value moved here
+LL |         x => x,
+   |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(a.clone()); None } => None,
+   |                                           ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/issue-33819.rs b/tests/ui/borrowck/issue-33819.rs
new file mode 100644
index 00000000000..fff5015cdc1
--- /dev/null
+++ b/tests/ui/borrowck/issue-33819.rs
@@ -0,0 +1,9 @@
+fn main() {
+    let mut op = Some(2);
+    match op {
+        Some(ref v) => { let a = &mut v; },
+        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+        //~| HELP try removing `&mut` here
+        None => {},
+    }
+}
diff --git a/tests/ui/borrowck/issue-33819.stderr b/tests/ui/borrowck/issue-33819.stderr
new file mode 100644
index 00000000000..f77fdbf2b6b
--- /dev/null
+++ b/tests/ui/borrowck/issue-33819.stderr
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/issue-33819.rs:4:34
+   |
+LL |         Some(ref v) => { let a = &mut v; },
+   |                                  ^^^^^^
+   |                                  |
+   |                                  cannot borrow as mutable
+   |                                  help: try removing `&mut` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-36082.fixed b/tests/ui/borrowck/issue-36082.fixed
new file mode 100644
index 00000000000..8fc963a8566
--- /dev/null
+++ b/tests/ui/borrowck/issue-36082.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+use std::cell::RefCell;
+
+fn main() {
+    let mut r = 0;
+    let s = 0;
+    let x = RefCell::new((&mut r,s));
+
+    let binding = x.borrow();
+    let val: &_ = binding.0;
+    //~^ ERROR temporary value dropped while borrowed [E0716]
+    //~| NOTE temporary value is freed at the end of this statement
+    //~| NOTE creates a temporary value which is freed while still in use
+    //~| HELP consider using a `let` binding to create a longer lived value
+    println!("{}", val);
+    //~^ borrow later used here
+}
diff --git a/tests/ui/borrowck/issue-36082.rs b/tests/ui/borrowck/issue-36082.rs
new file mode 100644
index 00000000000..20f66b4d45d
--- /dev/null
+++ b/tests/ui/borrowck/issue-36082.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+use std::cell::RefCell;
+
+fn main() {
+    let mut r = 0;
+    let s = 0;
+    let x = RefCell::new((&mut r,s));
+
+    let val: &_ = x.borrow().0;
+    //~^ ERROR temporary value dropped while borrowed [E0716]
+    //~| NOTE temporary value is freed at the end of this statement
+    //~| NOTE creates a temporary value which is freed while still in use
+    //~| HELP consider using a `let` binding to create a longer lived value
+    println!("{}", val);
+    //~^ borrow later used here
+}
diff --git a/tests/ui/borrowck/issue-36082.stderr b/tests/ui/borrowck/issue-36082.stderr
new file mode 100644
index 00000000000..a6357f8182f
--- /dev/null
+++ b/tests/ui/borrowck/issue-36082.stderr
@@ -0,0 +1,20 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-36082.rs:9:19
+   |
+LL |     let val: &_ = x.borrow().0;
+   |                   ^^^^^^^^^^  - temporary value is freed at the end of this statement
+   |                   |
+   |                   creates a temporary value which is freed while still in use
+...
+LL |     println!("{}", val);
+   |                    --- borrow later used here
+   |
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~     let binding = x.borrow();
+LL ~     let val: &_ = binding.0;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/borrowck/issue-41962.rs b/tests/ui/borrowck/issue-41962.rs
new file mode 100644
index 00000000000..38a01b138e4
--- /dev/null
+++ b/tests/ui/borrowck/issue-41962.rs
@@ -0,0 +1,9 @@
+pub fn main(){
+    let maybe = Some(vec![true, true]);
+
+    loop {
+        if let Some(thing) = maybe {
+        }
+        //~^^ ERROR use of moved value [E0382]
+    }
+}
diff --git a/tests/ui/borrowck/issue-41962.stderr b/tests/ui/borrowck/issue-41962.stderr
new file mode 100644
index 00000000000..716cc9d0c8b
--- /dev/null
+++ b/tests/ui/borrowck/issue-41962.stderr
@@ -0,0 +1,15 @@
+error[E0382]: use of moved value
+  --> $DIR/issue-41962.rs:5:21
+   |
+LL |         if let Some(thing) = maybe {
+   |                     ^^^^^ value moved here, in previous iteration of loop
+   |
+   = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         if let Some(ref thing) = maybe {
+   |                     +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/issue-42344.rs b/tests/ui/borrowck/issue-42344.rs
new file mode 100644
index 00000000000..a7636edf2f8
--- /dev/null
+++ b/tests/ui/borrowck/issue-42344.rs
@@ -0,0 +1,8 @@
+static TAB: [&mut [u8]; 0] = [];
+
+pub unsafe fn test() {
+    TAB[0].iter_mut();
+    //~^ ERROR cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable static item [E0596]
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/issue-42344.stderr b/tests/ui/borrowck/issue-42344.stderr
new file mode 100644
index 00000000000..29b4c8c38d7
--- /dev/null
+++ b/tests/ui/borrowck/issue-42344.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable static item
+  --> $DIR/issue-42344.rs:4:5
+   |
+LL |     TAB[0].iter_mut();
+   |     ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs
new file mode 100644
index 00000000000..ded46e56e34
--- /dev/null
+++ b/tests/ui/borrowck/issue-45199.rs
@@ -0,0 +1,24 @@
+fn test_drop_replace() {
+    let b: Box<isize>;
+    //~^ HELP consider making this binding mutable
+    //~| SUGGESTION mut b
+    b = Box::new(1);    //~ NOTE first assignment
+    b = Box::new(2);    //~ ERROR cannot assign twice to immutable variable `b`
+                        //~| NOTE cannot assign twice to immutable
+}
+
+fn test_call() {
+    let b = Box::new(1);    //~ NOTE first assignment
+                            //~| HELP consider making this binding mutable
+                            //~| SUGGESTION mut b
+    b = Box::new(2);        //~ ERROR cannot assign twice to immutable variable `b`
+                            //~| NOTE cannot assign twice to immutable
+}
+
+fn test_args(b: Box<i32>) {  //~ HELP consider making this binding mutable
+                                //~| SUGGESTION mut b
+    b = Box::new(2);            //~ ERROR cannot assign to immutable argument `b`
+                                //~| NOTE cannot assign to immutable argument
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr
new file mode 100644
index 00000000000..47aa3090827
--- /dev/null
+++ b/tests/ui/borrowck/issue-45199.stderr
@@ -0,0 +1,35 @@
+error[E0384]: cannot assign twice to immutable variable `b`
+  --> $DIR/issue-45199.rs:6:5
+   |
+LL |     let b: Box<isize>;
+   |         - help: consider making this binding mutable: `mut b`
+...
+LL |     b = Box::new(1);
+   |     - first assignment to `b`
+LL |     b = Box::new(2);
+   |     ^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `b`
+  --> $DIR/issue-45199.rs:14:5
+   |
+LL |     let b = Box::new(1);
+   |         -
+   |         |
+   |         first assignment to `b`
+   |         help: consider making this binding mutable: `mut b`
+...
+LL |     b = Box::new(2);
+   |     ^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign to immutable argument `b`
+  --> $DIR/issue-45199.rs:20:5
+   |
+LL | fn test_args(b: Box<i32>) {
+   |              - help: consider making this binding mutable: `mut b`
+LL |
+LL |     b = Box::new(2);
+   |     ^ cannot assign to immutable argument
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0384`.
diff --git a/tests/ui/borrowck/issue-45983.rs b/tests/ui/borrowck/issue-45983.rs
new file mode 100644
index 00000000000..6784f6f86a0
--- /dev/null
+++ b/tests/ui/borrowck/issue-45983.rs
@@ -0,0 +1,12 @@
+// As documented in Issue #45983, this test is evaluating the quality
+// of our diagnostics on erroneous code using higher-ranked closures.
+
+fn give_any<F: for<'r> FnOnce(&'r ())>(f: F) {
+    f(&());
+}
+
+fn main() {
+    let mut x = None;
+    give_any(|y| x = Some(y));
+    //~^ ERROR borrowed data escapes outside of closure
+}
diff --git a/tests/ui/borrowck/issue-45983.stderr b/tests/ui/borrowck/issue-45983.stderr
new file mode 100644
index 00000000000..feb098c5985
--- /dev/null
+++ b/tests/ui/borrowck/issue-45983.stderr
@@ -0,0 +1,13 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/issue-45983.rs:10:18
+   |
+LL |     let mut x = None;
+   |         ----- `x` declared here, outside of the closure body
+LL |     give_any(|y| x = Some(y));
+   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |               |
+   |               `y` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/borrowck/issue-46095.rs b/tests/ui/borrowck/issue-46095.rs
new file mode 100644
index 00000000000..59ddb60c9f2
--- /dev/null
+++ b/tests/ui/borrowck/issue-46095.rs
@@ -0,0 +1,30 @@
+// run-pass
+struct A;
+
+impl A {
+    fn take_mutably(&mut self) {}
+}
+
+fn identity<T>(t: T) -> T {
+    t
+}
+
+// Issue 46095
+// Built-in indexing should be used even when the index is not
+// trivially an integer
+// Overloaded indexing would cause wrapped to be borrowed mutably
+
+fn main() {
+    let mut a1 = A;
+    let mut a2 = A;
+
+    let wrapped = [&mut a1, &mut a2];
+
+    {
+        wrapped[0 + 1 - 1].take_mutably();
+    }
+
+    {
+        wrapped[identity(0)].take_mutably();
+    }
+}
diff --git a/tests/ui/borrowck/issue-46471.rs b/tests/ui/borrowck/issue-46471.rs
new file mode 100644
index 00000000000..8922005d2f8
--- /dev/null
+++ b/tests/ui/borrowck/issue-46471.rs
@@ -0,0 +1,7 @@
+fn foo() -> &'static u32 {
+    let x = 0;
+    &x
+    //~^ ERROR cannot return reference to local variable `x` [E0515]
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/issue-46471.stderr b/tests/ui/borrowck/issue-46471.stderr
new file mode 100644
index 00000000000..935414c1f3f
--- /dev/null
+++ b/tests/ui/borrowck/issue-46471.stderr
@@ -0,0 +1,9 @@
+error[E0515]: cannot return reference to local variable `x`
+  --> $DIR/issue-46471.rs:3:5
+   |
+LL |     &x
+   |     ^^ returns a reference to data owned by the current function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/issue-47215-ice-from-drop-elab.rs b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.rs
new file mode 100644
index 00000000000..e95a6b7c88b
--- /dev/null
+++ b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.rs
@@ -0,0 +1,20 @@
+// rust-lang/rust#47215: at one time, the compiler categorized
+// thread-local statics as a temporary rvalue, as a way to enforce
+// that they are only valid for a given lifetime.
+//
+// The problem with this is that you cannot move out of static items,
+// but you *can* move temporary rvalues. I.e., the categorization
+// above only solves half of the problem presented by thread-local
+// statics.
+
+#![feature(thread_local)]
+
+#[thread_local]
+static mut X: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0);
+
+fn main() {
+    unsafe {
+        let mut x = X; //~ ERROR cannot move out of static item `X` [E0507]
+        let _y = x.get_mut();
+    }
+}
diff --git a/tests/ui/borrowck/issue-47215-ice-from-drop-elab.stderr b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.stderr
new file mode 100644
index 00000000000..8d4918867f7
--- /dev/null
+++ b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.stderr
@@ -0,0 +1,14 @@
+error[E0507]: cannot move out of static item `X`
+  --> $DIR/issue-47215-ice-from-drop-elab.rs:17:21
+   |
+LL |         let mut x = X;
+   |                     ^ move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |         let mut x = &X;
+   |                     +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-51117.rs b/tests/ui/borrowck/issue-51117.rs
new file mode 100644
index 00000000000..e4664e4f3ea
--- /dev/null
+++ b/tests/ui/borrowck/issue-51117.rs
@@ -0,0 +1,15 @@
+// Regression test for #51117 in borrowck interaction with match
+// default bindings. The borrow of `*bar` created by `baz` was failing
+// to register as a conflict with `bar.take()`.
+
+fn main() {
+    let mut foo = Some("foo".to_string());
+    let bar = &mut foo;
+    match bar {
+        Some(baz) => {
+            bar.take(); //~ ERROR cannot borrow
+            drop(baz);
+        },
+        None => unreachable!(),
+    }
+}
diff --git a/tests/ui/borrowck/issue-51117.stderr b/tests/ui/borrowck/issue-51117.stderr
new file mode 100644
index 00000000000..ef1a16ea953
--- /dev/null
+++ b/tests/ui/borrowck/issue-51117.stderr
@@ -0,0 +1,13 @@
+error[E0499]: cannot borrow `*bar` as mutable more than once at a time
+  --> $DIR/issue-51117.rs:10:13
+   |
+LL |         Some(baz) => {
+   |              --- first mutable borrow occurs here
+LL |             bar.take();
+   |             ^^^^^^^^^^ second mutable borrow occurs here
+LL |             drop(baz);
+   |                  --- first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/issue-51301.rs b/tests/ui/borrowck/issue-51301.rs
new file mode 100644
index 00000000000..7e0a5190fcd
--- /dev/null
+++ b/tests/ui/borrowck/issue-51301.rs
@@ -0,0 +1,35 @@
+use std::any::TypeId;
+use std::collections::HashMap;
+use std::hash::Hash;
+
+trait State {
+    type EventType;
+    fn get_type_id_of_state(&self) -> TypeId;
+}
+
+struct StateMachine<EventType: Hash + Eq> {
+    current_state: Box<dyn State<EventType = EventType>>,
+    transition_table:
+        HashMap<TypeId, HashMap<EventType, fn() -> Box<dyn State<EventType = EventType>>>>,
+}
+
+impl<EventType: Hash + Eq> StateMachine<EventType> {
+    fn inner_process_event(&mut self, event: EventType) -> Result<(), i8> {
+        let new_state_creation_function = self
+            .transition_table
+            .iter()
+            .find(|(&event_typeid, _)| event_typeid == self.current_state.get_type_id_of_state())
+            .ok_or(1)?
+            .1
+            .iter()
+            .find(|(&event_type, _)| event == event_type)
+            //~^ ERROR cannot move out of a shared reference
+            .ok_or(2)?
+            .1;
+
+        self.current_state = new_state_creation_function();
+        Ok(())
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-51301.stderr b/tests/ui/borrowck/issue-51301.stderr
new file mode 100644
index 00000000000..6ec920cb81f
--- /dev/null
+++ b/tests/ui/borrowck/issue-51301.stderr
@@ -0,0 +1,17 @@
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/issue-51301.rs:25:20
+   |
+LL |             .find(|(&event_type, _)| event == event_type)
+   |                    ^^----------^^^^
+   |                      |
+   |                      data moved here
+   |                      move occurs because `event_type` has type `EventType`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |             .find(|(&ref event_type, _)| event == event_type)
+   |                      +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs b/tests/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs
new file mode 100644
index 00000000000..7d5acb95751
--- /dev/null
+++ b/tests/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs
@@ -0,0 +1,21 @@
+// We used to ICE if you had a single match arm with multiple
+// candidate patterns with `ref mut` identifiers used in the arm's
+// guard.
+//
+// Also, this test expands on the original bug's example by actually
+// trying to double check that we are matching against the right part
+// of the input data based on which candidate pattern actually fired.
+
+// run-pass
+
+fn foo(x: &mut Result<(u32, u32), (u32, u32)>) -> u32 {
+    match *x {
+        Ok((ref mut v, _)) | Err((_, ref mut v)) if *v > 0 => { *v }
+        _ => { 0 }
+    }
+}
+
+fn main() {
+    assert_eq!(foo(&mut Ok((3, 4))), 3);
+    assert_eq!(foo(&mut Err((3, 4))), 4);
+}
diff --git a/tests/ui/borrowck/issue-51415.fixed b/tests/ui/borrowck/issue-51415.fixed
new file mode 100644
index 00000000000..92943f6c9ec
--- /dev/null
+++ b/tests/ui/borrowck/issue-51415.fixed
@@ -0,0 +1,12 @@
+// run-rustfix
+// Regression test for #51415: match default bindings were failing to
+// see the "move out" implied by `&s` below.
+
+fn main() {
+    let a = vec![String::from("a")];
+    let opt = a.iter().enumerate().find(|(_, &ref s)| {
+        //~^ ERROR cannot move out
+        *s == String::from("d")
+    }).map(|(i, _)| i);
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/borrowck/issue-51415.rs b/tests/ui/borrowck/issue-51415.rs
new file mode 100644
index 00000000000..56ed57a61a0
--- /dev/null
+++ b/tests/ui/borrowck/issue-51415.rs
@@ -0,0 +1,12 @@
+// run-rustfix
+// Regression test for #51415: match default bindings were failing to
+// see the "move out" implied by `&s` below.
+
+fn main() {
+    let a = vec![String::from("a")];
+    let opt = a.iter().enumerate().find(|(_, &s)| {
+        //~^ ERROR cannot move out
+        *s == String::from("d")
+    }).map(|(i, _)| i);
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/borrowck/issue-51415.stderr b/tests/ui/borrowck/issue-51415.stderr
new file mode 100644
index 00000000000..0d486b45592
--- /dev/null
+++ b/tests/ui/borrowck/issue-51415.stderr
@@ -0,0 +1,17 @@
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/issue-51415.rs:7:42
+   |
+LL |     let opt = a.iter().enumerate().find(|(_, &s)| {
+   |                                          ^^^^^-^
+   |                                               |
+   |                                               data moved here
+   |                                               move occurs because `s` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |     let opt = a.iter().enumerate().find(|(_, &ref s)| {
+   |                                               +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-52713-bug.rs b/tests/ui/borrowck/issue-52713-bug.rs
new file mode 100644
index 00000000000..671e83dfadc
--- /dev/null
+++ b/tests/ui/borrowck/issue-52713-bug.rs
@@ -0,0 +1,17 @@
+// Regression test for a bug in #52713: this was an optimization for
+// computing liveness that wound up accidentally causing the program
+// below to be accepted.
+
+fn foo<'a>(x: &'a mut u32) -> u32 {
+    let mut x = 22;
+    let y = &x;
+    if false {
+        return x;
+    }
+
+    x += 1; //~ ERROR
+    println!("{}", y);
+    return 0;
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/issue-52713-bug.stderr b/tests/ui/borrowck/issue-52713-bug.stderr
new file mode 100644
index 00000000000..4abb6fb2c71
--- /dev/null
+++ b/tests/ui/borrowck/issue-52713-bug.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/issue-52713-bug.rs:12:5
+   |
+LL |     let y = &x;
+   |             -- borrow of `x` occurs here
+...
+LL |     x += 1;
+   |     ^^^^^^ assignment to borrowed `x` occurs here
+LL |     println!("{}", y);
+   |                    - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs b/tests/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs
new file mode 100644
index 00000000000..fc8a075540b
--- /dev/null
+++ b/tests/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs
@@ -0,0 +1,21 @@
+// This is a regression test for #52967, where we discovered that in
+// the initial deployment of NLL for the 2018 edition, I forgot to
+// turn on two-phase-borrows in addition to `-Z borrowck=migrate`.
+
+// revisions: edition2015 edition2018
+//[edition2018]edition:2018
+
+// run-pass
+
+fn the_bug() {
+    let mut stuff = ("left", "right");
+    match stuff {
+        (ref mut left, _) if *left == "left" => { *left = "new left"; }
+        _ => {}
+    }
+    assert_eq!(stuff, ("new left", "right"));
+}
+
+fn main() {
+    the_bug();
+}
diff --git a/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs
new file mode 100644
index 00000000000..f1fd1b507c7
--- /dev/null
+++ b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let f = move || {};
+    let _action = move || {
+        || f() // The `nested` closure
+        //~^ ERROR lifetime may not live long enough
+    };
+}
diff --git a/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
new file mode 100644
index 00000000000..f0b57484632
--- /dev/null
+++ b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
@@ -0,0 +1,19 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9
+   |
+LL |     let _action = move || {
+   |                   -------
+   |                   |     |
+   |                   |     return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:11]` contains a lifetime `'2`
+   |                   lifetime `'1` represents this closure's body
+LL |         || f() // The `nested` closure
+   |         ^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |
+   = note: closure implements `Fn`, so references to captured variables can't escape the closure
+help: consider adding 'move' keyword before the nested closure
+   |
+LL |         move || f() // The `nested` closure
+   |         ++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs
new file mode 100644
index 00000000000..205ea10c90b
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs
@@ -0,0 +1,33 @@
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let mut t: Tuple;
+        t.0 = S(1);
+        //~^ ERROR E0381
+        t.1 = 2;
+        println!("{:?} {:?}", t.0, t.1);
+    }
+
+    {
+        let mut u: Tpair;
+        u.0 = S(1);
+        //~^ ERROR E0381
+        u.1 = 2;
+        println!("{:?} {:?}", u.0, u.1);
+    }
+
+    {
+        let mut v: Spair;
+        v.x = S(1);
+        //~^ ERROR E0381
+        v.y = 2;
+        println!("{:?} {:?}", v.x, v.y);
+    }
+}
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr
new file mode 100644
index 00000000000..2a0eba396f1
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr
@@ -0,0 +1,33 @@
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:12:9
+   |
+LL |         let mut t: Tuple;
+   |             ----- binding declared here but left uninitialized
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `u` isn't fully initialized
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:20:9
+   |
+LL |         let mut u: Tpair;
+   |             ----- binding declared here but left uninitialized
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ `u` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `v` isn't fully initialized
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:28:9
+   |
+LL |         let mut v: Spair;
+   |             ----- binding declared here but left uninitialized
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ `v` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs
new file mode 100644
index 00000000000..f7fb2fd4da9
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs
@@ -0,0 +1,36 @@
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let mut t: Tuple = (S(0), 0);
+        drop(t);
+        t.0 = S(1);
+        //~^ ERROR assign to part of moved value
+        t.1 = 2;
+        println!("{:?} {:?}", t.0, t.1);
+    }
+
+    {
+        let mut u: Tpair = Tpair(S(0), 0);
+        drop(u);
+        u.0 = S(1);
+        //~^ ERROR assign to part of moved value
+        u.1 = 2;
+        println!("{:?} {:?}", u.0, u.1);
+    }
+
+    {
+        let mut v: Spair = Spair { x: S(0), y: 0 };
+        drop(v);
+        v.x = S(1);
+        //~^ ERROR assign to part of moved value
+        v.y = 2;
+        println!("{:?} {:?}", v.x, v.y);
+    }
+}
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr
new file mode 100644
index 00000000000..b188766e221
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr
@@ -0,0 +1,33 @@
+error[E0382]: assign to part of moved value: `t`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:13:9
+   |
+LL |         let mut t: Tuple = (S(0), 0);
+   |             ----- move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+LL |         drop(t);
+   |              - value moved here
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+
+error[E0382]: assign to part of moved value: `u`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:22:9
+   |
+LL |         let mut u: Tpair = Tpair(S(0), 0);
+   |             ----- move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+LL |         drop(u);
+   |              - value moved here
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+
+error[E0382]: assign to part of moved value: `v`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:31:9
+   |
+LL |         let mut v: Spair = Spair { x: S(0), y: 0 };
+   |             ----- move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+LL |         drop(v);
+   |              - value moved here
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs
new file mode 100644
index 00000000000..498ca01e972
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs
@@ -0,0 +1,42 @@
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let t: Tuple = (S(0), 0);
+        drop(t);
+        t.0 = S(1);
+        //~^ ERROR assign to part of moved value: `t` [E0382]
+        //~| ERROR cannot assign to `t.0`, as `t` is not declared as mutable [E0594]
+        t.1 = 2;
+        //~^ ERROR cannot assign to `t.1`, as `t` is not declared as mutable [E0594]
+        println!("{:?} {:?}", t.0, t.1);
+    }
+
+    {
+        let u: Tpair = Tpair(S(0), 0);
+        drop(u);
+        u.0 = S(1);
+        //~^ ERROR assign to part of moved value: `u` [E0382]
+        //~| ERROR cannot assign to `u.0`, as `u` is not declared as mutable [E0594]
+        u.1 = 2;
+        //~^ ERROR cannot assign to `u.1`, as `u` is not declared as mutable [E0594]
+        println!("{:?} {:?}", u.0, u.1);
+    }
+
+    {
+        let v: Spair = Spair { x: S(0), y: 0 };
+        drop(v);
+        v.x = S(1);
+        //~^ ERROR assign to part of moved value: `v` [E0382]
+        //~| ERROR cannot assign to `v.x`, as `v` is not declared as mutable [E0594]
+        v.y = 2;
+        //~^ ERROR cannot assign to `v.y`, as `v` is not declared as mutable [E0594]
+        println!("{:?} {:?}", v.x, v.y);
+    }
+}
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
new file mode 100644
index 00000000000..774b6cf0ea6
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
@@ -0,0 +1,100 @@
+error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
+   |
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut t: Tuple = (S(0), 0);
+   |             +++
+
+error[E0382]: assign to part of moved value: `t`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
+   |
+LL |         let t: Tuple = (S(0), 0);
+   |             - move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+LL |         drop(t);
+   |              - value moved here
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+
+error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:16:9
+   |
+LL |         t.1 = 2;
+   |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut t: Tuple = (S(0), 0);
+   |             +++
+
+error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
+   |
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut u: Tpair = Tpair(S(0), 0);
+   |             +++
+
+error[E0382]: assign to part of moved value: `u`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
+   |
+LL |         let u: Tpair = Tpair(S(0), 0);
+   |             - move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+LL |         drop(u);
+   |              - value moved here
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+
+error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
+   |
+LL |         u.1 = 2;
+   |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut u: Tpair = Tpair(S(0), 0);
+   |             +++
+
+error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
+   |
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Spair = Spair { x: S(0), y: 0 };
+   |             +++
+
+error[E0382]: assign to part of moved value: `v`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
+   |
+LL |         let v: Spair = Spair { x: S(0), y: 0 };
+   |             - move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+LL |         drop(v);
+   |              - value moved here
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+
+error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
+   |
+LL |         v.y = 2;
+   |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Spair = Spair { x: S(0), y: 0 };
+   |             +++
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0382, E0594.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.rs b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.rs
new file mode 100644
index 00000000000..50d0c40fdf6
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.rs
@@ -0,0 +1,33 @@
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let t: Tuple;
+        t.0 = S(1);
+        //~^ ERROR E0381
+        t.1 = 2;
+        println!("{:?} {:?}", t.0, t.1);
+    }
+
+    {
+        let u: Tpair;
+        u.0 = S(1);
+        //~^ ERROR E0381
+        u.1 = 2;
+        println!("{:?} {:?}", u.0, u.1);
+    }
+
+    {
+        let v: Spair;
+        v.x = S(1);
+        //~^ ERROR E0381
+        v.y = 2;
+        println!("{:?} {:?}", v.x, v.y);
+    }
+}
diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr
new file mode 100644
index 00000000000..67a62583057
--- /dev/null
+++ b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr
@@ -0,0 +1,33 @@
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:12:9
+   |
+LL |         let t: Tuple;
+   |             - binding declared here but left uninitialized
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `u` isn't fully initialized
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:20:9
+   |
+LL |         let u: Tpair;
+   |             - binding declared here but left uninitialized
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ `u` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `v` isn't fully initialized
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:28:9
+   |
+LL |         let v: Spair;
+   |             - binding declared here but left uninitialized
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ `v` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs
new file mode 100644
index 00000000000..3e46ee6f078
--- /dev/null
+++ b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs
@@ -0,0 +1,20 @@
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct Value;
+impl Value {
+    fn as_array(&self) -> Option<&Vec<Value>> {
+        None
+    }
+}
+
+fn foo(val: Value) {
+    let _reviewers_original: Vec<Value> = match val.as_array() {
+        Some(array) => {
+            *array //~ ERROR cannot move out of `*array`
+        }
+        None => vec![]
+    };
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
new file mode 100644
index 00000000000..99c63e4db50
--- /dev/null
+++ b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
@@ -0,0 +1,15 @@
+error[E0507]: cannot move out of `*array` which is behind a shared reference
+  --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:14:13
+   |
+LL |             *array
+   |             ^^^^^^ move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait
+   |
+help: consider removing the dereference here
+   |
+LL -             *array
+LL +             array
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
new file mode 100644
index 00000000000..b3cce1b3a06
--- /dev/null
+++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
@@ -0,0 +1,55 @@
+// rust-lang/rust#55492: errors detected during MIR-borrowck's
+// analysis of a closure body may only be caught when AST-borrowck
+// looks at some parent.
+
+// transcribed from borrowck-closures-unique.rs
+mod borrowck_closures_unique {
+    pub fn e(x: &'static mut isize) {
+        static mut Y: isize = 3;
+        let mut c1 = |y: &'static mut isize| x = y;
+        //~^ ERROR is not declared as mutable
+        unsafe { c1(&mut Y); }
+    }
+}
+
+mod borrowck_closures_unique_grandparent {
+    pub fn ee(x: &'static mut isize) {
+        static mut Z: isize = 3;
+        let mut c1 = |z: &'static mut isize| {
+            let mut c2 = |y: &'static mut isize| x = y;
+        //~^ ERROR is not declared as mutable
+            c2(z);
+        };
+        unsafe { c1(&mut Z); }
+    }
+}
+
+// adapted from mutability_errors.rs
+mod mutability_errors {
+    pub fn capture_assign_whole(x: (i32,)) {
+        || { x = (1,); };
+        //~^ ERROR is not declared as mutable
+    }
+    pub fn capture_assign_part(x: (i32,)) {
+        || { x.0 = 1; };
+        //~^ ERROR is not declared as mutable
+    }
+    pub fn capture_reborrow_whole(x: (i32,)) {
+        || { &mut x; };
+        //~^ ERROR is not declared as mutable
+    }
+    pub fn capture_reborrow_part(x: (i32,)) {
+        || { &mut x.0; };
+        //~^ ERROR is not declared as mutable
+    }
+}
+
+fn main() {
+    static mut X: isize = 2;
+    unsafe { borrowck_closures_unique::e(&mut X); }
+
+    mutability_errors::capture_assign_whole((1000,));
+    mutability_errors::capture_assign_part((2000,));
+    mutability_errors::capture_reborrow_whole((3000,));
+    mutability_errors::capture_reborrow_part((4000,));
+}
diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
new file mode 100644
index 00000000000..4c299cdc455
--- /dev/null
+++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
@@ -0,0 +1,54 @@
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+  --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46
+   |
+LL |     pub fn e(x: &'static mut isize) {
+   |              - help: consider changing this to be mutable: `mut x`
+LL |         static mut Y: isize = 3;
+LL |         let mut c1 = |y: &'static mut isize| x = y;
+   |                                              ^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+  --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:50
+   |
+LL |     pub fn ee(x: &'static mut isize) {
+   |               - help: consider changing this to be mutable: `mut x`
+...
+LL |             let mut c2 = |y: &'static mut isize| x = y;
+   |                                                  ^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+  --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:14
+   |
+LL |     pub fn capture_assign_whole(x: (i32,)) {
+   |                                 - help: consider changing this to be mutable: `mut x`
+LL |         || { x = (1,); };
+   |              ^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
+  --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:34:14
+   |
+LL |     pub fn capture_assign_part(x: (i32,)) {
+   |                                - help: consider changing this to be mutable: `mut x`
+LL |         || { x.0 = 1; };
+   |              ^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:38:14
+   |
+LL |     pub fn capture_reborrow_whole(x: (i32,)) {
+   |                                   - help: consider changing this to be mutable: `mut x`
+LL |         || { &mut x; };
+   |              ^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
+  --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14
+   |
+LL |     pub fn capture_reborrow_part(x: (i32,)) {
+   |                                  - help: consider changing this to be mutable: `mut x`
+LL |         || { &mut x.0; };
+   |              ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs b/tests/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs
new file mode 100644
index 00000000000..b87ef3baa4a
--- /dev/null
+++ b/tests/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+// rust-lang/rust#55552: The strategy pnkfelix landed in PR #55274
+// (for ensuring that NLL respects user-provided lifetime annotations)
+// did not handle the case where the ascribed type has some expliit
+// wildcards (`_`) mixed in, and it caused an internal compiler error
+// (ICE).
+//
+// This test is just checking that we do not ICE when such things
+// occur.
+
+struct X;
+struct Y;
+struct Z;
+
+struct Pair { x: X, y: Y }
+
+pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+where A: FnOnce() -> RA + Send,
+      B: FnOnce() -> RB + Send,
+      RA: Send,
+      RB: Send
+{
+    (oper_a(), oper_b())
+}
+
+fn main() {
+    let ((_x, _y), _z): (_, Z) = join(|| (X, Y), || Z);
+
+    let (Pair { x: _x, y: _y }, Z): (_, Z) = join(|| Pair { x: X, y: Y }, || Z);
+}
diff --git a/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs b/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs
new file mode 100644
index 00000000000..efa313a9d23
--- /dev/null
+++ b/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs
@@ -0,0 +1,11 @@
+fn main() {
+    let mut greeting = "Hello world!".to_string();
+    let res = (|| (|| &greeting)())();
+
+    greeting = "DEALLOCATED".to_string();
+    //~^ ERROR cannot assign
+    drop(greeting);
+    //~^ ERROR cannot move
+
+    println!("thread result: {:?}", res);
+}
diff --git a/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr
new file mode 100644
index 00000000000..57803247ba8
--- /dev/null
+++ b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr
@@ -0,0 +1,32 @@
+error[E0506]: cannot assign to `greeting` because it is borrowed
+  --> $DIR/issue-58776-borrowck-scans-children.rs:5:5
+   |
+LL |     let res = (|| (|| &greeting)())();
+   |                --      -------- borrow occurs due to use in closure
+   |                |
+   |                borrow of `greeting` occurs here
+LL |
+LL |     greeting = "DEALLOCATED".to_string();
+   |     ^^^^^^^^ assignment to borrowed `greeting` occurs here
+...
+LL |     println!("thread result: {:?}", res);
+   |                                     --- borrow later used here
+
+error[E0505]: cannot move out of `greeting` because it is borrowed
+  --> $DIR/issue-58776-borrowck-scans-children.rs:7:10
+   |
+LL |     let res = (|| (|| &greeting)())();
+   |                --      -------- borrow occurs due to use in closure
+   |                |
+   |                borrow of `greeting` occurs here
+...
+LL |     drop(greeting);
+   |          ^^^^^^^^ move out of `greeting` occurs here
+...
+LL |     println!("thread result: {:?}", res);
+   |                                     --- borrow later used here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0505, E0506.
+For more information about an error, try `rustc --explain E0505`.
diff --git a/tests/ui/borrowck/issue-62007-assign-box.rs b/tests/ui/borrowck/issue-62007-assign-box.rs
new file mode 100644
index 00000000000..f6fbea821b5
--- /dev/null
+++ b/tests/ui/borrowck/issue-62007-assign-box.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+// Issue #62007: assigning over a deref projection of a box (in this
+// case, `*list = n;`) should be able to kill all borrows of `*list`,
+// so that `*list` can be borrowed on the next iteration through the
+// loop.
+
+#![allow(dead_code)]
+
+struct List<T> {
+    value: T,
+    next: Option<Box<List<T>>>,
+}
+
+fn to_refs<T>(mut list: Box<&mut List<T>>) -> Vec<&mut T> {
+    let mut result = vec![];
+    loop {
+        result.push(&mut list.value);
+        if let Some(n) = list.next.as_mut() {
+            *list = n;
+        } else {
+            return result;
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62007-assign-field.rs b/tests/ui/borrowck/issue-62007-assign-field.rs
new file mode 100644
index 00000000000..5b21c083816
--- /dev/null
+++ b/tests/ui/borrowck/issue-62007-assign-field.rs
@@ -0,0 +1,26 @@
+// run-pass
+
+// Issue #62007: assigning over a field projection (`list.0 = n;` in
+// this case) should be able to kill all borrows of `list.0`, so that
+// `list.0` can be borrowed on the next iteration through the loop.
+
+#![allow(dead_code)]
+
+struct List<T> {
+    value: T,
+    next: Option<Box<List<T>>>,
+}
+
+fn to_refs<T>(mut list: (&mut List<T>,)) -> Vec<&mut T> {
+    let mut result = vec![];
+    loop {
+        result.push(&mut (list.0).value);
+        if let Some(n) = (list.0).next.as_mut() {
+            list.0 = n;
+        } else {
+            return result;
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.rs b/tests/ui/borrowck/issue-62107-match-arm-scopes.rs
new file mode 100644
index 00000000000..93ce34d2fe5
--- /dev/null
+++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.rs
@@ -0,0 +1,12 @@
+fn main() {
+    let e: i32;
+    match e {
+        //~^ ERROR E0381
+        ref u if true => {}
+        ref v if true => {
+            let tx = 0;
+            &tx;
+        }
+        _ => (),
+    }
+}
diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
new file mode 100644
index 00000000000..9683da919aa
--- /dev/null
+++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `e` isn't initialized
+  --> $DIR/issue-62107-match-arm-scopes.rs:3:11
+   |
+LL |     let e: i32;
+   |         - binding declared here but left uninitialized
+LL |     match e {
+   |           ^ `e` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let e: i32 = 0;
+   |                +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs
new file mode 100644
index 00000000000..33d55be5812
--- /dev/null
+++ b/tests/ui/borrowck/issue-64453.rs
@@ -0,0 +1,23 @@
+struct Project;
+struct Value;
+
+static settings_dir: String = format!("");
+//~^ ERROR cannot call non-const fn
+//~| ERROR is not yet stable as a const
+
+fn from_string(_: String) -> Value {
+    Value
+}
+fn set_editor(_: Value) {}
+
+fn main() {
+    let settings_data = from_string(settings_dir);
+    //~^ ERROR cannot move out of static item
+    let args: i32 = 0;
+
+    match args {
+        ref x if x == &0 => set_editor(settings_data),
+        ref x if x == &1 => set_editor(settings_data),
+        _ => unimplemented!(),
+    }
+}
diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr
new file mode 100644
index 00000000000..245c3a40e05
--- /dev/null
+++ b/tests/ui/borrowck/issue-64453.stderr
@@ -0,0 +1,29 @@
+error: `Arguments::<'a>::new_v1` is not yet stable as a const fn
+  --> $DIR/issue-64453.rs:4:31
+   |
+LL | static settings_dir: String = format!("");
+   |                               ^^^^^^^^^^^
+   |
+   = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
+   = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: cannot call non-const fn `format` in statics
+  --> $DIR/issue-64453.rs:4:31
+   |
+LL | static settings_dir: String = format!("");
+   |                               ^^^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
+   = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0507]: cannot move out of static item `settings_dir`
+  --> $DIR/issue-64453.rs:14:37
+   |
+LL |     let settings_data = from_string(settings_dir);
+   |                                     ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0507.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.rs b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.rs
new file mode 100644
index 00000000000..f6d0e9e04d3
--- /dev/null
+++ b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.rs
@@ -0,0 +1,11 @@
+// Regression test for #69789: rustc generated an invalid suggestion
+// when `&` reference from `&mut` iterator is mutated.
+
+fn main() {
+    for item in &mut std::iter::empty::<&'static ()>() {
+        //~^ NOTE this iterator yields `&` references
+        *item = ();
+        //~^ ERROR cannot assign
+        //~| NOTE  cannot be written
+    }
+}
diff --git a/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr
new file mode 100644
index 00000000000..369a8c61d2c
--- /dev/null
+++ b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr
@@ -0,0 +1,12 @@
+error[E0594]: cannot assign to `*item`, which is behind a `&` reference
+  --> $DIR/issue-69789-iterator-mut-suggestion.rs:7:9
+   |
+LL |     for item in &mut std::iter::empty::<&'static ()>() {
+   |                 -------------------------------------- this iterator yields `&` references
+LL |
+LL |         *item = ();
+   |         ^^^^^^^^^^ `item` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/issue-71546.rs b/tests/ui/borrowck/issue-71546.rs
new file mode 100644
index 00000000000..42100edeaa7
--- /dev/null
+++ b/tests/ui/borrowck/issue-71546.rs
@@ -0,0 +1,17 @@
+// Regression test for #71546.
+//
+// Made to pass as part of fixing #98095.
+//
+// check-pass
+
+pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str>
+where
+    V: 'static,
+    for<'a> &'a V: IntoIterator,
+    for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
+{
+    let csv_str: String = value.into_iter().map(|elem| elem.to_string()).collect::<String>();
+    Ok(csv_str)
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-7573.rs b/tests/ui/borrowck/issue-7573.rs
new file mode 100644
index 00000000000..7c07411533f
--- /dev/null
+++ b/tests/ui/borrowck/issue-7573.rs
@@ -0,0 +1,41 @@
+pub struct CrateId {
+    local_path: String,
+    junk: String,
+}
+
+impl CrateId {
+    fn new(s: &str) -> CrateId {
+        CrateId { local_path: s.to_string(), junk: "wutevs".to_string() }
+    }
+}
+
+pub fn remove_package_from_database() {
+    let mut lines_to_use: Vec<&CrateId> = Vec::new();
+    //~^ NOTE `lines_to_use` declared here, outside of the closure body
+    let push_id = |installed_id: &CrateId| {
+        //~^ NOTE `installed_id` is a reference that is only valid in the closure body
+        lines_to_use.push(installed_id);
+        //~^ ERROR borrowed data escapes outside of closure
+        //~| NOTE `installed_id` escapes the closure body here
+    };
+    list_database(push_id);
+
+    for l in &lines_to_use {
+        println!("{}", l.local_path);
+    }
+}
+
+pub fn list_database<F>(mut f: F)
+where
+    F: FnMut(&CrateId),
+{
+    let stuff = ["foo", "bar"];
+
+    for l in &stuff {
+        f(&CrateId::new(*l));
+    }
+}
+
+pub fn main() {
+    remove_package_from_database();
+}
diff --git a/tests/ui/borrowck/issue-7573.stderr b/tests/ui/borrowck/issue-7573.stderr
new file mode 100644
index 00000000000..9d86286b867
--- /dev/null
+++ b/tests/ui/borrowck/issue-7573.stderr
@@ -0,0 +1,15 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/issue-7573.rs:17:9
+   |
+LL |     let mut lines_to_use: Vec<&CrateId> = Vec::new();
+   |         ---------------- `lines_to_use` declared here, outside of the closure body
+LL |
+LL |     let push_id = |installed_id: &CrateId| {
+   |                    ------------ `installed_id` is a reference that is only valid in the closure body
+LL |
+LL |         lines_to_use.push(installed_id);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/borrowck/issue-80772.rs b/tests/ui/borrowck/issue-80772.rs
new file mode 100644
index 00000000000..1b8caa3f8ac
--- /dev/null
+++ b/tests/ui/borrowck/issue-80772.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+trait SomeTrait {}
+
+pub struct Exhibit {
+    constant: usize,
+    factory: fn(&usize) -> Box<dyn SomeTrait>,
+}
+
+pub const A_CONSTANT: &[Exhibit] = &[
+    Exhibit {
+        constant: 1,
+        factory: |_| unimplemented!(),
+    },
+    Exhibit {
+        constant: "Hello world".len(),
+        factory: |_| unimplemented!(),
+    },
+];
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-1.rs b/tests/ui/borrowck/issue-81365-1.rs
new file mode 100644
index 00000000000..8e212a77016
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-1.rs
@@ -0,0 +1,26 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+impl Container {
+    fn bad_borrow(&mut self) {
+        let first = &self.target_field;
+        self.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-1.stderr b/tests/ui/borrowck/issue-81365-1.stderr
new file mode 100644
index 00000000000..d79394834dc
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-1.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `self.container_field` because it is borrowed
+  --> $DIR/issue-81365-1.rs:21:9
+   |
+LL |         let first = &self.target_field;
+   |                      ---- borrow of `self.container_field` occurs here
+LL |         self.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `DerefTarget`
+note: deref defined here
+  --> $DIR/issue-81365-1.rs:12:5
+   |
+LL |     type Target = DerefTarget;
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-10.rs b/tests/ui/borrowck/issue-81365-10.rs
new file mode 100644
index 00000000000..7602e184a9f
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-10.rs
@@ -0,0 +1,26 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+impl Container {
+    fn bad_borrow(&mut self) {
+        let first = &self.deref().target_field;
+        self.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-10.stderr b/tests/ui/borrowck/issue-81365-10.stderr
new file mode 100644
index 00000000000..27123ef2be1
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-10.stderr
@@ -0,0 +1,13 @@
+error[E0506]: cannot assign to `self.container_field` because it is borrowed
+  --> $DIR/issue-81365-10.rs:21:9
+   |
+LL |         let first = &self.deref().target_field;
+   |                      ------------ borrow of `self.container_field` occurs here
+LL |         self.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-11.rs b/tests/ui/borrowck/issue-81365-11.rs
new file mode 100644
index 00000000000..6b558c65d3d
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-11.rs
@@ -0,0 +1,32 @@
+use std::ops::{Deref, DerefMut};
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+impl DerefMut for Container {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.target
+    }
+}
+
+impl Container {
+    fn bad_borrow(&mut self) {
+        let first = &mut self.target_field;
+        self.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-11.stderr b/tests/ui/borrowck/issue-81365-11.stderr
new file mode 100644
index 00000000000..0770c136632
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-11.stderr
@@ -0,0 +1,13 @@
+error[E0506]: cannot assign to `self.container_field` because it is borrowed
+  --> $DIR/issue-81365-11.rs:27:9
+   |
+LL |         let first = &mut self.target_field;
+   |                          ---- borrow of `self.container_field` occurs here
+LL |         self.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-2.rs b/tests/ui/borrowck/issue-81365-2.rs
new file mode 100644
index 00000000000..fbbdd93b97c
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-2.rs
@@ -0,0 +1,30 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+struct Outer {
+    container: Container,
+}
+
+impl Outer {
+    fn bad_borrow(&mut self) {
+        let first = &self.container.target_field;
+        self.container.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-2.stderr b/tests/ui/borrowck/issue-81365-2.stderr
new file mode 100644
index 00000000000..764eaaa7cc7
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-2.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
+  --> $DIR/issue-81365-2.rs:25:9
+   |
+LL |         let first = &self.container.target_field;
+   |                      -------------- borrow of `self.container.container_field` occurs here
+LL |         self.container.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `DerefTarget`
+note: deref defined here
+  --> $DIR/issue-81365-2.rs:12:5
+   |
+LL |     type Target = DerefTarget;
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-3.rs b/tests/ui/borrowck/issue-81365-3.rs
new file mode 100644
index 00000000000..9a9e3a31358
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-3.rs
@@ -0,0 +1,37 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+struct Outer {
+    container: Container,
+}
+
+impl Deref for Outer {
+    type Target = Container;
+    fn deref(&self) -> &Self::Target {
+        &self.container
+    }
+}
+
+impl Outer {
+    fn bad_borrow(&mut self) {
+        let first = &self.target_field;
+        self.container.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-3.stderr b/tests/ui/borrowck/issue-81365-3.stderr
new file mode 100644
index 00000000000..9447174fd21
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-3.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
+  --> $DIR/issue-81365-3.rs:32:9
+   |
+LL |         let first = &self.target_field;
+   |                      ---- borrow of `self.container.container_field` occurs here
+LL |         self.container.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `Container`
+note: deref defined here
+  --> $DIR/issue-81365-3.rs:23:5
+   |
+LL |     type Target = Container;
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-4.rs b/tests/ui/borrowck/issue-81365-4.rs
new file mode 100644
index 00000000000..b2643eb3358
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-4.rs
@@ -0,0 +1,38 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+struct Outer {
+    container: Container,
+    outer_field: bool,
+}
+
+impl Deref for Outer {
+    type Target = Container;
+    fn deref(&self) -> &Self::Target {
+        &self.container
+    }
+}
+
+impl Outer {
+    fn bad_borrow(&mut self) {
+        let first = &self.target_field;
+        self.outer_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-4.stderr b/tests/ui/borrowck/issue-81365-4.stderr
new file mode 100644
index 00000000000..0ab3fa92706
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-4.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `self.outer_field` because it is borrowed
+  --> $DIR/issue-81365-4.rs:33:9
+   |
+LL |         let first = &self.target_field;
+   |                      ---- borrow of `self.outer_field` occurs here
+LL |         self.outer_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `Container`
+note: deref defined here
+  --> $DIR/issue-81365-4.rs:24:5
+   |
+LL |     type Target = Container;
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-5.rs b/tests/ui/borrowck/issue-81365-5.rs
new file mode 100644
index 00000000000..d36b79615e3
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-5.rs
@@ -0,0 +1,33 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+
+impl DerefTarget {
+    fn get(&self) -> &bool {
+        &self.target_field
+    }
+}
+
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+impl Container {
+    fn bad_borrow(&mut self) {
+        let first = self.get();
+        self.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-5.stderr b/tests/ui/borrowck/issue-81365-5.stderr
new file mode 100644
index 00000000000..20ff229ffe7
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-5.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `self.container_field` because it is borrowed
+  --> $DIR/issue-81365-5.rs:28:9
+   |
+LL |         let first = self.get();
+   |                     ---------- borrow of `self.container_field` occurs here
+LL |         self.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `DerefTarget`
+note: deref defined here
+  --> $DIR/issue-81365-5.rs:19:5
+   |
+LL |     type Target = DerefTarget;
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-6.rs b/tests/ui/borrowck/issue-81365-6.rs
new file mode 100644
index 00000000000..85ea77756b3
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-6.rs
@@ -0,0 +1,23 @@
+use std::ops::Deref;
+
+struct Container {
+    target: Vec<()>,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = [()];
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+impl Container {
+    fn bad_borrow(&mut self) {
+        let first = &self[0];
+        self.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-6.stderr b/tests/ui/borrowck/issue-81365-6.stderr
new file mode 100644
index 00000000000..575aed73b46
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-6.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `self.container_field` because it is borrowed
+  --> $DIR/issue-81365-6.rs:18:9
+   |
+LL |         let first = &self[0];
+   |                      ---- borrow of `self.container_field` occurs here
+LL |         self.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `[()]`
+note: deref defined here
+  --> $DIR/issue-81365-6.rs:9:5
+   |
+LL |     type Target = [()];
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-7.rs b/tests/ui/borrowck/issue-81365-7.rs
new file mode 100644
index 00000000000..cbf70f11a9a
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-7.rs
@@ -0,0 +1,24 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+fn bad_borrow(c: &mut Container) {
+    let first = &c.target_field;
+    c.container_field = true; //~ ERROR E0506
+    first;
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-7.stderr b/tests/ui/borrowck/issue-81365-7.stderr
new file mode 100644
index 00000000000..52d2d9e75a9
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-7.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `c.container_field` because it is borrowed
+  --> $DIR/issue-81365-7.rs:20:5
+   |
+LL |     let first = &c.target_field;
+   |                  - borrow of `c.container_field` occurs here
+LL |     c.container_field = true;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here
+LL |     first;
+   |     ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `DerefTarget`
+note: deref defined here
+  --> $DIR/issue-81365-7.rs:12:5
+   |
+LL |     type Target = DerefTarget;
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-8.rs b/tests/ui/borrowck/issue-81365-8.rs
new file mode 100644
index 00000000000..0bb1033fb42
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-8.rs
@@ -0,0 +1,26 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+impl Container {
+    fn bad_borrow(&mut self) {
+        let first = &(*self).target_field;
+        self.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-8.stderr b/tests/ui/borrowck/issue-81365-8.stderr
new file mode 100644
index 00000000000..fd83e10a295
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-8.stderr
@@ -0,0 +1,20 @@
+error[E0506]: cannot assign to `self.container_field` because it is borrowed
+  --> $DIR/issue-81365-8.rs:21:9
+   |
+LL |         let first = &(*self).target_field;
+   |                      ------- borrow of `self.container_field` occurs here
+LL |         self.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+   |
+   = note: borrow occurs due to deref coercion to `DerefTarget`
+note: deref defined here
+  --> $DIR/issue-81365-8.rs:12:5
+   |
+LL |     type Target = DerefTarget;
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81365-9.rs b/tests/ui/borrowck/issue-81365-9.rs
new file mode 100644
index 00000000000..cd57afa288d
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-9.rs
@@ -0,0 +1,26 @@
+use std::ops::Deref;
+
+struct DerefTarget {
+    target_field: bool,
+}
+struct Container {
+    target: DerefTarget,
+    container_field: bool,
+}
+
+impl Deref for Container {
+    type Target = DerefTarget;
+    fn deref(&self) -> &Self::Target {
+        &self.target
+    }
+}
+
+impl Container {
+    fn bad_borrow(&mut self) {
+        let first = &Deref::deref(self).target_field;
+        self.container_field = true; //~ ERROR E0506
+        first;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81365-9.stderr b/tests/ui/borrowck/issue-81365-9.stderr
new file mode 100644
index 00000000000..c7d48214fd4
--- /dev/null
+++ b/tests/ui/borrowck/issue-81365-9.stderr
@@ -0,0 +1,13 @@
+error[E0506]: cannot assign to `self.container_field` because it is borrowed
+  --> $DIR/issue-81365-9.rs:21:9
+   |
+LL |         let first = &Deref::deref(self).target_field;
+   |                                   ---- borrow of `self.container_field` occurs here
+LL |         self.container_field = true;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+LL |         first;
+   |         ----- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-81899.rs b/tests/ui/borrowck/issue-81899.rs
new file mode 100644
index 00000000000..1f1af5c7e05
--- /dev/null
+++ b/tests/ui/borrowck/issue-81899.rs
@@ -0,0 +1,15 @@
+// Regression test for #81899.
+// The `panic!()` below is important to trigger the fixed ICE.
+
+const _CONST: &[u8] = &f(&[], |_| {});
+//~^ constant
+
+const fn f<F>(_: &[u8], _: F) -> &[u8]
+where
+    F: FnMut(&u8),
+{
+    panic!() //~ ERROR evaluation of constant value failed
+    //~^ panic
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-81899.stderr b/tests/ui/borrowck/issue-81899.stderr
new file mode 100644
index 00000000000..1b03bc3af9c
--- /dev/null
+++ b/tests/ui/borrowck/issue-81899.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-81899.rs:11:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:11:5
+   |
+note: inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:34]>`
+  --> $DIR/issue-81899.rs:11:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^
+note: inside `_CONST`
+  --> $DIR/issue-81899.rs:4:24
+   |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   |                        ^^^^^^^^^^^^^^
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant used
+  --> $DIR/issue-81899.rs:4:23
+   |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   |                       ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/borrowck/issue-82032.rs b/tests/ui/borrowck/issue-82032.rs
new file mode 100644
index 00000000000..4a01b60c1f6
--- /dev/null
+++ b/tests/ui/borrowck/issue-82032.rs
@@ -0,0 +1,16 @@
+use std::{fs, io::*};
+use std::collections::HashMap;
+
+type Handle = BufWriter<fs::File>;
+struct Thing(HashMap<String, Handle>);
+
+impl Thing {
+    pub fn die_horribly(&mut self) {
+        for v in self.0.values() {
+            v.flush();
+              //~^ ERROR cannot borrow
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-82032.stderr b/tests/ui/borrowck/issue-82032.stderr
new file mode 100644
index 00000000000..25f343117a3
--- /dev/null
+++ b/tests/ui/borrowck/issue-82032.stderr
@@ -0,0 +1,14 @@
+error[E0596]: cannot borrow `*v` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-82032.rs:10:13
+   |
+LL |         for v in self.0.values() {
+   |                  ---------------
+   |                  |      |
+   |                  |      help: use mutable method: `values_mut()`
+   |                  this iterator yields `&` references
+LL |             v.flush();
+   |             ^^^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
new file mode 100644
index 00000000000..dd0320bc53b
--- /dev/null
+++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
@@ -0,0 +1,24 @@
+// Regression test for #82126. Checks that mismatched lifetimes and types are
+// properly handled.
+
+// edition:2018
+
+use std::sync::Mutex;
+
+struct MarketMultiplier {}
+
+impl MarketMultiplier {
+    fn buy(&mut self) -> &mut usize {
+        todo!()
+    }
+}
+
+async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
+    //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+    //~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
+    LockedMarket(generator.lock().unwrap().buy())
+}
+
+struct LockedMarket<T>(T);
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
new file mode 100644
index 00000000000..d2b927fb664
--- /dev/null
+++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
@@ -0,0 +1,33 @@
+error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
+   |
+LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
+   |                                                           ^^^^^^^^^^^^---- help: remove these generics
+   |                                                           |
+   |                                                           expected 0 lifetime arguments
+   |
+note: struct defined here, with 0 lifetime parameters
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
+   |
+LL | struct LockedMarket<T>(T);
+   |        ^^^^^^^^^^^^
+
+error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
+   |
+LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
+   |                                                           ^^^^^^^^^^^^ expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
+   |
+LL | struct LockedMarket<T>(T);
+   |        ^^^^^^^^^^^^ -
+help: add missing generic argument
+   |
+LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
+   |                                                                          +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/borrowck/issue-82462.rs b/tests/ui/borrowck/issue-82462.rs
new file mode 100644
index 00000000000..5a3c64255cc
--- /dev/null
+++ b/tests/ui/borrowck/issue-82462.rs
@@ -0,0 +1,21 @@
+struct DroppingSlice<'a>(&'a [i32]);
+
+impl Drop for DroppingSlice<'_> {
+    fn drop(&mut self) {
+        println!("hi from slice");
+    }
+}
+
+impl DroppingSlice<'_> {
+    fn iter(&self) -> std::slice::Iter<'_, i32> {
+        self.0.iter()
+    }
+}
+
+fn main() {
+    let mut v = vec![1, 2, 3, 4];
+    for x in DroppingSlice(&*v).iter() {
+        v.push(*x); //~ERROR
+        break;
+    }
+}
diff --git a/tests/ui/borrowck/issue-82462.stderr b/tests/ui/borrowck/issue-82462.stderr
new file mode 100644
index 00000000000..a2c291f7797
--- /dev/null
+++ b/tests/ui/borrowck/issue-82462.stderr
@@ -0,0 +1,22 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/issue-82462.rs:18:9
+   |
+LL |     for x in DroppingSlice(&*v).iter() {
+   |              ------------------
+   |              |               |
+   |              |               immutable borrow occurs here
+   |              a temporary with access to the immutable borrow is created here ...
+LL |         v.push(*x);
+   |         ^^^^^^^^^^ mutable borrow occurs here
+LL |         break;
+LL |     }
+   |     - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice`
+   |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+   |
+LL |     };
+   |      +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs
new file mode 100644
index 00000000000..d301e7b3524
--- /dev/null
+++ b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs
@@ -0,0 +1,32 @@
+// rust-lang/rust#83309: The compiler tries to suggest potential
+// methods that return `&mut` items. However, when it doesn't
+// find such methods, it still tries to add suggestions
+// which then fails an assertion later because there was
+// no suggestions to make.
+
+
+fn main() {
+    for v in Query.iter_mut() {
+        //~^ NOTE this iterator yields `&` references
+        *v -= 1;
+        //~^ ERROR cannot assign to `*v`, which is behind a `&` reference
+        //~| NOTE `v` is a `&` reference, so the data it refers to cannot be written
+    }
+}
+
+pub struct Query;
+pub struct QueryIter<'a>(&'a i32);
+
+impl Query {
+    pub fn iter_mut<'a>(&'a mut self) -> QueryIter<'a> {
+        todo!();
+    }
+}
+
+impl<'a> Iterator for QueryIter<'a> {
+    type Item = &'a i32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        todo!();
+    }
+}
diff --git a/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr
new file mode 100644
index 00000000000..26ce007dd34
--- /dev/null
+++ b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr
@@ -0,0 +1,12 @@
+error[E0594]: cannot assign to `*v`, which is behind a `&` reference
+  --> $DIR/issue-83309-ice-immut-in-for-loop.rs:11:9
+   |
+LL |     for v in Query.iter_mut() {
+   |              ---------------- this iterator yields `&` references
+LL |
+LL |         *v -= 1;
+   |         ^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/issue-83760.rs b/tests/ui/borrowck/issue-83760.rs
new file mode 100644
index 00000000000..e25b4f72785
--- /dev/null
+++ b/tests/ui/borrowck/issue-83760.rs
@@ -0,0 +1,40 @@
+struct Struct;
+
+fn test1() {
+    let mut val = Some(Struct);
+    while let Some(foo) = val { //~ ERROR use of moved value
+        if true {
+            val = None;
+        } else {
+
+        }
+    }
+}
+
+fn test2() {
+    let mut foo = Some(Struct);
+    let _x = foo.unwrap();
+    if true {
+        foo = Some(Struct);
+    } else {
+    }
+    let _y = foo; //~ ERROR use of moved value: `foo`
+}
+
+fn test3() {
+    let mut foo = Some(Struct);
+    let _x = foo.unwrap();
+    if true {
+        foo = Some(Struct);
+    } else if true {
+        foo = Some(Struct);
+    } else if true {
+        foo = Some(Struct);
+    } else if true {
+        foo = Some(Struct);
+    } else {
+    }
+    let _y = foo; //~ ERROR use of moved value: `foo`
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-83760.stderr b/tests/ui/borrowck/issue-83760.stderr
new file mode 100644
index 00000000000..a585bff0c65
--- /dev/null
+++ b/tests/ui/borrowck/issue-83760.stderr
@@ -0,0 +1,60 @@
+error[E0382]: use of moved value
+  --> $DIR/issue-83760.rs:5:20
+   |
+LL |     while let Some(foo) = val {
+   |                    ^^^ value moved here, in previous iteration of loop
+LL |         if true {
+LL |             val = None;
+   |             ---------- this reinitialization might get skipped
+   |
+   = note: move occurs because value has type `Struct`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     while let Some(ref foo) = val {
+   |                    +++
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/issue-83760.rs:21:14
+   |
+LL |     let mut foo = Some(Struct);
+   |         ------- move occurs because `foo` has type `Option<Struct>`, which does not implement the `Copy` trait
+LL |     let _x = foo.unwrap();
+   |                  -------- `foo` moved due to this method call
+LL |     if true {
+LL |         foo = Some(Struct);
+   |         ------------------ this reinitialization might get skipped
+...
+LL |     let _y = foo;
+   |              ^^^ value used here after move
+   |
+note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/issue-83760.rs:37:14
+   |
+LL |     let mut foo = Some(Struct);
+   |         ------- move occurs because `foo` has type `Option<Struct>`, which does not implement the `Copy` trait
+LL |     let _x = foo.unwrap();
+   |                  -------- `foo` moved due to this method call
+...
+LL |     let _y = foo;
+   |              ^^^ value used here after move
+   |
+note: these 3 reinitializations and 1 other might get skipped
+  --> $DIR/issue-83760.rs:30:9
+   |
+LL |         foo = Some(Struct);
+   |         ^^^^^^^^^^^^^^^^^^
+LL |     } else if true {
+LL |         foo = Some(Struct);
+   |         ^^^^^^^^^^^^^^^^^^
+LL |     } else if true {
+LL |         foo = Some(Struct);
+   |         ^^^^^^^^^^^^^^^^^^
+note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/issue-85581.rs b/tests/ui/borrowck/issue-85581.rs
new file mode 100644
index 00000000000..ccc120c5421
--- /dev/null
+++ b/tests/ui/borrowck/issue-85581.rs
@@ -0,0 +1,15 @@
+// Regression test of #85581.
+// Checks not to suggest to add `;` when the second mutable borrow
+// is in the first's scope.
+
+use std::collections::BinaryHeap;
+
+fn foo(heap: &mut BinaryHeap<i32>) {
+    match heap.peek_mut() {
+        Some(_) => { heap.pop(); },
+        //~^ ERROR: cannot borrow `*heap` as mutable more than once at a time
+        None => (),
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-85581.stderr b/tests/ui/borrowck/issue-85581.stderr
new file mode 100644
index 00000000000..59ca4867fd7
--- /dev/null
+++ b/tests/ui/borrowck/issue-85581.stderr
@@ -0,0 +1,17 @@
+error[E0499]: cannot borrow `*heap` as mutable more than once at a time
+  --> $DIR/issue-85581.rs:9:22
+   |
+LL |     match heap.peek_mut() {
+   |           ---------------
+   |           |
+   |           first mutable borrow occurs here
+   |           a temporary with access to the first borrow is created here ...
+LL |         Some(_) => { heap.pop(); },
+   |                      ^^^^^^^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<PeekMut<'_, i32>>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/issue-85765.rs b/tests/ui/borrowck/issue-85765.rs
new file mode 100644
index 00000000000..1598cd5d3c8
--- /dev/null
+++ b/tests/ui/borrowck/issue-85765.rs
@@ -0,0 +1,29 @@
+fn main() {
+    let mut test = Vec::new();
+    let rofl: &Vec<Vec<i32>> = &mut test;
+    //~^ NOTE consider changing this binding's type to be
+    rofl.push(Vec::new());
+    //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference
+    //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+    let mut mutvar = 42;
+    let r = &mutvar;
+    //~^ HELP consider changing this to be a mutable reference
+    *r = 0;
+    //~^ ERROR cannot assign to `*r`, which is behind a `&` reference
+    //~| NOTE `r` is a `&` reference, so the data it refers to cannot be written
+
+    #[rustfmt::skip]
+    let x: &usize = &mut{0};
+    //~^ NOTE consider changing this binding's type to be
+    *x = 1;
+    //~^ ERROR cannot assign to `*x`, which is behind a `&` reference
+    //~| NOTE `x` is a `&` reference, so the data it refers to cannot be written
+
+    #[rustfmt::skip]
+    let y: &usize = &mut(0);
+    //~^ NOTE consider changing this binding's type to be
+    *y = 1;
+    //~^ ERROR cannot assign to `*y`, which is behind a `&` reference
+    //~| NOTE `y` is a `&` reference, so the data it refers to cannot be written
+}
diff --git a/tests/ui/borrowck/issue-85765.stderr b/tests/ui/borrowck/issue-85765.stderr
new file mode 100644
index 00000000000..7da7dba68ab
--- /dev/null
+++ b/tests/ui/borrowck/issue-85765.stderr
@@ -0,0 +1,42 @@
+error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-85765.rs:5:5
+   |
+LL |     let rofl: &Vec<Vec<i32>> = &mut test;
+   |         ---- consider changing this binding's type to be: `&mut Vec<Vec<i32>>`
+LL |
+LL |     rofl.push(Vec::new());
+   |     ^^^^^^^^^^^^^^^^^^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error[E0594]: cannot assign to `*r`, which is behind a `&` reference
+  --> $DIR/issue-85765.rs:12:5
+   |
+LL |     *r = 0;
+   |     ^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let r = &mut mutvar;
+   |             ~~~~~~~~~~~
+
+error[E0594]: cannot assign to `*x`, which is behind a `&` reference
+  --> $DIR/issue-85765.rs:19:5
+   |
+LL |     let x: &usize = &mut{0};
+   |         - consider changing this binding's type to be: `&mut usize`
+LL |
+LL |     *x = 1;
+   |     ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `*y`, which is behind a `&` reference
+  --> $DIR/issue-85765.rs:26:5
+   |
+LL |     let y: &usize = &mut(0);
+   |         - consider changing this binding's type to be: `&mut usize`
+LL |
+LL |     *y = 1;
+   |     ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.rs b/tests/ui/borrowck/issue-87456-point-to-closure.rs
new file mode 100644
index 00000000000..9fc12ba7490
--- /dev/null
+++ b/tests/ui/borrowck/issue-87456-point-to-closure.rs
@@ -0,0 +1,14 @@
+// Regression test for #87456.
+
+fn take_mut(_val: impl FnMut()) {}
+
+fn main() {
+    let val = String::new();
+    //~^ NOTE: captured outer variable
+    take_mut(|| {
+    //~^ NOTE: captured by this `FnMut` closure
+        let _foo: String = val;
+        //~^ ERROR: cannot move out of `val`, a captured variable in an `FnMut` closure [E0507]
+        //~| NOTE: move occurs because
+    })
+}
diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.stderr b/tests/ui/borrowck/issue-87456-point-to-closure.stderr
new file mode 100644
index 00000000000..afd141125ac
--- /dev/null
+++ b/tests/ui/borrowck/issue-87456-point-to-closure.stderr
@@ -0,0 +1,20 @@
+error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure
+  --> $DIR/issue-87456-point-to-closure.rs:10:28
+   |
+LL |     let val = String::new();
+   |         --- captured outer variable
+LL |
+LL |     take_mut(|| {
+   |              -- captured by this `FnMut` closure
+LL |
+LL |         let _foo: String = val;
+   |                            ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |         let _foo: String = &val;
+   |                            +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/issue-88434-minimal-example.rs b/tests/ui/borrowck/issue-88434-minimal-example.rs
new file mode 100644
index 00000000000..b75abcb731e
--- /dev/null
+++ b/tests/ui/borrowck/issue-88434-minimal-example.rs
@@ -0,0 +1,14 @@
+// Regression test related to issue 88434
+
+const _CONST: &() = &f(&|_| {});
+//~^ constant
+
+const fn f<F>(_: &F)
+where
+    F: FnMut(&u8),
+{
+    panic!() //~ ERROR evaluation of constant value failed
+    //~^ panic
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/issue-88434-minimal-example.stderr b/tests/ui/borrowck/issue-88434-minimal-example.stderr
new file mode 100644
index 00000000000..a5a571c6d4d
--- /dev/null
+++ b/tests/ui/borrowck/issue-88434-minimal-example.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-88434-minimal-example.rs:10:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5
+   |
+note: inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:28]>`
+  --> $DIR/issue-88434-minimal-example.rs:10:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^
+note: inside `_CONST`
+  --> $DIR/issue-88434-minimal-example.rs:3:22
+   |
+LL | const _CONST: &() = &f(&|_| {});
+   |                      ^^^^^^^^^^
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant used
+  --> $DIR/issue-88434-minimal-example.rs:3:21
+   |
+LL | const _CONST: &() = &f(&|_| {});
+   |                     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs
new file mode 100644
index 00000000000..f9134e669dc
--- /dev/null
+++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs
@@ -0,0 +1,14 @@
+// Regression test for issue 88434
+
+const _CONST: &[u8] = &f(&[], |_| {});
+//~^ constant
+
+const fn f<F>(_: &[u8], _: F) -> &[u8]
+where
+    F: FnMut(&u8),
+{
+    panic!() //~ ERROR evaluation of constant value failed
+    //~^ panic
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
new file mode 100644
index 00000000000..00023c459a8
--- /dev/null
+++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+   |
+note: inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:34]>`
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^
+note: inside `_CONST`
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:3:24
+   |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   |                        ^^^^^^^^^^^^^^
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant used
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:3:23
+   |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   |                       ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/borrowck/issue-91206.rs b/tests/ui/borrowck/issue-91206.rs
new file mode 100644
index 00000000000..67407c1eae3
--- /dev/null
+++ b/tests/ui/borrowck/issue-91206.rs
@@ -0,0 +1,16 @@
+struct TestClient;
+
+impl TestClient {
+    fn get_inner_ref(&self) -> &Vec<usize> {
+        todo!()
+    }
+}
+
+fn main() {
+    let client = TestClient;
+    let inner = client.get_inner_ref();
+    //~^ NOTE consider changing this binding's type to be
+    inner.clear();
+    //~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596]
+    //~| NOTE `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+}
diff --git a/tests/ui/borrowck/issue-91206.stderr b/tests/ui/borrowck/issue-91206.stderr
new file mode 100644
index 00000000000..12d8d27c5f0
--- /dev/null
+++ b/tests/ui/borrowck/issue-91206.stderr
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-91206.rs:13:5
+   |
+LL |     let inner = client.get_inner_ref();
+   |         ----- consider changing this binding's type to be: `&mut Vec<usize>`
+LL |
+LL |     inner.clear();
+   |     ^^^^^^^^^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-92015.rs b/tests/ui/borrowck/issue-92015.rs
new file mode 100644
index 00000000000..16d651717ff
--- /dev/null
+++ b/tests/ui/borrowck/issue-92015.rs
@@ -0,0 +1,7 @@
+// Regression test for #92105.
+// ICE when mutating immutable reference from last statement of a block.
+
+fn main() {
+    let foo = Some(&0).unwrap();
+    *foo = 1; //~ ERROR cannot assign
+}
diff --git a/tests/ui/borrowck/issue-92015.stderr b/tests/ui/borrowck/issue-92015.stderr
new file mode 100644
index 00000000000..62b1183e71b
--- /dev/null
+++ b/tests/ui/borrowck/issue-92015.stderr
@@ -0,0 +1,11 @@
+error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
+  --> $DIR/issue-92015.rs:6:5
+   |
+LL |     let foo = Some(&0).unwrap();
+   |         --- consider changing this binding's type to be: `&mut i32`
+LL |     *foo = 1;
+   |     ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/issue-93078.rs b/tests/ui/borrowck/issue-93078.rs
new file mode 100644
index 00000000000..2e608c5db3e
--- /dev/null
+++ b/tests/ui/borrowck/issue-93078.rs
@@ -0,0 +1,15 @@
+trait Modify {
+    fn modify(&mut self) ;
+}
+
+impl<T> Modify for T  {
+    fn modify(&mut self)  {}
+}
+
+trait Foo {
+    fn mute(&mut self) {
+        self.modify(); //~ ERROR cannot borrow `self` as mutable
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-93078.stderr b/tests/ui/borrowck/issue-93078.stderr
new file mode 100644
index 00000000000..771a652a173
--- /dev/null
+++ b/tests/ui/borrowck/issue-93078.stderr
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+  --> $DIR/issue-93078.rs:11:9
+   |
+LL |         self.modify();
+   |         ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = note: as `Self` may be unsized, this call attempts to take `&mut &mut self`
+   = note: however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/issue-93093.rs b/tests/ui/borrowck/issue-93093.rs
new file mode 100644
index 00000000000..f4db5ecafac
--- /dev/null
+++ b/tests/ui/borrowck/issue-93093.rs
@@ -0,0 +1,14 @@
+// edition:2018
+struct S {
+    foo: usize,
+}
+impl S {
+    async fn bar(&self) { //~ HELP consider changing this to be a mutable reference
+        //~| SUGGESTION &mut self
+        self.foo += 1; //~ ERROR cannot assign to `self.foo`, which is behind a `&` reference [E0594]
+    }
+}
+
+fn main() {
+    S { foo: 1 }.bar();
+}
diff --git a/tests/ui/borrowck/issue-93093.stderr b/tests/ui/borrowck/issue-93093.stderr
new file mode 100644
index 00000000000..afa76594f0b
--- /dev/null
+++ b/tests/ui/borrowck/issue-93093.stderr
@@ -0,0 +1,14 @@
+error[E0594]: cannot assign to `self.foo`, which is behind a `&` reference
+  --> $DIR/issue-93093.rs:8:9
+   |
+LL |         self.foo += 1;
+   |         ^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     async fn bar(&mut self) {
+   |                  ~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs
new file mode 100644
index 00000000000..95847d8d301
--- /dev/null
+++ b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs
@@ -0,0 +1,14 @@
+fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
+    None.into_iter()
+        .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
+        //~^ ERROR captured variable cannot escape `FnMut` closure body
+        //~| HELP consider adding 'move' keyword before the nested closure
+}
+
+fn foo2(s: &str) -> impl Sized + '_ {
+    move |()| s.chars().map(|c| format!("{}{}", c, s))
+    //~^ ERROR lifetime may not live long enough
+    //~| HELP consider adding 'move' keyword before the nested closure
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr
new file mode 100644
index 00000000000..2eae614a2f5
--- /dev/null
+++ b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr
@@ -0,0 +1,37 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-95079-missing-move-in-nested-closure.rs:3:29
+   |
+LL | fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
+   |         - variable defined here
+LL |     None.into_iter()
+LL |         .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
+   |                           - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                           | |
+   |                           | returns a reference to a captured variable which escapes the closure body
+   |                           | variable captured here
+   |                           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
+help: consider adding 'move' keyword before the nested closure
+   |
+LL |         .flat_map(move |()| s.chars().map(move |c| format!("{}{}", c, s)))
+   |                                           ++++
+
+error: lifetime may not live long enough
+  --> $DIR/issue-95079-missing-move-in-nested-closure.rs:9:15
+   |
+LL |     move |()| s.chars().map(|c| format!("{}{}", c, s))
+   |     --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |     |       |
+   |     |       return type of closure `Map<Chars<'_>, [closure@$DIR/issue-95079-missing-move-in-nested-closure.rs:9:29: 9:32]>` contains a lifetime `'2`
+   |     lifetime `'1` represents this closure's body
+   |
+   = note: closure implements `Fn`, so references to captured variables can't escape the closure
+help: consider adding 'move' keyword before the nested closure
+   |
+LL |     move |()| s.chars().map(move |c| format!("{}{}", c, s))
+   |                             ++++
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs
new file mode 100644
index 00000000000..5b5d86eec2c
--- /dev/null
+++ b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs
@@ -0,0 +1,49 @@
+// run-pass
+
+#![allow(unused_must_use)]
+#![allow(dead_code)]
+use std::thread;
+
+fn user(_i: isize) {}
+
+fn foo() {
+    // Here, i is *copied* into the proc (heap closure).
+    // Requires allocation.  The proc's copy is not mutable.
+    let mut i = 0;
+    let t = thread::spawn(move|| {
+        user(i);
+        println!("spawned {}", i)
+    });
+    i += 1;
+    println!("original {}", i);
+    t.join();
+}
+
+fn bar() {
+    // Here, the original i has not been moved, only copied, so is still
+    // mutable outside of the proc.
+    let mut i = 0;
+    while i < 10 {
+        let t = thread::spawn(move|| {
+            user(i);
+        });
+        i += 1;
+        t.join();
+    }
+}
+
+fn car() {
+    // Here, i must be shadowed in the proc to be mutable.
+    let mut i = 0;
+    while i < 10 {
+        let t = thread::spawn(move|| {
+            let mut i = i;
+            i += 1;
+            user(i);
+        });
+        i += 1;
+        t.join();
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/lazy-init.rs b/tests/ui/borrowck/lazy-init.rs
new file mode 100644
index 00000000000..a4b5d18bb33
--- /dev/null
+++ b/tests/ui/borrowck/lazy-init.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+#![allow(unused_mut)]
+
+
+fn foo(x: isize) { println!("{}", x); }
+
+pub fn main() { let mut x: isize; if 1 > 2 { x = 12; } else { x = 10; } foo(x); }
diff --git a/tests/ui/borrowck/many-mutable-borrows.rs b/tests/ui/borrowck/many-mutable-borrows.rs
new file mode 100644
index 00000000000..3e6ea9d25d9
--- /dev/null
+++ b/tests/ui/borrowck/many-mutable-borrows.rs
@@ -0,0 +1,18 @@
+fn main() {
+    let v = Vec::new(); //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+}
diff --git a/tests/ui/borrowck/many-mutable-borrows.stderr b/tests/ui/borrowck/many-mutable-borrows.stderr
new file mode 100644
index 00000000000..aa0cbcffd95
--- /dev/null
+++ b/tests/ui/borrowck/many-mutable-borrows.stderr
@@ -0,0 +1,33 @@
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/many-mutable-borrows.rs:2:9
+   |
+LL |     let v = Vec::new();
+   |         ^ not mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+   |
+   = note: ...and 5 other attempted mutable borrows
+help: consider changing this to be mutable
+   |
+LL |     let mut v = Vec::new();
+   |         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/move-error-in-promoted-2.rs b/tests/ui/borrowck/move-error-in-promoted-2.rs
new file mode 100644
index 00000000000..13da34f3922
--- /dev/null
+++ b/tests/ui/borrowck/move-error-in-promoted-2.rs
@@ -0,0 +1,10 @@
+// Regression test for #70934
+
+struct S;
+
+fn foo() {
+    &([S][0],);
+    //~^ ERROR cannot move out of type `[S; 1]`
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr
new file mode 100644
index 00000000000..38dba94bdd4
--- /dev/null
+++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr
@@ -0,0 +1,12 @@
+error[E0508]: cannot move out of type `[S; 1]`, a non-copy array
+  --> $DIR/move-error-in-promoted-2.rs:6:7
+   |
+LL |     &([S][0],);
+   |       ^^^^^^
+   |       |
+   |       cannot move out of here
+   |       move occurs because value has type `S`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/tests/ui/borrowck/move-error-in-promoted.rs b/tests/ui/borrowck/move-error-in-promoted.rs
new file mode 100644
index 00000000000..b94db645131
--- /dev/null
+++ b/tests/ui/borrowck/move-error-in-promoted.rs
@@ -0,0 +1,17 @@
+// Regression test for #70934
+
+fn f() {
+    const C: [S2; 1] = [S2];
+    let _ = S1(C[0]).clone();
+    //~^ ERROR cannot move out of type `[S2; 1]`
+}
+
+#[derive(Clone)]
+struct S1(S2);
+
+#[derive(Clone)]
+struct S2;
+
+fn main() {
+    f();
+}
diff --git a/tests/ui/borrowck/move-error-in-promoted.stderr b/tests/ui/borrowck/move-error-in-promoted.stderr
new file mode 100644
index 00000000000..a4432e38da0
--- /dev/null
+++ b/tests/ui/borrowck/move-error-in-promoted.stderr
@@ -0,0 +1,12 @@
+error[E0508]: cannot move out of type `[S2; 1]`, a non-copy array
+  --> $DIR/move-error-in-promoted.rs:5:16
+   |
+LL |     let _ = S1(C[0]).clone();
+   |                ^^^^
+   |                |
+   |                cannot move out of here
+   |                move occurs because value has type `S2`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/tests/ui/borrowck/move-error-snippets-ext.rs b/tests/ui/borrowck/move-error-snippets-ext.rs
new file mode 100644
index 00000000000..c77f6c8276e
--- /dev/null
+++ b/tests/ui/borrowck/move-error-snippets-ext.rs
@@ -0,0 +1,7 @@
+// ignore-test
+
+macro_rules! aaa {
+    ($c:ident) => {{
+        let a = $c;
+    }}
+}
diff --git a/tests/ui/borrowck/move-error-snippets.rs b/tests/ui/borrowck/move-error-snippets.rs
new file mode 100644
index 00000000000..64f95653828
--- /dev/null
+++ b/tests/ui/borrowck/move-error-snippets.rs
@@ -0,0 +1,23 @@
+// Test that we don't ICE after trying to construct a cross-file snippet #63800.
+
+// compile-flags: --test
+
+#[macro_use]
+#[path = "move-error-snippets-ext.rs"]
+mod move_error_snippets_ext;
+
+struct A;
+
+macro_rules! sss {
+    () => {
+        #[test]
+        fn fff() {
+            static D: A = A;
+            aaa!(D);         //~ ERROR cannot move
+        }
+    };
+}
+
+sss!();
+
+fn main() {}
diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr
new file mode 100644
index 00000000000..8ac711e9e59
--- /dev/null
+++ b/tests/ui/borrowck/move-error-snippets.stderr
@@ -0,0 +1,20 @@
+error[E0507]: cannot move out of static item `D`
+  --> $DIR/move-error-snippets-ext.rs:5:17
+   |
+LL |         let a = $c;
+   |                 ^^ move occurs because `D` has type `A`, which does not implement the `Copy` trait
+   |
+  ::: $DIR/move-error-snippets.rs:21:1
+   |
+LL | sss!();
+   | ------ in this macro invocation
+   |
+   = note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+   |
+LL |         let a = &$c;
+   |                 +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/move-from-union-field-issue-66500.rs b/tests/ui/borrowck/move-from-union-field-issue-66500.rs
new file mode 100644
index 00000000000..0bd2147f463
--- /dev/null
+++ b/tests/ui/borrowck/move-from-union-field-issue-66500.rs
@@ -0,0 +1,28 @@
+// Moving from a reference/raw pointer should be an error, even when they're
+// the field of a union.
+
+union Pointers {
+    a: &'static String,
+    b: &'static mut String,
+    c: *const String,
+    d: *mut String,
+}
+
+unsafe fn move_ref(u: Pointers) -> String {
+    *u.a
+    //~^ ERROR cannot move out of `*u.a`
+}
+unsafe fn move_ref_mut(u: Pointers) -> String {
+    *u.b
+    //~^ ERROR cannot move out of `*u.b`
+}
+unsafe fn move_ptr(u: Pointers) -> String {
+    *u.c
+    //~^ ERROR cannot move out of `*u.c`
+}
+unsafe fn move_ptr_mut(u: Pointers) -> String {
+    *u.d
+    //~^ ERROR cannot move out of `*u.d`
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr
new file mode 100644
index 00000000000..70078582713
--- /dev/null
+++ b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr
@@ -0,0 +1,27 @@
+error[E0507]: cannot move out of `*u.a` which is behind a shared reference
+  --> $DIR/move-from-union-field-issue-66500.rs:12:5
+   |
+LL |     *u.a
+   |     ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait
+
+error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
+  --> $DIR/move-from-union-field-issue-66500.rs:16:5
+   |
+LL |     *u.b
+   |     ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait
+
+error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
+  --> $DIR/move-from-union-field-issue-66500.rs:20:5
+   |
+LL |     *u.c
+   |     ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait
+
+error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
+  --> $DIR/move-from-union-field-issue-66500.rs:24:5
+   |
+LL |     *u.d
+   |     ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/move-in-pattern-mut-in-loop.rs b/tests/ui/borrowck/move-in-pattern-mut-in-loop.rs
new file mode 100644
index 00000000000..4b42f9d4cd5
--- /dev/null
+++ b/tests/ui/borrowck/move-in-pattern-mut-in-loop.rs
@@ -0,0 +1,10 @@
+// Regression test for #80913.
+
+fn main() {
+    let mut x = 42_i32;
+    let mut opt = Some(&mut x);
+    for _ in 0..5 {
+        if let Some(mut _x) = opt {}
+        //~^ ERROR: use of moved value
+    }
+}
diff --git a/tests/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/tests/ui/borrowck/move-in-pattern-mut-in-loop.stderr
new file mode 100644
index 00000000000..55948afca73
--- /dev/null
+++ b/tests/ui/borrowck/move-in-pattern-mut-in-loop.stderr
@@ -0,0 +1,15 @@
+error[E0382]: use of moved value
+  --> $DIR/move-in-pattern-mut-in-loop.rs:7:21
+   |
+LL |         if let Some(mut _x) = opt {}
+   |                     ^^^^^^ value moved here, in previous iteration of loop
+   |
+   = note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         if let Some(ref mut _x) = opt {}
+   |                     +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/move-in-pattern-mut.rs b/tests/ui/borrowck/move-in-pattern-mut.rs
new file mode 100644
index 00000000000..b5c275bf28c
--- /dev/null
+++ b/tests/ui/borrowck/move-in-pattern-mut.rs
@@ -0,0 +1,23 @@
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+    V {
+        s: S,
+    }
+}
+fn bar(_: E) {}
+
+fn main() {
+    let s = Some(S);
+    if let Some(mut x) = s {
+        x = S;
+    }
+    foo(s); //~ ERROR use of partially moved value: `s`
+    let mut e = E::V { s: S };
+    let E::V { s: mut x } = e;
+    x = S;
+    bar(e); //~ ERROR use of partially moved value: `e`
+}
diff --git a/tests/ui/borrowck/move-in-pattern-mut.stderr b/tests/ui/borrowck/move-in-pattern-mut.stderr
new file mode 100644
index 00000000000..dd3471e2c8b
--- /dev/null
+++ b/tests/ui/borrowck/move-in-pattern-mut.stderr
@@ -0,0 +1,33 @@
+error[E0382]: use of partially moved value: `s`
+  --> $DIR/move-in-pattern-mut.rs:18:9
+   |
+LL |     if let Some(mut x) = s {
+   |                 ----- value partially moved here
+...
+LL |     foo(s);
+   |         ^ value used here after partial move
+   |
+   = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     if let Some(ref mut x) = s {
+   |                 +++
+
+error[E0382]: use of partially moved value: `e`
+  --> $DIR/move-in-pattern-mut.rs:22:9
+   |
+LL |     let E::V { s: mut x } = e;
+   |                   ----- value partially moved here
+LL |     x = S;
+LL |     bar(e);
+   |         ^ value used here after partial move
+   |
+   = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let E::V { s: ref mut x } = e;
+   |                   +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/move-in-pattern.fixed b/tests/ui/borrowck/move-in-pattern.fixed
new file mode 100644
index 00000000000..145893d3343
--- /dev/null
+++ b/tests/ui/borrowck/move-in-pattern.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+    V {
+        s: S,
+    }
+}
+fn bar(_: E) {}
+
+fn main() {
+    let s = Some(S);
+    if let Some(ref x) = s {
+        let _ = x;
+    }
+    foo(s); //~ ERROR use of partially moved value: `s`
+    let e = E::V { s: S };
+    let E::V { s: ref x } = e;
+    let _ = x;
+    bar(e); //~ ERROR use of partially moved value: `e`
+}
diff --git a/tests/ui/borrowck/move-in-pattern.rs b/tests/ui/borrowck/move-in-pattern.rs
new file mode 100644
index 00000000000..14851d0f6fc
--- /dev/null
+++ b/tests/ui/borrowck/move-in-pattern.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+    V {
+        s: S,
+    }
+}
+fn bar(_: E) {}
+
+fn main() {
+    let s = Some(S);
+    if let Some(x) = s {
+        let _ = x;
+    }
+    foo(s); //~ ERROR use of partially moved value: `s`
+    let e = E::V { s: S };
+    let E::V { s: x } = e;
+    let _ = x;
+    bar(e); //~ ERROR use of partially moved value: `e`
+}
diff --git a/tests/ui/borrowck/move-in-pattern.stderr b/tests/ui/borrowck/move-in-pattern.stderr
new file mode 100644
index 00000000000..250acbe5928
--- /dev/null
+++ b/tests/ui/borrowck/move-in-pattern.stderr
@@ -0,0 +1,33 @@
+error[E0382]: use of partially moved value: `s`
+  --> $DIR/move-in-pattern.rs:19:9
+   |
+LL |     if let Some(x) = s {
+   |                 - value partially moved here
+...
+LL |     foo(s);
+   |         ^ value used here after partial move
+   |
+   = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     if let Some(ref x) = s {
+   |                 +++
+
+error[E0382]: use of partially moved value: `e`
+  --> $DIR/move-in-pattern.rs:23:9
+   |
+LL |     let E::V { s: x } = e;
+   |                   - value partially moved here
+LL |     let _ = x;
+LL |     bar(e);
+   |         ^ value used here after partial move
+   |
+   = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let E::V { s: ref x } = e;
+   |                   +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.rs b/tests/ui/borrowck/move-in-static-initializer-issue-38520.rs
new file mode 100644
index 00000000000..c2a59a1054c
--- /dev/null
+++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.rs
@@ -0,0 +1,16 @@
+// Regression test for #38520. Check that moves of `Foo` are not
+// permitted as `Foo` is not copy (even in a static/const
+// initializer).
+
+struct Foo(usize);
+
+const fn get(x: Foo) -> usize {
+    x.0
+}
+
+const X: Foo = Foo(22);
+static Y: usize = get(*&X); //~ ERROR [E0507]
+const Z: usize = get(*&X); //~ ERROR [E0507]
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
new file mode 100644
index 00000000000..6619fb42c28
--- /dev/null
+++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
@@ -0,0 +1,15 @@
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/move-in-static-initializer-issue-38520.rs:12:23
+   |
+LL | static Y: usize = get(*&X);
+   |                       ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/move-in-static-initializer-issue-38520.rs:13:22
+   |
+LL | const Z: usize = get(*&X);
+   |                      ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/mut-borrow-in-loop-2.fixed b/tests/ui/borrowck/mut-borrow-in-loop-2.fixed
new file mode 100644
index 00000000000..ceeba30a90f
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-in-loop-2.fixed
@@ -0,0 +1,35 @@
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+    fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+    fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+    fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(&mut *value);
+    }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(&mut *value); //~ ERROR use of moved value: `value`
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/mut-borrow-in-loop-2.rs b/tests/ui/borrowck/mut-borrow-in-loop-2.rs
new file mode 100644
index 00000000000..d13fb7e5679
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-in-loop-2.rs
@@ -0,0 +1,35 @@
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+    fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+    fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+    fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(&mut *value);
+    }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(value); //~ ERROR use of moved value: `value`
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/mut-borrow-in-loop-2.stderr b/tests/ui/borrowck/mut-borrow-in-loop-2.stderr
new file mode 100644
index 00000000000..74e7067c9af
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-in-loop-2.stderr
@@ -0,0 +1,25 @@
+error[E0382]: use of moved value: `value`
+  --> $DIR/mut-borrow-in-loop-2.rs:31:23
+   |
+LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+   |                         ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait
+LL |     for _ in 0..3 {
+   |     ------------- inside of this loop
+LL |         Other::handle(value);
+   |                       ^^^^^ value moved here, in previous iteration of loop
+   |
+note: consider changing this parameter type in function `handle` to borrow instead if owning the value isn't necessary
+  --> $DIR/mut-borrow-in-loop-2.rs:9:22
+   |
+LL |     fn handle(value: T) -> Self;
+   |        ------        ^ this parameter takes ownership of the value
+   |        |
+   |        in this function
+help: consider creating a fresh reborrow of `value` here
+   |
+LL |         Other::handle(&mut *value);
+   |                       ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/mut-borrow-in-loop.rs b/tests/ui/borrowck/mut-borrow-in-loop.rs
new file mode 100644
index 00000000000..22667906e12
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-in-loop.rs
@@ -0,0 +1,29 @@
+// produce special borrowck message inside all kinds of loops
+
+struct FuncWrapper<'a, T : 'a> {
+    func : fn(&'a mut T) -> ()
+}
+
+impl<'a, T : 'a> FuncWrapper<'a, T> {
+    fn in_loop(self, arg : &'a mut T) {
+        loop {
+            (self.func)(arg) //~ ERROR cannot borrow
+        }
+    }
+
+    fn in_while(self, arg : &'a mut T) {
+        while true { //~ WARN denote infinite loops with
+            (self.func)(arg) //~ ERROR cannot borrow
+        }
+    }
+
+    fn in_for(self, arg : &'a mut T) {
+        let v : Vec<()> = vec![];
+        for _ in v.iter() {
+            (self.func)(arg) //~ ERROR cannot borrow
+        }
+    }
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/mut-borrow-in-loop.stderr b/tests/ui/borrowck/mut-borrow-in-loop.stderr
new file mode 100644
index 00000000000..b621694a548
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-in-loop.stderr
@@ -0,0 +1,47 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/mut-borrow-in-loop.rs:15:9
+   |
+LL |         while true {
+   |         ^^^^^^^^^^ help: use `loop`
+   |
+   = note: `#[warn(while_true)]` on by default
+
+error[E0499]: cannot borrow `*arg` as mutable more than once at a time
+  --> $DIR/mut-borrow-in-loop.rs:10:25
+   |
+LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
+   |      -- lifetime `'a` defined here
+...
+LL |             (self.func)(arg)
+   |             ------------^^^-
+   |             |           |
+   |             |           `*arg` was mutably borrowed here in the previous iteration of the loop
+   |             argument requires that `*arg` is borrowed for `'a`
+
+error[E0499]: cannot borrow `*arg` as mutable more than once at a time
+  --> $DIR/mut-borrow-in-loop.rs:16:25
+   |
+LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
+   |      -- lifetime `'a` defined here
+...
+LL |             (self.func)(arg)
+   |             ------------^^^-
+   |             |           |
+   |             |           `*arg` was mutably borrowed here in the previous iteration of the loop
+   |             argument requires that `*arg` is borrowed for `'a`
+
+error[E0499]: cannot borrow `*arg` as mutable more than once at a time
+  --> $DIR/mut-borrow-in-loop.rs:23:25
+   |
+LL | impl<'a, T : 'a> FuncWrapper<'a, T> {
+   |      -- lifetime `'a` defined here
+...
+LL |             (self.func)(arg)
+   |             ------------^^^-
+   |             |           |
+   |             |           `*arg` was mutably borrowed here in the previous iteration of the loop
+   |             argument requires that `*arg` is borrowed for `'a`
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/mut-borrow-of-mut-ref.rs b/tests/ui/borrowck/mut-borrow-of-mut-ref.rs
new file mode 100644
index 00000000000..477a2aa48d5
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-of-mut-ref.rs
@@ -0,0 +1,36 @@
+// Suggest not mutably borrowing a mutable reference
+#![crate_type = "rlib"]
+
+pub fn f(b: &mut i32) {
+    //~^ ERROR cannot borrow
+    //~| NOTE not mutable
+    //~| NOTE the binding is already a mutable borrow
+    h(&mut b);
+    //~^ NOTE cannot borrow as mutable
+    //~| HELP try removing `&mut` here
+    g(&mut &mut b);
+    //~^ NOTE cannot borrow as mutable
+    //~| HELP try removing `&mut` here
+}
+
+pub fn g(b: &mut i32) { //~ NOTE the binding is already a mutable borrow
+    h(&mut &mut b);
+    //~^ ERROR cannot borrow
+    //~| NOTE cannot borrow as mutable
+    //~| HELP try removing `&mut` here
+}
+
+pub fn h(_: &mut i32) {}
+
+trait Foo {
+    fn bar(&mut self);
+}
+
+impl Foo for &mut String {
+    fn bar(&mut self) {}
+}
+
+pub fn baz(f: &mut String) { //~ HELP consider making the binding mutable
+    f.bar(); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable
+    //~^ NOTE cannot borrow as mutable
+}
diff --git a/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr b/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr
new file mode 100644
index 00000000000..c6f75b1c0d0
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr
@@ -0,0 +1,59 @@
+error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
+  --> $DIR/mut-borrow-of-mut-ref.rs:4:10
+   |
+LL | pub fn f(b: &mut i32) {
+   |          ^ not mutable
+...
+LL |     h(&mut b);
+   |       ------ cannot borrow as mutable
+...
+LL |     g(&mut &mut b);
+   |            ------ cannot borrow as mutable
+   |
+note: the binding is already a mutable borrow
+  --> $DIR/mut-borrow-of-mut-ref.rs:4:13
+   |
+LL | pub fn f(b: &mut i32) {
+   |             ^^^^^^^^
+help: try removing `&mut` here
+   |
+LL -     h(&mut b);
+LL +     h(b);
+   |
+help: try removing `&mut` here
+   |
+LL -     g(&mut &mut b);
+LL +     g(&mut b);
+   |
+
+error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
+  --> $DIR/mut-borrow-of-mut-ref.rs:17:12
+   |
+LL |     h(&mut &mut b);
+   |            ^^^^^^ cannot borrow as mutable
+   |
+note: the binding is already a mutable borrow
+  --> $DIR/mut-borrow-of-mut-ref.rs:16:13
+   |
+LL | pub fn g(b: &mut i32) {
+   |             ^^^^^^^^
+help: try removing `&mut` here
+   |
+LL -     h(&mut &mut b);
+LL +     h(&mut b);
+   |
+
+error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
+  --> $DIR/mut-borrow-of-mut-ref.rs:34:5
+   |
+LL |     f.bar();
+   |     ^^^^^^^ cannot borrow as mutable
+   |
+help: consider making the binding mutable
+   |
+LL | pub fn baz(mut f: &mut String) {
+   |            +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/mut-borrow-outside-loop.rs b/tests/ui/borrowck/mut-borrow-outside-loop.rs
new file mode 100644
index 00000000000..c02bfbf8739
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-outside-loop.rs
@@ -0,0 +1,22 @@
+// ensure borrowck messages are correct outside special case
+#![feature(rustc_attrs)]
+fn main() { #![rustc_error] // rust-lang/rust#49855
+    let mut void = ();
+
+    let first = &mut void;
+    let second = &mut void; //~ ERROR cannot borrow
+    first.use_mut();
+    second.use_mut();
+
+    loop {
+        let mut inner_void = ();
+
+        let inner_first = &mut inner_void;
+        let inner_second = &mut inner_void; //~ ERROR cannot borrow
+        inner_second.use_mut();
+        inner_first.use_mut();
+    }
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
diff --git a/tests/ui/borrowck/mut-borrow-outside-loop.stderr b/tests/ui/borrowck/mut-borrow-outside-loop.stderr
new file mode 100644
index 00000000000..e6895b27f35
--- /dev/null
+++ b/tests/ui/borrowck/mut-borrow-outside-loop.stderr
@@ -0,0 +1,24 @@
+error[E0499]: cannot borrow `void` as mutable more than once at a time
+  --> $DIR/mut-borrow-outside-loop.rs:7:18
+   |
+LL |     let first = &mut void;
+   |                 --------- first mutable borrow occurs here
+LL |     let second = &mut void;
+   |                  ^^^^^^^^^ second mutable borrow occurs here
+LL |     first.use_mut();
+   |     --------------- first borrow later used here
+
+error[E0499]: cannot borrow `inner_void` as mutable more than once at a time
+  --> $DIR/mut-borrow-outside-loop.rs:15:28
+   |
+LL |         let inner_first = &mut inner_void;
+   |                           --------------- first mutable borrow occurs here
+LL |         let inner_second = &mut inner_void;
+   |                            ^^^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |         inner_second.use_mut();
+LL |         inner_first.use_mut();
+   |         --------------------- first borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/mutability-errors.rs b/tests/ui/borrowck/mutability-errors.rs
new file mode 100644
index 00000000000..82116425f06
--- /dev/null
+++ b/tests/ui/borrowck/mutability-errors.rs
@@ -0,0 +1,82 @@
+// All the possible mutability error cases.
+
+#![allow(unused)]
+
+type MakeRef = fn() -> &'static (i32,);
+type MakePtr = fn() -> *const (i32,);
+
+fn named_ref(x: &(i32,)) {
+    *x = (1,); //~ ERROR
+    x.0 = 1; //~ ERROR
+    &mut *x; //~ ERROR
+    &mut x.0; //~ ERROR
+}
+
+fn unnamed_ref(f: MakeRef) {
+    *f() = (1,); //~ ERROR
+    f().0 = 1; //~ ERROR
+    &mut *f(); //~ ERROR
+    &mut f().0; //~ ERROR
+}
+
+unsafe fn named_ptr(x: *const (i32,)) {
+    *x = (1,); //~ ERROR
+    (*x).0 = 1; //~ ERROR
+    &mut *x; //~ ERROR
+    &mut (*x).0; //~ ERROR
+}
+
+unsafe fn unnamed_ptr(f: MakePtr) {
+    *f() = (1,); //~ ERROR
+    (*f()).0 = 1; //~ ERROR
+    &mut *f(); //~ ERROR
+    &mut (*f()).0; //~ ERROR
+}
+
+fn fn_ref<F: Fn()>(f: F) -> F { f }
+
+fn ref_closure(mut x: (i32,)) {
+    fn_ref(|| {
+        x = (1,); //~ ERROR
+        x.0 = 1; //~ ERROR
+        &mut x; //~ ERROR
+        &mut x.0; //~ ERROR
+    });
+    fn_ref(move || {
+        x = (1,); //~ ERROR
+        x.0 = 1; //~ ERROR
+        &mut x; //~ ERROR
+        &mut x.0; //~ ERROR
+    });
+}
+
+fn imm_local(x: (i32,)) { //~ ERROR
+    &mut x;
+    &mut x.0;
+}
+
+fn imm_capture(x: (i32,)) {
+    || {
+        x = (1,); //~ ERROR
+        x.0 = 1; //~ ERROR
+        &mut x; //~ ERROR
+        &mut x.0; //~ ERROR
+    };
+    move || {
+        x = (1,); //~ ERROR
+        x.0 = 1; //~ ERROR
+        &mut x; //~ ERROR
+        &mut x.0; //~ ERROR
+    };
+}
+
+static X: (i32,) = (0,);
+
+fn imm_static() {
+    X = (1,); //~ ERROR
+    X.0 = 1; //~ ERROR
+    &mut X; //~ ERROR
+    &mut X.0; //~ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/mutability-errors.stderr b/tests/ui/borrowck/mutability-errors.stderr
new file mode 100644
index 00000000000..d7c602718f1
--- /dev/null
+++ b/tests/ui/borrowck/mutability-errors.stderr
@@ -0,0 +1,361 @@
+error[E0594]: cannot assign to `*x`, which is behind a `&` reference
+  --> $DIR/mutability-errors.rs:9:5
+   |
+LL |     *x = (1,);
+   |     ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
+
+error[E0594]: cannot assign to `x.0`, which is behind a `&` reference
+  --> $DIR/mutability-errors.rs:10:5
+   |
+LL |     x.0 = 1;
+   |     ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
+
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
+  --> $DIR/mutability-errors.rs:11:5
+   |
+LL |     &mut *x;
+   |     ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
+
+error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference
+  --> $DIR/mutability-errors.rs:12:5
+   |
+LL |     &mut x.0;
+   |     ^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
+
+error[E0594]: cannot assign to data in a `&` reference
+  --> $DIR/mutability-errors.rs:16:5
+   |
+LL |     *f() = (1,);
+   |     ^^^^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to data in a `&` reference
+  --> $DIR/mutability-errors.rs:17:5
+   |
+LL |     f().0 = 1;
+   |     ^^^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/mutability-errors.rs:18:5
+   |
+LL |     &mut *f();
+   |     ^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/mutability-errors.rs:19:5
+   |
+LL |     &mut f().0;
+   |     ^^^^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to `*x`, which is behind a `*const` pointer
+  --> $DIR/mutability-errors.rs:23:5
+   |
+LL |     *x = (1,);
+   |     ^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
+
+error[E0594]: cannot assign to `x.0`, which is behind a `*const` pointer
+  --> $DIR/mutability-errors.rs:24:5
+   |
+LL |     (*x).0 = 1;
+   |     ^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
+
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
+  --> $DIR/mutability-errors.rs:25:5
+   |
+LL |     &mut *x;
+   |     ^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
+
+error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer
+  --> $DIR/mutability-errors.rs:26:5
+   |
+LL |     &mut (*x).0;
+   |     ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
+
+error[E0594]: cannot assign to data in a `*const` pointer
+  --> $DIR/mutability-errors.rs:30:5
+   |
+LL |     *f() = (1,);
+   |     ^^^^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to data in a `*const` pointer
+  --> $DIR/mutability-errors.rs:31:5
+   |
+LL |     (*f()).0 = 1;
+   |     ^^^^^^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow data in a `*const` pointer as mutable
+  --> $DIR/mutability-errors.rs:32:5
+   |
+LL |     &mut *f();
+   |     ^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `*const` pointer as mutable
+  --> $DIR/mutability-errors.rs:33:5
+   |
+LL |     &mut (*f()).0;
+   |     ^^^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
+  --> $DIR/mutability-errors.rs:40:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+   |         ^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables
+  --> $DIR/mutability-errors.rs:41:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+LL |         x.0 = 1;
+   |         ^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/mutability-errors.rs:42:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+...
+LL |         &mut x;
+   |         ^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables
+  --> $DIR/mutability-errors.rs:43:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+...
+LL |         &mut x.0;
+   |         ^^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
+  --> $DIR/mutability-errors.rs:46:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+   |         ^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables
+  --> $DIR/mutability-errors.rs:47:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+LL |         x.0 = 1;
+   |         ^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/mutability-errors.rs:48:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+...
+LL |         &mut x;
+   |         ^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables
+  --> $DIR/mutability-errors.rs:49:9
+   |
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+...
+LL |         &mut x.0;
+   |         ^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/mutability-errors.rs:53:14
+   |
+LL | fn imm_local(x: (i32,)) {
+   |              ^ not mutable
+LL |     &mut x;
+   |     ------ cannot borrow as mutable
+LL |     &mut x.0;
+   |     -------- cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_local(mut x: (i32,)) {
+   |              +++
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+  --> $DIR/mutability-errors.rs:60:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+LL |     || {
+LL |         x = (1,);
+   |         ^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
+  --> $DIR/mutability-errors.rs:61:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+...
+LL |         x.0 = 1;
+   |         ^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/mutability-errors.rs:62:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+...
+LL |         &mut x;
+   |         ^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
+  --> $DIR/mutability-errors.rs:63:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+...
+LL |         &mut x.0;
+   |         ^^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+  --> $DIR/mutability-errors.rs:66:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+...
+LL |         x = (1,);
+   |         ^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
+  --> $DIR/mutability-errors.rs:67:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+...
+LL |         x.0 = 1;
+   |         ^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/mutability-errors.rs:68:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+...
+LL |         &mut x;
+   |         ^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
+  --> $DIR/mutability-errors.rs:69:9
+   |
+LL | fn imm_capture(x: (i32,)) {
+   |                - help: consider changing this to be mutable: `mut x`
+...
+LL |         &mut x.0;
+   |         ^^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to immutable static item `X`
+  --> $DIR/mutability-errors.rs:76:5
+   |
+LL |     X = (1,);
+   |     ^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `X.0`, as `X` is an immutable static item
+  --> $DIR/mutability-errors.rs:77:5
+   |
+LL |     X.0 = 1;
+   |     ^^^^^^^ cannot assign
+
+error[E0596]: cannot borrow immutable static item `X` as mutable
+  --> $DIR/mutability-errors.rs:78:5
+   |
+LL |     &mut X;
+   |     ^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `X.0` as mutable, as `X` is an immutable static item
+  --> $DIR/mutability-errors.rs:79:5
+   |
+LL |     &mut X.0;
+   |     ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 37 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/borrowck/or-patterns.rs b/tests/ui/borrowck/or-patterns.rs
new file mode 100644
index 00000000000..aeab3b92e98
--- /dev/null
+++ b/tests/ui/borrowck/or-patterns.rs
@@ -0,0 +1,62 @@
+// Test that borrow check considers all choices in an or pattern, even the
+// unreachable ones.
+
+fn or_pattern_moves_all(x: ((String, String),)) {
+    match x {
+        ((y, _) | (_, y),) => (),
+    }
+    &x.0 .0;
+    //~^ ERROR borrow of moved value
+    &x.0 .1;
+    //~^ ERROR borrow of moved value
+}
+
+fn or_pattern_borrows_all(mut x: ((String, String),)) {
+    let r = match x {
+        ((ref y, _) | (_, ref y),) => y,
+    };
+    &mut x.0 .0;
+    //~^ ERROR cannot borrow
+    &mut x.0 .1;
+    //~^ ERROR cannot borrow
+    drop(r);
+}
+
+fn or_pattern_borrows_all_mut(mut x: ((String, String),)) {
+    let r = match x {
+        ((ref mut y, _) | (_, ref mut y),) => y,
+    };
+    &x.0 .0;
+    //~^ ERROR cannot borrow
+    &x.0 .1;
+    //~^ ERROR cannot borrow
+    drop(r);
+}
+
+fn let_or_pattern_moves_all(x: ((String, String),)) {
+    let ((y, _) | (_, y),) = x;
+    &x.0 .0;
+    //~^ ERROR borrow of moved value
+    &x.0 .1;
+    //~^ ERROR borrow of moved value
+}
+
+fn let_or_pattern_borrows_all(mut x: ((String, String),)) {
+    let ((ref r, _) | (_, ref r),) = x;
+    &mut x.0 .0;
+    //~^ ERROR cannot borrow
+    &mut x.0 .1;
+    //~^ ERROR cannot borrow
+    drop(r);
+}
+
+fn let_or_pattern_borrows_all_mut(mut x: ((String, String),)) {
+    let ((ref mut r, _) | (_, ref mut r),) = x;
+    &x.0 .0;
+    //~^ ERROR cannot borrow
+    &x.0 .1;
+    //~^ ERROR cannot borrow
+    drop(r);
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/or-patterns.stderr b/tests/ui/borrowck/or-patterns.stderr
new file mode 100644
index 00000000000..9501798bb06
--- /dev/null
+++ b/tests/ui/borrowck/or-patterns.stderr
@@ -0,0 +1,157 @@
+error[E0382]: borrow of moved value: `x.0.0`
+  --> $DIR/or-patterns.rs:8:5
+   |
+LL |         ((y, _) | (_, y),) => (),
+   |           - value moved here
+LL |     }
+LL |     &x.0 .0;
+   |     ^^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ((ref y, _) | (_, y),) => (),
+   |           +++
+
+error[E0382]: borrow of moved value: `x.0.1`
+  --> $DIR/or-patterns.rs:10:5
+   |
+LL |         ((y, _) | (_, y),) => (),
+   |                       - value moved here
+...
+LL |     &x.0 .1;
+   |     ^^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ((y, _) | (_, ref y),) => (),
+   |                       +++
+
+error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
+  --> $DIR/or-patterns.rs:18:5
+   |
+LL |         ((ref y, _) | (_, ref y),) => y,
+   |           ----- immutable borrow occurs here
+LL |     };
+LL |     &mut x.0 .0;
+   |     ^^^^^^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable
+  --> $DIR/or-patterns.rs:20:5
+   |
+LL |         ((ref y, _) | (_, ref y),) => y,
+   |                           ----- immutable borrow occurs here
+...
+LL |     &mut x.0 .1;
+   |     ^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable
+  --> $DIR/or-patterns.rs:29:5
+   |
+LL |         ((ref mut y, _) | (_, ref mut y),) => y,
+   |           --------- mutable borrow occurs here
+LL |     };
+LL |     &x.0 .0;
+   |     ^^^^^^^ immutable borrow occurs here
+...
+LL |     drop(r);
+   |          - mutable borrow later used here
+
+error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable
+  --> $DIR/or-patterns.rs:31:5
+   |
+LL |         ((ref mut y, _) | (_, ref mut y),) => y,
+   |                               --------- mutable borrow occurs here
+...
+LL |     &x.0 .1;
+   |     ^^^^^^^ immutable borrow occurs here
+LL |
+LL |     drop(r);
+   |          - mutable borrow later used here
+
+error[E0382]: borrow of moved value: `x.0.0`
+  --> $DIR/or-patterns.rs:38:5
+   |
+LL |     let ((y, _) | (_, y),) = x;
+   |           - value moved here
+LL |     &x.0 .0;
+   |     ^^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((ref y, _) | (_, y),) = x;
+   |           +++
+
+error[E0382]: borrow of moved value: `x.0.1`
+  --> $DIR/or-patterns.rs:40:5
+   |
+LL |     let ((y, _) | (_, y),) = x;
+   |                       - value moved here
+...
+LL |     &x.0 .1;
+   |     ^^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((y, _) | (_, ref y),) = x;
+   |                       +++
+
+error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
+  --> $DIR/or-patterns.rs:46:5
+   |
+LL |     let ((ref r, _) | (_, ref r),) = x;
+   |           ----- immutable borrow occurs here
+LL |     &mut x.0 .0;
+   |     ^^^^^^^^^^^ mutable borrow occurs here
+...
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable
+  --> $DIR/or-patterns.rs:48:5
+   |
+LL |     let ((ref r, _) | (_, ref r),) = x;
+   |                           ----- immutable borrow occurs here
+...
+LL |     &mut x.0 .1;
+   |     ^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |     drop(r);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable
+  --> $DIR/or-patterns.rs:55:5
+   |
+LL |     let ((ref mut r, _) | (_, ref mut r),) = x;
+   |           --------- mutable borrow occurs here
+LL |     &x.0 .0;
+   |     ^^^^^^^ immutable borrow occurs here
+...
+LL |     drop(r);
+   |          - mutable borrow later used here
+
+error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable
+  --> $DIR/or-patterns.rs:57:5
+   |
+LL |     let ((ref mut r, _) | (_, ref mut r),) = x;
+   |                               --------- mutable borrow occurs here
+...
+LL |     &x.0 .1;
+   |     ^^^^^^^ immutable borrow occurs here
+LL |
+LL |     drop(r);
+   |          - mutable borrow later used here
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0382, E0502.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs
new file mode 100644
index 00000000000..3576734de3c
--- /dev/null
+++ b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs
@@ -0,0 +1,31 @@
+// Test that we fail to promote the constant here which has a `ref
+// mut` borrow.
+
+fn gimme_static_mut_let() -> &'static mut u32 {
+    let ref mut x = 1234543;
+    x //~ ERROR
+}
+
+fn gimme_static_mut_let_nested() -> &'static mut u32 {
+    let (ref mut x, ) = (1234543, );
+    x //~ ERROR
+}
+
+fn gimme_static_mut_match() -> &'static mut u32 {
+    match 1234543 { //~ ERROR
+        ref mut x => x
+    }
+}
+
+fn gimme_static_mut_match_nested() -> &'static mut u32 {
+    match (123443,) { //~ ERROR
+        (ref mut x,) => x,
+    }
+}
+
+fn gimme_static_mut_ampersand() -> &'static mut u32 {
+    &mut 1234543 //~ ERROR
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr
new file mode 100644
index 00000000000..60af4123735
--- /dev/null
+++ b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr
@@ -0,0 +1,50 @@
+error[E0515]: cannot return value referencing temporary value
+  --> $DIR/promote-ref-mut-in-let-issue-46557.rs:6:5
+   |
+LL |     let ref mut x = 1234543;
+   |                     ------- temporary value created here
+LL |     x
+   |     ^ returns a value referencing data owned by the current function
+
+error[E0515]: cannot return value referencing temporary value
+  --> $DIR/promote-ref-mut-in-let-issue-46557.rs:11:5
+   |
+LL |     let (ref mut x, ) = (1234543, );
+   |                         ----------- temporary value created here
+LL |     x
+   |     ^ returns a value referencing data owned by the current function
+
+error[E0515]: cannot return value referencing temporary value
+  --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:5
+   |
+LL |       match 1234543 {
+   |       ^     ------- temporary value created here
+   |  _____|
+   | |
+LL | |         ref mut x => x
+LL | |     }
+   | |_____^ returns a value referencing data owned by the current function
+
+error[E0515]: cannot return value referencing temporary value
+  --> $DIR/promote-ref-mut-in-let-issue-46557.rs:21:5
+   |
+LL |       match (123443,) {
+   |       ^     --------- temporary value created here
+   |  _____|
+   | |
+LL | |         (ref mut x,) => x,
+LL | |     }
+   | |_____^ returns a value referencing data owned by the current function
+
+error[E0515]: cannot return reference to temporary value
+  --> $DIR/promote-ref-mut-in-let-issue-46557.rs:27:5
+   |
+LL |     &mut 1234543
+   |     ^^^^^-------
+   |     |    |
+   |     |    temporary value created here
+   |     returns a reference to data owned by the current function
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/reassignment_immutable_fields.rs b/tests/ui/borrowck/reassignment_immutable_fields.rs
new file mode 100644
index 00000000000..fd2ab62a40f
--- /dev/null
+++ b/tests/ui/borrowck/reassignment_immutable_fields.rs
@@ -0,0 +1,20 @@
+// This test is currently disallowed, but we hope someday to support it.
+//
+// FIXME(#21232)
+
+fn assign_both_fields_and_use() {
+    let x: (u32, u32);
+    x.0 = 1; //~ ERROR
+    x.1 = 22;
+    drop(x.0);
+    drop(x.1);
+}
+
+fn assign_both_fields_the_use_var() {
+    let x: (u32, u32);
+    x.0 = 1; //~ ERROR
+    x.1 = 22;
+    drop(x);
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/reassignment_immutable_fields.stderr b/tests/ui/borrowck/reassignment_immutable_fields.stderr
new file mode 100644
index 00000000000..e6b25573e70
--- /dev/null
+++ b/tests/ui/borrowck/reassignment_immutable_fields.stderr
@@ -0,0 +1,23 @@
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/reassignment_immutable_fields.rs:7:5
+   |
+LL |     let x: (u32, u32);
+   |         - binding declared here but left uninitialized
+LL |     x.0 = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/reassignment_immutable_fields.rs:15:5
+   |
+LL |     let x: (u32, u32);
+   |         - binding declared here but left uninitialized
+LL |     x.0 = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/reassignment_immutable_fields_overlapping.rs b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.rs
new file mode 100644
index 00000000000..d7aad6c01bd
--- /dev/null
+++ b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.rs
@@ -0,0 +1,16 @@
+// This should never be allowed -- `foo.a` and `foo.b` are
+// overlapping, so since `x` is not `mut` we should not permit
+// reassignment.
+
+union Foo {
+    a: u32,
+    b: u32,
+}
+
+unsafe fn overlapping_fields() {
+    let x: Foo;
+    x.a = 1;  //~ ERROR
+    x.b = 22; //~ ERROR
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
new file mode 100644
index 00000000000..81e5bc45d4d
--- /dev/null
+++ b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
@@ -0,0 +1,25 @@
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/reassignment_immutable_fields_overlapping.rs:12:5
+   |
+LL |     let x: Foo;
+   |         - binding declared here but left uninitialized
+LL |     x.a = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
+  --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5
+   |
+LL |     x.b = 22;
+   |     ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: Foo;
+   |         +++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0381, E0594.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/reassignment_immutable_fields_twice.rs b/tests/ui/borrowck/reassignment_immutable_fields_twice.rs
new file mode 100644
index 00000000000..2775a54c830
--- /dev/null
+++ b/tests/ui/borrowck/reassignment_immutable_fields_twice.rs
@@ -0,0 +1,17 @@
+// This should never be allowed -- since `x` is not `mut`, so `x.0`
+// cannot be assigned twice.
+
+fn var_then_field() {
+    let x: (u32, u32);
+    x = (22, 44);
+    x.0 = 1; //~ ERROR
+}
+
+fn same_field_twice() {
+    let x: (u32, u32);
+    x.0 = 1; //~ ERROR
+    x.0 = 22;
+    x.1 = 44;
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/reassignment_immutable_fields_twice.stderr b/tests/ui/borrowck/reassignment_immutable_fields_twice.stderr
new file mode 100644
index 00000000000..ba0457809ad
--- /dev/null
+++ b/tests/ui/borrowck/reassignment_immutable_fields_twice.stderr
@@ -0,0 +1,25 @@
+error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
+  --> $DIR/reassignment_immutable_fields_twice.rs:7:5
+   |
+LL |     x.0 = 1;
+   |     ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: (u32, u32);
+   |         +++
+
+error[E0381]: partially assigned binding `x` isn't fully initialized
+  --> $DIR/reassignment_immutable_fields_twice.rs:12:5
+   |
+LL |     let x: (u32, u32);
+   |         - binding declared here but left uninitialized
+LL |     x.0 = 1;
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0381, E0594.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/reborrow-sugg-move-then-borrow.rs b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.rs
new file mode 100644
index 00000000000..31eba074008
--- /dev/null
+++ b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.rs
@@ -0,0 +1,26 @@
+// Tests the suggestion to reborrow the first move site
+// when we move then borrow a `&mut` ref.
+
+struct State;
+
+impl IntoIterator for &mut State {
+    type IntoIter = std::vec::IntoIter<()>;
+    type Item = ();
+
+    fn into_iter(self) -> Self::IntoIter {
+        vec![].into_iter()
+    }
+}
+
+fn once(f: impl FnOnce()) {}
+
+fn fill_memory_blocks_mt(state: &mut State) {
+    for _ in state {}
+    //~^ HELP consider creating a fresh reborrow of `state` here
+    fill_segment(state);
+    //~^ ERROR borrow of moved value: `state`
+}
+
+fn fill_segment(state: &mut State) {}
+
+fn main() {}
diff --git a/tests/ui/borrowck/reborrow-sugg-move-then-borrow.stderr b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.stderr
new file mode 100644
index 00000000000..ecd916a59fc
--- /dev/null
+++ b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.stderr
@@ -0,0 +1,21 @@
+error[E0382]: borrow of moved value: `state`
+  --> $DIR/reborrow-sugg-move-then-borrow.rs:20:18
+   |
+LL | fn fill_memory_blocks_mt(state: &mut State) {
+   |                          ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait
+LL |     for _ in state {}
+   |              ----- `state` moved due to this implicit call to `.into_iter()`
+LL |
+LL |     fill_segment(state);
+   |                  ^^^^^ value borrowed here after move
+   |
+note: `into_iter` takes ownership of the receiver `self`, which moves `state`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: consider creating a fresh reborrow of `state` here
+   |
+LL |     for _ in &mut *state {}
+   |              ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs
new file mode 100644
index 00000000000..141ad5bd2c4
--- /dev/null
+++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs
@@ -0,0 +1,54 @@
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+struct Inv<'a> { // invariant w/r/t 'a
+    x: &'a mut &'a isize
+}
+
+pub trait Foo<'a, 't> {
+    fn no_bound<'b>(self, b: Inv<'b>);
+    fn has_bound<'b:'a>(self, b: Inv<'b>);
+    fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+}
+
+impl<'a, 't> Foo<'a, 't> for &'a isize {
+    fn no_bound<'b:'a>(self, b: Inv<'b>) {
+        //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
+    }
+
+    fn has_bound<'b>(self, b: Inv<'b>) {
+        //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
+    }
+
+    fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+        //~^ ERROR method not compatible with trait
+        //~| ERROR method not compatible with trait
+        //
+        // Note: This is a terrible error message. It is caused
+        // because, in the trait, 'b is early bound, and in the impl,
+        // 'c is early bound, so -- after substitution -- the
+        // lifetimes themselves look isomorphic.  We fail because the
+        // lifetimes that appear in the types are in the wrong
+        // order. This should really be fixed by keeping more
+        // information about the lifetime declarations in the trait so
+        // that we can compare better to the impl, even in cross-crate
+        // cases.
+    }
+
+    fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
+        //~^ ERROR lifetime parameters or bounds on method `wrong_bound2` do not match the trait
+    }
+
+    fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
+    }
+
+    fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+        //~^ ERROR E0276
+    }
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
new file mode 100644
index 00000000000..930fea9158d
--- /dev/null
+++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
@@ -0,0 +1,78 @@
+error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:19:16
+   |
+LL |     fn no_bound<'b>(self, b: Inv<'b>);
+   |                ---- lifetimes in impl do not match this method in trait
+...
+LL |     fn no_bound<'b:'a>(self, b: Inv<'b>) {
+   |                ^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:23:17
+   |
+LL |     fn has_bound<'b:'a>(self, b: Inv<'b>);
+   |                 ------- lifetimes in impl do not match this method in trait
+...
+LL |     fn has_bound<'b>(self, b: Inv<'b>) {
+   |                 ^^^^ lifetimes do not match method in trait
+
+error[E0308]: method not compatible with trait
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:5
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
+              found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
+note: the lifetime `'c` as defined here...
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |                        ^^
+note: ...does not necessarily outlive the lifetime `'c` as defined here
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |                        ^^
+
+error[E0308]: method not compatible with trait
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:5
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
+              found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
+note: the lifetime `'c` as defined here...
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |                        ^^
+note: ...does not necessarily outlive the lifetime `'c` as defined here
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |                        ^^
+
+error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:42:20
+   |
+LL |     fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+   |                    ---------------- lifetimes in impl do not match this method in trait
+...
+LL |     fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
+   |                    ^ lifetimes do not match method in trait
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:49:26
+   |
+LL |     fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+   |     ------------------------------------------------------- definition of `another_bound` from trait
+...
+LL |     fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+   |                          ^^ impl has extra requirement `'x: 't`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0195, E0276, E0308.
+For more information about an error, try `rustc --explain E0195`.
diff --git a/tests/ui/borrowck/regions-escape-bound-fn-2.rs b/tests/ui/borrowck/regions-escape-bound-fn-2.rs
new file mode 100644
index 00000000000..0e98d98cf87
--- /dev/null
+++ b/tests/ui/borrowck/regions-escape-bound-fn-2.rs
@@ -0,0 +1,13 @@
+fn with_int<F>(f: F)
+where
+    F: FnOnce(&isize),
+{
+    let x = 3;
+    f(&x);
+}
+
+fn main() {
+    let mut x = None;
+    with_int(|y| x = Some(y));
+    //~^ ERROR borrowed data escapes outside of closure
+}
diff --git a/tests/ui/borrowck/regions-escape-bound-fn-2.stderr b/tests/ui/borrowck/regions-escape-bound-fn-2.stderr
new file mode 100644
index 00000000000..14393bc8eee
--- /dev/null
+++ b/tests/ui/borrowck/regions-escape-bound-fn-2.stderr
@@ -0,0 +1,13 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-bound-fn-2.rs:11:18
+   |
+LL |     let mut x = None;
+   |         ----- `x` declared here, outside of the closure body
+LL |     with_int(|y| x = Some(y));
+   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |               |
+   |               `y` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/borrowck/regions-escape-bound-fn.rs b/tests/ui/borrowck/regions-escape-bound-fn.rs
new file mode 100644
index 00000000000..f896ae7bdad
--- /dev/null
+++ b/tests/ui/borrowck/regions-escape-bound-fn.rs
@@ -0,0 +1,13 @@
+fn with_int<F>(f: F)
+where
+    F: FnOnce(&isize),
+{
+    let x = 3;
+    f(&x);
+}
+
+fn main() {
+    let mut x: Option<&isize> = None;
+    with_int(|y| x = Some(y));
+    //~^ ERROR borrowed data escapes outside of closure
+}
diff --git a/tests/ui/borrowck/regions-escape-bound-fn.stderr b/tests/ui/borrowck/regions-escape-bound-fn.stderr
new file mode 100644
index 00000000000..a23fdacdee6
--- /dev/null
+++ b/tests/ui/borrowck/regions-escape-bound-fn.stderr
@@ -0,0 +1,13 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-bound-fn.rs:11:18
+   |
+LL |     let mut x: Option<&isize> = None;
+   |         ----- `x` declared here, outside of the closure body
+LL |     with_int(|y| x = Some(y));
+   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |               |
+   |               `y` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/borrowck/regions-escape-unboxed-closure.rs b/tests/ui/borrowck/regions-escape-unboxed-closure.rs
new file mode 100644
index 00000000000..f01e47122d1
--- /dev/null
+++ b/tests/ui/borrowck/regions-escape-unboxed-closure.rs
@@ -0,0 +1,7 @@
+fn with_int(f: &mut dyn FnMut(&isize)) {}
+
+fn main() {
+    let mut x: Option<&isize> = None;
+    with_int(&mut |y| x = Some(y));
+    //~^ ERROR borrowed data escapes outside of closure
+}
diff --git a/tests/ui/borrowck/regions-escape-unboxed-closure.stderr b/tests/ui/borrowck/regions-escape-unboxed-closure.stderr
new file mode 100644
index 00000000000..153f77c8913
--- /dev/null
+++ b/tests/ui/borrowck/regions-escape-unboxed-closure.stderr
@@ -0,0 +1,13 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-unboxed-closure.rs:5:23
+   |
+LL |     let mut x: Option<&isize> = None;
+   |         ----- `x` declared here, outside of the closure body
+LL |     with_int(&mut |y| x = Some(y));
+   |                    -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |                    |
+   |                    `y` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/borrowck/return-local-binding-from-desugaring.rs b/tests/ui/borrowck/return-local-binding-from-desugaring.rs
new file mode 100644
index 00000000000..c6643edf5a9
--- /dev/null
+++ b/tests/ui/borrowck/return-local-binding-from-desugaring.rs
@@ -0,0 +1,33 @@
+// To avoid leaking the names of local bindings from expressions like for loops, #60984
+// explicitly ignored them, but an assertion that `LocalKind::Var` *must* have a name would
+// trigger an ICE. Before this change, this file's output would be:
+// ```
+// error[E0515]: cannot return value referencing local variable `__next`
+//   --> return-local-binding-from-desugaring.rs:LL:CC
+//    |
+// LL |     for ref x in xs {
+//    |         ----- `__next` is borrowed here
+// ...
+// LL |     result
+//    |     ^^^^^^ returns a value referencing data owned by the current function
+// ```
+// FIXME: ideally `LocalKind` would carry more information to more accurately explain the problem.
+
+use std::collections::HashMap;
+use std::hash::Hash;
+
+fn group_by<I, F, T>(xs: &mut I, f: F) -> HashMap<T, Vec<&I::Item>>
+where
+    I: Iterator,
+    F: Fn(&I::Item) -> T,
+    T: Eq + Hash,
+{
+    let mut result = HashMap::new();
+    for ref x in xs {
+        let key = f(x);
+        result.entry(key).or_insert(Vec::new()).push(x);
+    }
+    result //~ ERROR cannot return value referencing temporary value
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/return-local-binding-from-desugaring.stderr b/tests/ui/borrowck/return-local-binding-from-desugaring.stderr
new file mode 100644
index 00000000000..9f952542e18
--- /dev/null
+++ b/tests/ui/borrowck/return-local-binding-from-desugaring.stderr
@@ -0,0 +1,12 @@
+error[E0515]: cannot return value referencing temporary value
+  --> $DIR/return-local-binding-from-desugaring.rs:30:5
+   |
+LL |     for ref x in xs {
+   |                  -- temporary value created here
+...
+LL |     result
+   |     ^^^^^^ returns a value referencing data owned by the current function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/borrowck/slice-index-bounds-check-invalidation.rs b/tests/ui/borrowck/slice-index-bounds-check-invalidation.rs
new file mode 100644
index 00000000000..0e0e3cda6e2
--- /dev/null
+++ b/tests/ui/borrowck/slice-index-bounds-check-invalidation.rs
@@ -0,0 +1,82 @@
+// Test that we error if a slice is modified after it has been bounds checked
+// and before we actually index it.
+
+fn modify_before_assert_slice_slice(x: &[&[i32]]) -> i32 {
+    let mut x = x;
+    let z: &[i32] = &[1, 2, 3];
+    let y: &[&[i32]] = &[z];
+    x[{ x = y; 0 }][2]              // OK we haven't checked any bounds before we index `x`.
+}
+
+fn modify_before_assert_array_slice(x: &[&[i32]; 3]) -> i32 {
+    let mut x = x;
+    let z: &[i32] = &[1, 2, 3];
+    let y: &[&[i32]; 3] = &[z, z, z];
+    x[{ x = y; 0 }][2]              // OK we haven't checked any bounds before we index `x`.
+}
+
+fn modify_before_assert_slice_array(x: &[&[i32; 3]]) -> i32 {
+    let mut x = x;
+    let z: &[i32; 3] = &[1, 2, 3];
+    let y: &[&[i32; 3]] = &[z];
+    x[{ x = y; 0 }][2]              // OK we haven't checked any bounds before we index `x`.
+}
+
+fn modify_before_assert_array_array(x: &[&[i32; 3]; 3]) -> i32 {
+    let mut x = x;
+    let z: &[i32; 3] = &[1, 2, 3];
+    let y: &[&[i32; 3]; 3] = &[z, z, z];
+    x[{ x = y; 0 }][2]              // OK we haven't checked any bounds before we index `x`.
+}
+
+fn modify_after_assert_slice_slice(x: &[&[i32]]) -> i32 {
+    let mut x = x;
+    let z: &[i32] = &[1, 2, 3];
+    let y: &[&[i32]] = &[&z];
+    x[1][{ x = y; 2}]               //~ ERROR cannot assign `x` in indexing expression
+}
+
+fn modify_after_assert_array_slice(x: &[&[i32]; 1]) -> i32 {
+    let mut x = x;
+    let z: &[i32] = &[1, 2, 3];
+    let y: &[&[i32]; 1] = &[&z];
+    x[0][{ x = y; 2}]               // OK cannot invalidate a fixed-size array bounds check
+}
+
+fn modify_after_assert_slice_array(x: &[&[i32; 3]]) -> i32 {
+    let mut x = x;
+    let z: &[i32; 3] = &[1, 2, 3];
+    let y: &[&[i32; 3]] = &[&z];
+    x[1][{ x = y; 2}]               //~ ERROR cannot assign `x` in indexing expression
+}
+
+fn modify_after_assert_array_array(x: &[&[i32; 3]; 1]) -> i32 {
+    let mut x = x;
+    let z: &[i32; 3] = &[1, 2, 3];
+    let y: &[&[i32; 3]; 1] = &[&z];
+    x[0][{ x = y; 2}]               // OK cannot invalidate a fixed-size array bounds check
+}
+
+fn modify_after_assert_slice_slice_array(x: &[&[[i32; 1]]]) -> i32 {
+    let mut x = x;
+    let z: &[[i32; 1]] = &[[1], [2], [3]];
+    let y: &[&[[i32; 1]]] = &[&z];
+    x[1][{ x = y; 2}][0]            //~ ERROR cannot assign `x` in indexing expression
+}
+
+fn modify_after_assert_slice_slice_slice(x: &[&[&[i32]]]) -> i32 {
+    let mut x = x;
+    let z: &[&[i32]] = &[&[1], &[2], &[3]];
+    let y: &[&[&[i32]]] = &[z];
+    x[1][{ x = y; 2}][0]            //~ ERROR cannot assign `x` in indexing expression
+}
+
+
+fn main() {
+    println!("{}", modify_after_assert_slice_array(&[&[4, 5, 6], &[9, 10, 11]]));
+    println!("{}", modify_after_assert_slice_slice(&[&[4, 5, 6], &[9, 10, 11]]));
+    println!("{}", modify_after_assert_slice_slice_array(&[&[[4], [5], [6]], &[[9], [10], [11]]]));
+    println!("{}", modify_after_assert_slice_slice_slice(
+        &[&[&[4], &[5], &[6]], &[&[9], &[10], &[11]]]),
+    );
+}
diff --git a/tests/ui/borrowck/slice-index-bounds-check-invalidation.stderr b/tests/ui/borrowck/slice-index-bounds-check-invalidation.stderr
new file mode 100644
index 00000000000..f9ed16f19cd
--- /dev/null
+++ b/tests/ui/borrowck/slice-index-bounds-check-invalidation.stderr
@@ -0,0 +1,35 @@
+error[E0510]: cannot assign `x` in indexing expression
+  --> $DIR/slice-index-bounds-check-invalidation.rs:36:12
+   |
+LL |     x[1][{ x = y; 2}]
+   |     ----   ^^^^^ cannot assign
+   |     |
+   |     value is immutable in indexing expression
+
+error[E0510]: cannot assign `x` in indexing expression
+  --> $DIR/slice-index-bounds-check-invalidation.rs:50:12
+   |
+LL |     x[1][{ x = y; 2}]
+   |     ----   ^^^^^ cannot assign
+   |     |
+   |     value is immutable in indexing expression
+
+error[E0510]: cannot assign `x` in indexing expression
+  --> $DIR/slice-index-bounds-check-invalidation.rs:64:12
+   |
+LL |     x[1][{ x = y; 2}][0]
+   |     ----   ^^^^^ cannot assign
+   |     |
+   |     value is immutable in indexing expression
+
+error[E0510]: cannot assign `x` in indexing expression
+  --> $DIR/slice-index-bounds-check-invalidation.rs:71:12
+   |
+LL |     x[1][{ x = y; 2}][0]
+   |     ----   ^^^^^ cannot assign
+   |     |
+   |     value is immutable in indexing expression
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0510`.
diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.rs b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.rs
new file mode 100644
index 00000000000..1dcf0461879
--- /dev/null
+++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.rs
@@ -0,0 +1,16 @@
+// This is not exactly right, yet.
+
+// Ideally we should be suggesting `as_mut` for the first case,
+// and suggesting to change `as_ref` to `as_mut` in the second.
+
+fn x(cb: &mut Option<&mut dyn FnMut()>) {
+    cb.map(|cb| cb());
+    //~^ ERROR cannot move out of `*cb` which is behind a mutable reference
+}
+
+fn x2(cb: &mut Option<&mut dyn FnMut()>) {
+    cb.as_ref().map(|cb| cb());
+    //~^ ERROR cannot borrow `*cb` as mutable, as it is behind a `&` reference
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr
new file mode 100644
index 00000000000..4621d879351
--- /dev/null
+++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr
@@ -0,0 +1,25 @@
+error[E0507]: cannot move out of `*cb` which is behind a mutable reference
+  --> $DIR/suggest-as-ref-on-mut-closure.rs:7:5
+   |
+LL |     cb.map(|cb| cb());
+   |     ^^^--------------
+   |     |  |
+   |     |  `*cb` moved due to this method call
+   |     help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
+   |     move occurs because `*cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait
+   |
+note: `Option::<T>::map` takes ownership of the receiver `self`, which moves `*cb`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference
+  --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26
+   |
+LL |     cb.as_ref().map(|cb| cb());
+   |                      --  ^^ `cb` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |                      |
+   |                      consider changing this binding's type to be: `&mut &mut dyn FnMut()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0507, E0596.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/borrowck/suggest-assign-rvalue.rs b/tests/ui/borrowck/suggest-assign-rvalue.rs
new file mode 100644
index 00000000000..aaca9d47f0a
--- /dev/null
+++ b/tests/ui/borrowck/suggest-assign-rvalue.rs
@@ -0,0 +1,57 @@
+#![allow(dead_code)]
+#![feature(never_type)]
+
+#[derive(Debug, Default)]
+struct Demo {}
+
+#[derive(Debug)]
+struct DemoNoDef {}
+
+fn apple(_: u32) {}
+
+fn banana() {
+    let chaenomeles;
+    apple(chaenomeles);
+    //~^ ERROR used binding `chaenomeles` isn't initialized [E0381]
+}
+
+fn main() {
+    let my_bool: bool = bool::default();
+    println!("my_bool: {}", my_bool);
+
+    let my_float: f32;
+    println!("my_float: {}", my_float);
+    //~^ ERROR used binding `my_float` isn't initialized
+    let demo: Demo;
+    println!("demo: {:?}", demo);
+    //~^ ERROR used binding `demo` isn't initialized
+
+    let demo_no: DemoNoDef;
+    println!("demo_no: {:?}", demo_no);
+    //~^ ERROR used binding `demo_no` isn't initialized
+
+    let arr: [i32; 5];
+    println!("arr: {:?}", arr);
+    //~^ ERROR used binding `arr` isn't initialized
+    let foo: Vec<&str>;
+    println!("foo: {:?}", foo);
+    //~^ ERROR used binding `foo` isn't initialized
+
+    let my_string: String;
+    println!("my_string: {}", my_string);
+    //~^ ERROR used binding `my_string` isn't initialized
+
+    let my_int: &i32;
+    println!("my_int: {}", *my_int);
+    //~^ ERROR used binding `my_int` isn't initialized
+
+    let hello: &str;
+    println!("hello: {}", hello);
+    //~^ ERROR used binding `hello` isn't initialized
+
+    let never: !;
+    println!("never: {}", never);
+    //~^ ERROR used binding `never` isn't initialized [E0381]
+
+    banana();
+}
diff --git a/tests/ui/borrowck/suggest-assign-rvalue.stderr b/tests/ui/borrowck/suggest-assign-rvalue.stderr
new file mode 100644
index 00000000000..92acba640d7
--- /dev/null
+++ b/tests/ui/borrowck/suggest-assign-rvalue.stderr
@@ -0,0 +1,138 @@
+error[E0381]: used binding `chaenomeles` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:14:11
+   |
+LL |     let chaenomeles;
+   |         ----------- binding declared here but left uninitialized
+LL |     apple(chaenomeles);
+   |           ^^^^^^^^^^^ `chaenomeles` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let chaenomeles = 0;
+   |                     +++
+
+error[E0381]: used binding `my_float` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:23:30
+   |
+LL |     let my_float: f32;
+   |         -------- binding declared here but left uninitialized
+LL |     println!("my_float: {}", my_float);
+   |                              ^^^^^^^^ `my_float` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_float: f32 = 0.0;
+   |                       +++++
+
+error[E0381]: used binding `demo` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:26:28
+   |
+LL |     let demo: Demo;
+   |         ---- binding declared here but left uninitialized
+LL |     println!("demo: {:?}", demo);
+   |                            ^^^^ `demo` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let demo: Demo = Default::default();
+   |                    ++++++++++++++++++++
+
+error[E0381]: used binding `demo_no` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:30:31
+   |
+LL |     let demo_no: DemoNoDef;
+   |         ------- binding declared here but left uninitialized
+LL |     println!("demo_no: {:?}", demo_no);
+   |                               ^^^^^^^ `demo_no` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let demo_no: DemoNoDef = todo!();
+   |                            +++++++++
+
+error[E0381]: used binding `arr` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:34:27
+   |
+LL |     let arr: [i32; 5];
+   |         --- binding declared here but left uninitialized
+LL |     println!("arr: {:?}", arr);
+   |                           ^^^ `arr` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let arr: [i32; 5] = todo!();
+   |                       +++++++++
+
+error[E0381]: used binding `foo` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:37:27
+   |
+LL |     let foo: Vec<&str>;
+   |         --- binding declared here but left uninitialized
+LL |     println!("foo: {:?}", foo);
+   |                           ^^^ `foo` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let foo: Vec<&str> = vec![];
+   |                        ++++++++
+
+error[E0381]: used binding `my_string` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:41:31
+   |
+LL |     let my_string: String;
+   |         --------- binding declared here but left uninitialized
+LL |     println!("my_string: {}", my_string);
+   |                               ^^^^^^^^^ `my_string` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_string: String = Default::default();
+   |                           ++++++++++++++++++++
+
+error[E0381]: used binding `my_int` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:45:28
+   |
+LL |     let my_int: &i32;
+   |         ------ binding declared here but left uninitialized
+LL |     println!("my_int: {}", *my_int);
+   |                            ^^^^^^^ `*my_int` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_int: &i32 = todo!();
+   |                      +++++++++
+
+error[E0381]: used binding `hello` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:49:27
+   |
+LL |     let hello: &str;
+   |         ----- binding declared here but left uninitialized
+LL |     println!("hello: {}", hello);
+   |                           ^^^^^ `hello` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let hello: &str = todo!();
+   |                     +++++++++
+
+error[E0381]: used binding `never` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:53:27
+   |
+LL |     let never: !;
+   |         ----- binding declared here but left uninitialized
+LL |     println!("never: {}", never);
+   |                           ^^^^^ `never` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/borrowck/suggest-local-var-double-mut.rs b/tests/ui/borrowck/suggest-local-var-double-mut.rs
new file mode 100644
index 00000000000..d5996ba68be
--- /dev/null
+++ b/tests/ui/borrowck/suggest-local-var-double-mut.rs
@@ -0,0 +1,27 @@
+// See issue #77834.
+
+#![crate_type = "lib"]
+
+mod method_syntax {
+    struct Foo;
+
+    impl Foo {
+        fn foo(&mut self, _: f32) -> i32 { todo!() }
+        fn bar(&mut self) -> f32 { todo!() }
+        fn baz(&mut self) {
+            self.foo(self.bar()); //~ ERROR
+        }
+    }
+}
+
+mod fully_qualified_syntax {
+    struct Foo;
+
+    impl Foo {
+        fn foo(&mut self, _: f32) -> i32 { todo!() }
+        fn bar(&mut self) -> f32 { todo!() }
+        fn baz(&mut self) {
+            Self::foo(self, Self::bar(self)); //~ ERROR
+        }
+    }
+}
diff --git a/tests/ui/borrowck/suggest-local-var-double-mut.stderr b/tests/ui/borrowck/suggest-local-var-double-mut.stderr
new file mode 100644
index 00000000000..3a43c18a7ed
--- /dev/null
+++ b/tests/ui/borrowck/suggest-local-var-double-mut.stderr
@@ -0,0 +1,44 @@
+error[E0499]: cannot borrow `*self` as mutable more than once at a time
+  --> $DIR/suggest-local-var-double-mut.rs:12:22
+   |
+LL |             self.foo(self.bar());
+   |             ---------^^^^^^^^^^-
+   |             |    |   |
+   |             |    |   second mutable borrow occurs here
+   |             |    first borrow later used by call
+   |             first mutable borrow occurs here
+   |
+help: try adding a local storing this argument...
+  --> $DIR/suggest-local-var-double-mut.rs:12:22
+   |
+LL |             self.foo(self.bar());
+   |                      ^^^^^^^^^^
+help: ...and then using that local as the argument to this call
+  --> $DIR/suggest-local-var-double-mut.rs:12:13
+   |
+LL |             self.foo(self.bar());
+   |             ^^^^^^^^^^^^^^^^^^^^
+
+error[E0499]: cannot borrow `*self` as mutable more than once at a time
+  --> $DIR/suggest-local-var-double-mut.rs:24:39
+   |
+LL |             Self::foo(self, Self::bar(self));
+   |             --------- ----            ^^^^ second mutable borrow occurs here
+   |             |         |
+   |             |         first mutable borrow occurs here
+   |             first borrow later used by call
+   |
+help: try adding a local storing this argument...
+  --> $DIR/suggest-local-var-double-mut.rs:24:29
+   |
+LL |             Self::foo(self, Self::bar(self));
+   |                             ^^^^^^^^^^^^^^^
+help: ...and then using that local as the argument to this call
+  --> $DIR/suggest-local-var-double-mut.rs:24:13
+   |
+LL |             Self::foo(self, Self::bar(self));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/suggest-local-var-for-vector.rs b/tests/ui/borrowck/suggest-local-var-for-vector.rs
new file mode 100644
index 00000000000..40f013f6a78
--- /dev/null
+++ b/tests/ui/borrowck/suggest-local-var-for-vector.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let mut vec = vec![0u32; 420];
+    vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable
+}
diff --git a/tests/ui/borrowck/suggest-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-local-var-for-vector.stderr
new file mode 100644
index 00000000000..615fffcd578
--- /dev/null
+++ b/tests/ui/borrowck/suggest-local-var-for-vector.stderr
@@ -0,0 +1,24 @@
+error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ----^^^^^^^^^-----
+   |     |   |
+   |     |   immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/suggest-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |         ^^^^^^^^^
+help: ...and then using that local here
+  --> $DIR/suggest-local-var-for-vector.rs:3:5
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/suggest-local-var-imm-and-mut.rs b/tests/ui/borrowck/suggest-local-var-imm-and-mut.rs
new file mode 100644
index 00000000000..bf167ba79f3
--- /dev/null
+++ b/tests/ui/borrowck/suggest-local-var-imm-and-mut.rs
@@ -0,0 +1,27 @@
+// See issue #77834.
+
+#![crate_type = "lib"]
+
+mod method_syntax {
+    struct Foo;
+
+    impl Foo {
+        fn foo(&self, _: f32) -> i32 { todo!() }
+        fn bar(&mut self) -> f32 { todo!() }
+        fn baz(&mut self) {
+            self.foo(self.bar()); //~ ERROR
+        }
+    }
+}
+
+mod fully_qualified_syntax {
+    struct Foo;
+
+    impl Foo {
+        fn foo(&self, _: f32) -> i32 { todo!() }
+        fn bar(&mut self) -> f32 { todo!() }
+        fn baz(&mut self) {
+            Self::foo(self, Self::bar(self)); //~ ERROR
+        }
+    }
+}
diff --git a/tests/ui/borrowck/suggest-local-var-imm-and-mut.stderr b/tests/ui/borrowck/suggest-local-var-imm-and-mut.stderr
new file mode 100644
index 00000000000..eb934e7b72b
--- /dev/null
+++ b/tests/ui/borrowck/suggest-local-var-imm-and-mut.stderr
@@ -0,0 +1,22 @@
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+  --> $DIR/suggest-local-var-imm-and-mut.rs:12:22
+   |
+LL |             self.foo(self.bar());
+   |             ---------^^^^^^^^^^-
+   |             |    |   |
+   |             |    |   mutable borrow occurs here
+   |             |    immutable borrow later used by call
+   |             immutable borrow occurs here
+
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+  --> $DIR/suggest-local-var-imm-and-mut.rs:24:29
+   |
+LL |             Self::foo(self, Self::bar(self));
+   |             --------- ----  ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |             |         |
+   |             |         immutable borrow occurs here
+   |             immutable borrow later used by call
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/suggest-storing-local-var-for-vector.rs b/tests/ui/borrowck/suggest-storing-local-var-for-vector.rs
new file mode 100644
index 00000000000..40f013f6a78
--- /dev/null
+++ b/tests/ui/borrowck/suggest-storing-local-var-for-vector.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let mut vec = vec![0u32; 420];
+    vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable
+}
diff --git a/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr
new file mode 100644
index 00000000000..e3a16eddfd5
--- /dev/null
+++ b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr
@@ -0,0 +1,24 @@
+error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ----^^^^^^^^^-----
+   |     |   |
+   |     |   immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |         ^^^^^^^^^
+help: ...and then using that local here
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:5
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/two-phase-across-loop.rs b/tests/ui/borrowck/two-phase-across-loop.rs
new file mode 100644
index 00000000000..3fcea7d1713
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-across-loop.rs
@@ -0,0 +1,22 @@
+// Test that a borrow which starts as a two-phase borrow and gets
+// carried around a loop winds up conflicting with itself.
+
+struct Foo { x: String }
+
+impl Foo {
+    fn get_string(&mut self) -> &str {
+        &self.x
+    }
+}
+
+fn main() {
+    let mut foo = Foo { x: format!("Hello, world") };
+    let mut strings = vec![];
+
+    loop {
+        strings.push(foo.get_string()); //~ ERROR cannot borrow `foo` as mutable
+        if strings.len() > 2 { break; }
+    }
+
+    println!("{:?}", strings);
+}
diff --git a/tests/ui/borrowck/two-phase-across-loop.stderr b/tests/ui/borrowck/two-phase-across-loop.stderr
new file mode 100644
index 00000000000..22f9b39dfee
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-across-loop.stderr
@@ -0,0 +1,12 @@
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/two-phase-across-loop.rs:17:22
+   |
+LL |         strings.push(foo.get_string());
+   |         -------------^^^^^^^^^^^^^^^^-
+   |         |            |
+   |         |            `foo` was mutably borrowed here in the previous iteration of the loop
+   |         first borrow used here, in later iteration of loop
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr
new file mode 100644
index 00000000000..aacf178932e
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr
@@ -0,0 +1,47 @@
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-activation-sharing-interference.rs:28:15
+   |
+LL |     let y = &mut x;
+   |             ------ mutable borrow occurs here
+LL |     { let z = &x; read(z); }
+   |               ^^ immutable borrow occurs here
+LL |
+LL |     *y += 1;
+   |     ------- mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-activation-sharing-interference.rs:36:13
+   |
+LL |     let y = &mut x;
+   |             ------ mutable borrow occurs here
+LL |     let z = &x;
+   |             ^^ immutable borrow occurs here
+LL |
+LL |     *y += 1;
+   |     ------- mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-activation-sharing-interference.rs:47:13
+   |
+LL |     let y = &mut x;
+   |             ------ mutable borrow occurs here
+LL |     let z = &x;
+   |             ^^ immutable borrow occurs here
+...
+LL |     *y += 1;
+   |     ------- mutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-activation-sharing-interference.rs:58:14
+   |
+LL |     let y = &mut x;
+   |             ------ mutable borrow occurs here
+LL |     let _z = &x;
+   |              ^^ immutable borrow occurs here
+LL |
+LL |     *y += 1;
+   |     ------- mutable borrow later used here
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.rs b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs
new file mode 100644
index 00000000000..8b880ff6416
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs
@@ -0,0 +1,65 @@
+// revisions: nll_target
+
+// The following revisions are disabled due to missing support from two-phase beyond autorefs
+//[nll_beyond] compile-flags: -Z two-phase-beyond-autoref
+
+// This is an important corner case pointed out by Niko: one is
+// allowed to initiate a shared borrow during a reservation, but it
+// *must end* before the activation occurs.
+//
+// FIXME: for clarity, diagnostics for these cases might be better off
+// if they specifically said "cannot activate mutable borrow of `x`"
+//
+// The convention for the listed revisions: "lxl" means lexical
+// lifetimes (which can be easier to reason about). "nll" means
+// non-lexical lifetimes. "nll_target" means the initial conservative
+// two-phase borrows that only applies to autoref-introduced borrows.
+// "nll_beyond" means the generalization of two-phase borrows to all
+// `&mut`-borrows (doing so makes it easier to write code for specific
+// corner cases).
+
+#![allow(dead_code)]
+
+fn read(_: &i32) { }
+
+fn ok() {
+    let mut x = 3;
+    let y = &mut x;
+    { let z = &x; read(z); }
+    //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+    *y += 1;
+}
+
+fn not_ok() {
+    let mut x = 3;
+    let y = &mut x;
+    let z = &x;
+    //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+    *y += 1;
+    //[lxl_beyond]~^   ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+    //[nll_beyond]~^^  ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+    read(z);
+}
+
+fn should_be_ok_with_nll() {
+    let mut x = 3;
+    let y = &mut x;
+    let z = &x;
+    //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+    read(z);
+    *y += 1;
+    //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+    // (okay with (generalized) nll today)
+}
+
+fn should_also_eventually_be_ok_with_nll() {
+    let mut x = 3;
+    let y = &mut x;
+    let _z = &x;
+    //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+    *y += 1;
+    //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+    // (okay with (generalized) nll today)
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr
new file mode 100644
index 00000000000..a57ceb84739
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr
@@ -0,0 +1,27 @@
+error[E0503]: cannot use `i` because it was mutably borrowed
+  --> $DIR/two-phase-allow-access-during-reservation.rs:26:19
+   |
+LL |     /*1*/ let p = &mut i; // (reservation of `i` starts here)
+   |                   ------ borrow of `i` occurs here
+LL |
+LL |     /*2*/ let j = i;      // OK: `i` is only reserved here
+   |                   ^ use of borrowed `i`
+...
+LL |     /*3*/ *p += 1;        // (mutable borrow of `i` starts here, since `p` is used)
+   |           ------- borrow later used here
+
+error[E0503]: cannot use `i` because it was mutably borrowed
+  --> $DIR/two-phase-allow-access-during-reservation.rs:31:19
+   |
+LL |     /*1*/ let p = &mut i; // (reservation of `i` starts here)
+   |                   ------ borrow of `i` occurs here
+...
+LL |     /*4*/ let k = i;
+   |                   ^ use of borrowed `i`
+...
+LL |     /*5*/ *p += 1;
+   |           ------- borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0503`.
diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs
new file mode 100644
index 00000000000..67d0842070f
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs
@@ -0,0 +1,37 @@
+// revisions: nll_target
+
+// The following revisions are disabled due to missing support for two_phase_beyond_autoref
+//[nll_beyond] compile-flags: -Z two_phase_beyond_autoref
+
+// This is the second counter-example from Niko's blog post
+// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
+//
+// It is "artificial". It is meant to illustrate directly that we
+// should allow an aliasing access during reservation, but *not* while
+// the mutable borrow is active.
+//
+// The convention for the listed revisions: "lxl" means lexical
+// lifetimes (which can be easier to reason about). "nll" means
+// non-lexical lifetimes. "nll_target" means the initial conservative
+// two-phase borrows that only applies to autoref-introduced borrows.
+// "nll_beyond" means the generalization of two-phase borrows to all
+// `&mut`-borrows (doing so makes it easier to write code for specific
+// corner cases).
+
+fn main() {
+    /*0*/ let mut i = 0;
+
+    /*1*/ let p = &mut i; // (reservation of `i` starts here)
+
+    /*2*/ let j = i;      // OK: `i` is only reserved here
+                          //[nll_target]~^  ERROR cannot use `i` because it was mutably borrowed [E0503]
+
+    /*3*/ *p += 1;        // (mutable borrow of `i` starts here, since `p` is used)
+
+    /*4*/ let k = i;      //[nll_beyond]~  ERROR cannot use `i` because it was mutably borrowed [E0503]
+                          //[nll_target]~^ ERROR cannot use `i` because it was mutably borrowed [E0503]
+
+    /*5*/ *p += 1;
+
+    let _ = (j, k, p);
+}
diff --git a/tests/ui/borrowck/two-phase-baseline.rs b/tests/ui/borrowck/two-phase-baseline.rs
new file mode 100644
index 00000000000..994dc823dfc
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-baseline.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+// This is the "goto example" for why we want two phase borrows.
+
+fn main() {
+    let mut v = vec![0, 1, 2];
+    v.push(v.len());
+    assert_eq!(v, [0, 1, 2, 3]);
+}
diff --git a/tests/ui/borrowck/two-phase-bin-ops.rs b/tests/ui/borrowck/two-phase-bin-ops.rs
new file mode 100644
index 00000000000..1242ae307d3
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-bin-ops.rs
@@ -0,0 +1,35 @@
+// run-pass
+use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
+use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
+
+struct A(i32);
+
+macro_rules! trivial_binop {
+    ($Trait:ident, $m:ident) => {
+        impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
+    }
+}
+
+trivial_binop!(AddAssign, add_assign);
+trivial_binop!(SubAssign, sub_assign);
+trivial_binop!(MulAssign, mul_assign);
+trivial_binop!(DivAssign, div_assign);
+trivial_binop!(RemAssign, rem_assign);
+trivial_binop!(BitAndAssign, bitand_assign);
+trivial_binop!(BitOrAssign, bitor_assign);
+trivial_binop!(BitXorAssign, bitxor_assign);
+trivial_binop!(ShlAssign, shl_assign);
+trivial_binop!(ShrAssign, shr_assign);
+
+fn main() {
+    let mut a = A(10);
+    a += a.0;
+    a -= a.0;
+    a *= a.0;
+    a /= a.0;
+    a &= a.0;
+    a |= a.0;
+    a ^= a.0;
+    a <<= a.0;
+    a >>= a.0;
+}
diff --git a/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs
new file mode 100644
index 00000000000..dd2ef4e27ee
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs
@@ -0,0 +1,19 @@
+// This is the third counter-example from Niko's blog post
+// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
+//
+// It shows that not all nested method calls on `self` are magically
+// allowed by this change. In particular, a nested `&mut` borrow is
+// still disallowed.
+
+fn main() {
+
+
+    let mut vec = vec![0, 1];
+    vec.get({
+
+        vec.push(2);
+        //~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
+
+        0
+    });
+}
diff --git a/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr
new file mode 100644
index 00000000000..21b0eddb902
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr
@@ -0,0 +1,19 @@
+error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:14:9
+   |
+LL |       vec.get({
+   |       -   --- immutable borrow later used by call
+   |  _____|
+   | |
+LL | |
+LL | |         vec.push(2);
+   | |         ^^^^^^^^^^^ mutable borrow occurs here
+LL | |
+LL | |
+LL | |         0
+LL | |     });
+   | |______- immutable borrow occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/two-phase-control-flow-split-before-activation.rs b/tests/ui/borrowck/two-phase-control-flow-split-before-activation.rs
new file mode 100644
index 00000000000..0b20e1945e6
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-control-flow-split-before-activation.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+fn main() {
+    let mut a = 0;
+    let mut b = 0;
+    let p = if maybe() {
+        &mut a
+    } else {
+        &mut b
+    };
+    use_(p);
+}
+
+fn maybe() -> bool { false }
+fn use_<T>(_: T) { }
diff --git a/tests/ui/borrowck/two-phase-method-receivers.rs b/tests/ui/borrowck/two-phase-method-receivers.rs
new file mode 100644
index 00000000000..6b879af5aec
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-method-receivers.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+struct Foo<'a> {
+    x: &'a i32
+}
+
+impl<'a> Foo<'a> {
+    fn method(&mut self, _: &i32) {
+    }
+}
+
+fn main() {
+    let a = &mut Foo { x: &22 };
+    Foo::method(a, a.x);
+}
diff --git a/tests/ui/borrowck/two-phase-multi-mut.rs b/tests/ui/borrowck/two-phase-multi-mut.rs
new file mode 100644
index 00000000000..bb646d7caf1
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-multi-mut.rs
@@ -0,0 +1,14 @@
+struct Foo {
+}
+
+impl Foo {
+    fn method(&mut self, foo: &mut Foo) {
+    }
+}
+
+fn main() {
+    let mut foo = Foo { };
+    foo.method(&mut foo);
+    //~^     cannot borrow `foo` as mutable more than once at a time
+    //~^^    cannot borrow `foo` as mutable more than once at a time
+}
diff --git a/tests/ui/borrowck/two-phase-multi-mut.stderr b/tests/ui/borrowck/two-phase-multi-mut.stderr
new file mode 100644
index 00000000000..2e53e17a31b
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-multi-mut.stderr
@@ -0,0 +1,23 @@
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/two-phase-multi-mut.rs:11:5
+   |
+LL |     foo.method(&mut foo);
+   |     ^^^^------^--------^
+   |     |   |      |
+   |     |   |      first mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     second mutable borrow occurs here
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/two-phase-multi-mut.rs:11:16
+   |
+LL |     foo.method(&mut foo);
+   |     -----------^^^^^^^^-
+   |     |   |      |
+   |     |   |      second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/two-phase-multiple-activations.rs b/tests/ui/borrowck/two-phase-multiple-activations.rs
new file mode 100644
index 00000000000..53fb71ebed4
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-multiple-activations.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+use std::io::Result;
+
+struct Foo {}
+
+pub trait FakeRead {
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>;
+}
+
+impl FakeRead for Foo {
+    fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> Result<usize> {
+        Ok(4)
+    }
+}
+
+fn main() {
+    let mut a = Foo {};
+    let mut v = Vec::new();
+    a.read_to_end(&mut v).unwrap();
+}
diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
new file mode 100644
index 00000000000..efd63a08aae
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
@@ -0,0 +1,93 @@
+error[E0499]: cannot borrow `*f` as mutable more than once at a time
+  --> $DIR/two-phase-nonrecv-autoref.rs:50:11
+   |
+LL |         f(f(10));
+   |         - ^ second mutable borrow occurs here
+   |         |
+   |         first mutable borrow occurs here
+   |         first borrow later used by call
+
+error[E0382]: use of moved value: `f`
+  --> $DIR/two-phase-nonrecv-autoref.rs:57:11
+   |
+LL |     fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
+   |                                            - move occurs because `f` has type `Box<F>`, which does not implement the `Copy` trait
+LL |         f(f(10));
+   |         - ^ value used here after move
+   |         |
+   |         value moved here
+
+error[E0499]: cannot borrow `*f` as mutable more than once at a time
+  --> $DIR/two-phase-nonrecv-autoref.rs:62:11
+   |
+LL |         f(f(10));
+   |         - ^ second mutable borrow occurs here
+   |         |
+   |         first mutable borrow occurs here
+   |         first borrow later used by call
+
+error[E0382]: use of moved value: `f`
+  --> $DIR/two-phase-nonrecv-autoref.rs:69:11
+   |
+LL |     fn twice_ten_oo(f: Box<dyn FnOnce(i32) -> i32>) {
+   |                     - move occurs because `f` has type `Box<dyn FnOnce(i32) -> i32>`, which does not implement the `Copy` trait
+LL |         f(f(10));
+   |         - ^ value used here after move
+   |         |
+   |         value moved here
+
+error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-nonrecv-autoref.rs:107:27
+   |
+LL |     double_access(&mut a, &a);
+   |     ------------- ------  ^^ immutable borrow occurs here
+   |     |             |
+   |     |             mutable borrow occurs here
+   |     mutable borrow later used by call
+
+error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-nonrecv-autoref.rs:132:7
+   |
+LL |     i[i[3]] = 4;
+   |     --^----
+   |     | |
+   |     | immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/two-phase-nonrecv-autoref.rs:132:7
+   |
+LL |     i[i[3]] = 4;
+   |       ^^^^
+help: ...and then using that local here
+  --> $DIR/two-phase-nonrecv-autoref.rs:132:5
+   |
+LL |     i[i[3]] = 4;
+   |     ^^^^^^^
+
+error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:7
+   |
+LL |     i[i[3]] = i[4];
+   |     --^----
+   |     | |
+   |     | immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:7
+   |
+LL |     i[i[3]] = i[4];
+   |       ^^^^
+help: ...and then using that local here
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:5
+   |
+LL |     i[i[3]] = i[4];
+   |     ^^^^^^^
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0382, E0499, E0502.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.rs b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs
new file mode 100644
index 00000000000..da238205b40
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs
@@ -0,0 +1,166 @@
+// revisions: base
+
+//[g2p]compile-flags: -Z two-phase-beyond-autoref
+// the above revision is disabled until two-phase-beyond-autoref support is better
+
+// This is a test checking that when we limit two-phase borrows to
+// method receivers, we do not let other kinds of auto-ref to leak
+// through.
+//
+// The g2p revision illustrates the "undesirable" behavior you would
+// otherwise observe without limiting the phasing to autoref on method
+// receivers (namely, in many cases demonstrated below, the error
+// would not arise).
+
+use std::ops::{Index, IndexMut};
+
+fn foo(x: &mut u32, y: u32) {
+    *x += y;
+}
+
+fn deref_coercion(x: &mut u32) {
+    foo(x, *x);
+    // Above error is a known limitation of AST borrowck
+}
+
+// While adding a flag to adjustments (indicating whether they
+// should support two-phase borrows, here are the cases I
+// encountered:
+//
+// - [x] Resolving overloaded_call_traits (call, call_mut, call_once)
+// - [x] deref_coercion (shown above)
+// - [x] coerce_unsized e.g., `&[T; n]`, `&mut [T; n] -> &[T]`,
+//                      `&mut [T; n] -> &mut [T]`, `&Concrete -> &Trait`
+// - [x] Method Call Receivers (the case we want to support!)
+// - [x] ExprKind::Index and ExprKind::Unary Deref; only need to handle coerce_index_op
+// - [x] overloaded_binops
+
+fn overloaded_call_traits() {
+    // Regarding overloaded call traits, note that there is no
+    // scenario where adding two-phase borrows should "fix" these
+    // cases, because either we will resolve both invocations to
+    // `call_mut` (in which case the inner call requires a mutable
+    // borrow which will conflict with the outer reservation), or we
+    // will resolve both to `call` (which will just work, regardless
+    // of two-phase borrow support), or we will resolve both to
+    // `call_once` (in which case the inner call requires moving the
+    // receiver, invalidating the outer call).
+
+    fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) {
+        f(f(10));
+        //~^ ERROR cannot borrow `*f` as mutable more than once at a time
+    }
+    fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
+        f(f(10));
+    }
+    fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
+        f(f(10));
+        //~^ ERROR use of moved value: `f`
+    }
+
+    fn twice_ten_om(f: &mut dyn FnMut(i32) -> i32) {
+        f(f(10));
+        //~^ ERROR cannot borrow `*f` as mutable more than once at a time
+    }
+    fn twice_ten_oi(f: &mut dyn Fn(i32) -> i32) {
+        f(f(10));
+    }
+    fn twice_ten_oo(f: Box<dyn FnOnce(i32) -> i32>) {
+        f(f(10));
+        //~^ ERROR use of moved value: `f`
+    }
+
+    twice_ten_sm(&mut |x| x + 1);
+    twice_ten_si(&mut |x| x + 1);
+    twice_ten_so(Box::new(|x| x + 1));
+    twice_ten_om(&mut |x| x + 1);
+    twice_ten_oi(&mut |x| x + 1);
+    twice_ten_oo(Box::new(|x| x + 1));
+}
+
+trait TwoMethods {
+    fn m(&mut self, x: i32) -> i32 { x + 1 }
+    fn i(&self, x: i32) -> i32 { x + 1 }
+}
+
+struct T;
+
+impl TwoMethods for T { }
+
+struct S;
+
+impl S {
+    fn m(&mut self, x: i32) -> i32 { x + 1 }
+    fn i(&self, x: i32) -> i32 { x + 1 }
+}
+
+impl TwoMethods for [i32; 3] { }
+
+fn double_access<X: Copy>(m: &mut [X], s: &[X]) {
+    m[0] = s[1];
+}
+
+fn coerce_unsized() {
+    let mut a = [1, 2, 3];
+
+    // This is not okay.
+    double_access(&mut a, &a);
+    //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+
+    // But this is okay.
+    a.m(a.i(10));
+    // Above error is an expected limitation of AST borrowck
+}
+
+struct I(i32);
+
+impl Index<i32> for I {
+    type Output = i32;
+    fn index(&self, _: i32) -> &i32 {
+        &self.0
+    }
+}
+
+impl IndexMut<i32> for I {
+    fn index_mut(&mut self, _: i32) -> &mut i32 {
+        &mut self.0
+    }
+}
+
+fn coerce_index_op() {
+    let mut i = I(10);
+    i[i[3]] = 4;
+    //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+    // Should be accepted with g2p
+
+    i[3] = i[4];
+
+    i[i[3]] = i[4];
+    //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+    // Should be accepted with g2p
+}
+
+fn main() {
+
+    // As a reminder, this is the basic case we want to ensure we handle.
+    let mut v = vec![1, 2, 3];
+    v.push(v.len());
+    // Error above is an expected limitation of AST borrowck
+
+    // (as a rule, pnkfelix does not like to write tests with dead code.)
+
+    deref_coercion(&mut 5);
+    overloaded_call_traits();
+
+
+    let mut s = S;
+    s.m(s.i(10));
+    // Error above is an expected limitation of AST borrowck
+
+    let mut t = T;
+    t.m(t.i(10));
+    // Error above is an expected limitation of AST borrowck
+
+    coerce_unsized();
+    coerce_index_op();
+}
diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.rs
new file mode 100644
index 00000000000..27e599c6cd5
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.rs
@@ -0,0 +1,29 @@
+// Test for #56254. The last example originally failed with the ast checker, was
+// accidentally allowed under migrate/nll, then linted against in migrate mode
+// but disallowed under NLL. Now, we accept it everywhere.
+
+//ignore-compare-mode-polonius
+
+fn double_conflicts() {
+    let mut v = vec![0, 1, 2];
+    let shared = &v;
+
+    v.extend(shared);
+    //~^ ERROR cannot borrow `v` as mutable
+}
+
+fn activation_conflict() {
+    let mut v = vec![0, 1, 2];
+
+    v.extend(&v);
+    //~^ ERROR cannot borrow `v` as mutable
+}
+
+fn reservation_allowed() {
+    let mut v = vec![0, 1, 2];
+    let shared = &v;
+
+    v.push(shared.len());
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr
new file mode 100644
index 00000000000..9e0f68b6543
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr
@@ -0,0 +1,25 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:11:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL |
+LL |     v.extend(shared);
+   |     ^^------^^^^^^^^
+   |     | |
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5
+   |
+LL |     v.extend(&v);
+   |     ^^------^--^
+   |     | |      |
+   |     | |      immutable borrow occurs here
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr
new file mode 100644
index 00000000000..e3e4057d6a7
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference.rs:32:17
+   |
+LL |         let shared = &vec;
+   |                      ---- immutable borrow occurs here
+...
+LL |         delay = &mut vec;
+   |                 ^^^^^^^^ mutable borrow occurs here
+...
+LL |         shared[0];
+   |         ------ immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs
new file mode 100644
index 00000000000..0463e22b3c2
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs
@@ -0,0 +1,45 @@
+// revisions: nll_target
+
+// The nll_beyond revision is disabled due to missing support from two-phase beyond autorefs
+//[nll_beyond]compile-flags: -Z two-phase-beyond-autoref
+//[nll_beyond]should-fail
+
+// This is a corner case that the current implementation is (probably)
+// treating more conservatively than is necessary. But it also does
+// not seem like a terribly important use case to cover.
+//
+// So this test is just making a note of the current behavior, with
+// the caveat that in the future, the rules may be loosened, at which
+// point this test might be thrown out.
+//
+// The convention for the listed revisions: "lxl" means lexical
+// lifetimes (which can be easier to reason about). "nll" means
+// non-lexical lifetimes. "nll_target" means the initial conservative
+// two-phase borrows that only applies to autoref-introduced borrows.
+// "nll_beyond" means the generalization of two-phase borrows to all
+// `&mut`-borrows (doing so makes it easier to write code for specific
+// corner cases).
+
+fn main() {
+    let mut vec = vec![0, 1];
+    let delay: &mut Vec<_>;
+    {
+        let shared = &vec;
+
+        // we reserve here, which could (on its own) be compatible
+        // with the shared borrow. But in the current implementation,
+        // its an error.
+        delay = &mut vec;
+        //[nll_beyond]~^  ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
+        //[nll_target]~^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
+
+        shared[0];
+    }
+
+    // the &mut-borrow only becomes active way down here.
+    //
+    // (At least in theory; part of the reason this test fails is that
+    // the constructed MIR throws in extra &mut reborrows which
+    // flummoxes our attempt to delay the activation point here.)
+    delay.push(2);
+}
diff --git a/tests/ui/borrowck/two-phase-sneaky.rs b/tests/ui/borrowck/two-phase-sneaky.rs
new file mode 100644
index 00000000000..bf06366debe
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-sneaky.rs
@@ -0,0 +1,15 @@
+// This is the first counter-example from Niko's blog post
+// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
+// of a danger for code to crash if we just turned off the check for whether
+// a mutable-borrow aliases another borrow.
+
+fn main() {
+    let mut v: Vec<String> = vec![format!("Hello, ")];
+    v[0].push_str({
+
+        v.push(format!("foo"));
+        //~^   ERROR cannot borrow `v` as mutable more than once at a time [E0499]
+
+        "World!"
+    });
+}
diff --git a/tests/ui/borrowck/two-phase-sneaky.stderr b/tests/ui/borrowck/two-phase-sneaky.stderr
new file mode 100644
index 00000000000..117d7ceaeef
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-sneaky.stderr
@@ -0,0 +1,14 @@
+error[E0499]: cannot borrow `v` as mutable more than once at a time
+  --> $DIR/two-phase-sneaky.rs:10:9
+   |
+LL |     v[0].push_str({
+   |     -    -------- first borrow later used by call
+   |     |
+   |     first mutable borrow occurs here
+LL |
+LL |         v.push(format!("foo"));
+   |         ^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.rs b/tests/ui/borrowck/two-phase-surprise-no-conflict.rs
new file mode 100644
index 00000000000..6d37d1ded64
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.rs
@@ -0,0 +1,167 @@
+// This is a test adapted from a minimization of the code from
+// rust-lang/rust#52934, where an accidental disabling of
+// two-phase-borrows (in the initial 2018 edition integration) broke
+// Clippy, but the scenarios where it was breaking were subtle enough
+// that we decided it warranted its own unit test, and pnkfelix
+// decided to use that test as an opportunity to illustrate the cases.
+
+#[derive(Copy, Clone)]
+struct BodyId;
+enum Expr { Closure(BodyId), Others }
+struct Body { value: Expr }
+
+struct Map { body: Body, }
+impl Map { fn body(&self, _: BodyId) -> &Body { unimplemented!() } }
+
+struct SpanlessHash<'a> { cx: &'a Map, cx_mut: &'a mut Map }
+
+impl <'a> SpanlessHash<'a> {
+    fn demo(&mut self) {
+        let _mut_borrow = &mut *self;
+        let _access = self.cx;
+        //~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503]
+        _mut_borrow;
+    }
+
+    fn hash_expr(&mut self, e: &Expr) {
+        match *e {
+            Expr::Closure(eid) => {
+                // Accepted by AST-borrowck for erroneous reasons
+                // (rust-lang/rust#38899).
+                //
+                // Not okay without two-phase borrows: the implicit
+                // `&mut self` of the receiver is evaluated first, and
+                // that conflicts with the `self.cx` access during
+                // argument evaluation, as demonstrated in `fn demo`
+                // above.
+                //
+                // Okay if we have two-phase borrows. Note that even
+                // if `self.cx.body(..)` holds onto a reference into
+                // `self.cx`, `self.cx` is an immutable-borrow, so
+                // nothing in the activation for `self.hash_expr(..)`
+                // can interfere with that immutable borrow.
+                self.hash_expr(&self.cx.body(eid).value);
+            },
+            _ => {}
+        }
+    }
+
+    fn hash_expr_mut(&mut self, e: &Expr) {
+        match *e {
+            Expr::Closure(eid) => {
+                // Not okay: the call to `self.cx_mut.body(eid)` might
+                // hold on to some mutably borrowed state in
+                // `self.cx_mut`, which would then interfere with the
+                // eventual activation of the `self` mutable borrow
+                // for `self.hash_expr(..)`
+                self.hash_expr(&self.cx_mut.body(eid).value);
+                //~^ ERROR cannot borrow `*self`
+            },
+            _ => {}
+        }
+    }
+}
+
+struct Session;
+struct Config;
+trait LateLintPass<'a> { }
+
+struct TrivialPass;
+impl TrivialPass {
+    fn new(_: &Session) -> Self { TrivialPass }
+    fn new_mut(_: &mut Session) -> Self { TrivialPass }
+}
+
+struct CapturePass<'a> { s: &'a Session }
+impl<'a> CapturePass<'a> {
+    fn new(s: &'a Session) -> Self { CapturePass { s } }
+    fn new_mut(s: &'a mut Session) -> Self { CapturePass { s } }
+}
+
+impl<'a> LateLintPass<'a> for TrivialPass { }
+impl<'a, 'b> LateLintPass<'a> for CapturePass<'b> { }
+
+struct Registry<'a> { sess_mut: &'a mut Session }
+impl<'a> Registry<'a> {
+    fn register_static(&mut self, _: Box<dyn LateLintPass + 'static>) { }
+
+    // Note: there isn't an interesting distinction between these
+    // different methods explored by any of the cases in the test
+    // below. pnkfelix just happened to write these cases out while
+    // exploring variations on `dyn for <'a> Trait<'a> + 'static`, and
+    // then decided to keep these particular ones in.
+    fn register_bound(&mut self, _: Box<dyn LateLintPass + 'a>) { }
+    fn register_univ(&mut self, _: Box<dyn for <'b> LateLintPass<'b> + 'a>) { }
+    fn register_ref(&mut self, _: &dyn LateLintPass) { }
+}
+
+fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
+    // Not okay without two-phase borrows: The implicit `&mut reg` of
+    // the receiver is evaluaated first, and that conflicts with the
+    // `reg.sess_mut` access during argument evaluation.
+    //
+    // Okay if we have two-phase borrows: inner borrows do not survive
+    // to the actual method invocation, because `TrivialPass::new`
+    // cannot (according to its type) keep them alive.
+    let reg = mk_reg();
+    reg.register_static(Box::new(TrivialPass::new(&reg.sess_mut)));
+    let reg = mk_reg();
+    reg.register_bound(Box::new(TrivialPass::new(&reg.sess_mut)));
+    let reg = mk_reg();
+    reg.register_univ(Box::new(TrivialPass::new(&reg.sess_mut)));
+    let reg = mk_reg();
+    reg.register_ref(&TrivialPass::new(&reg.sess_mut));
+
+    // These are not okay: the inner mutable borrows immediately
+    // conflict with the outer borrow/reservation, even with support
+    // for two-phase borrows.
+    let reg = mk_reg();
+    reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut)));
+    //~^ ERROR cannot borrow `reg.sess_mut`
+    let reg = mk_reg();
+    reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
+    //~^ ERROR cannot borrow `reg.sess_mut`
+    let reg = mk_reg();
+    reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
+    //~^ ERROR cannot borrow `reg.sess_mut`
+    let reg = mk_reg();
+    reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut));
+    //~^ ERROR cannot borrow `reg.sess_mut`
+
+    // These are not okay: the inner borrows may reach the actual
+    // method invocation, because `CapturePass::new` might (according
+    // to its type) keep them alive.
+    //
+    // (Also, we don't test `register_static` on CapturePass because
+    // that will fail to get past lifetime inference.)
+    let reg = mk_reg();
+    reg.register_bound(Box::new(CapturePass::new(&reg.sess_mut)));
+    //~^ ERROR cannot borrow `*reg` as mutable
+    let reg = mk_reg();
+    reg.register_univ(Box::new(CapturePass::new(&reg.sess_mut)));
+    //~^ ERROR cannot borrow `*reg` as mutable
+    let reg = mk_reg();
+    reg.register_ref(&CapturePass::new(&reg.sess_mut));
+    //~^ ERROR cannot borrow `*reg` as mutable
+
+    // These are not okay: the inner mutable borrows immediately
+    // conflict with the outer borrow/reservation, even with support
+    // for two-phase borrows.
+    //
+    // (Again, we don't test `register_static` on CapturePass because
+    // that will fail to get past lifetime inference.)
+    let reg = mk_reg();
+    reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
+    //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time
+    //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time
+    let reg = mk_reg();
+    reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
+    //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time
+    //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time
+    let reg = mk_reg();
+    reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
+    //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time
+    //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr
new file mode 100644
index 00000000000..5a240d90011
--- /dev/null
+++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr
@@ -0,0 +1,161 @@
+error[E0503]: cannot use `self.cx` because it was mutably borrowed
+  --> $DIR/two-phase-surprise-no-conflict.rs:21:23
+   |
+LL |         let _mut_borrow = &mut *self;
+   |                           ---------- borrow of `*self` occurs here
+LL |         let _access = self.cx;
+   |                       ^^^^^^^ use of borrowed `*self`
+LL |
+LL |         _mut_borrow;
+   |         ----------- borrow later used here
+
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-surprise-no-conflict.rs:57:17
+   |
+LL |                 self.hash_expr(&self.cx_mut.body(eid).value);
+   |                 ^^^^^---------^^---------------------^^^^^^^
+   |                 |    |          |
+   |                 |    |          immutable borrow occurs here
+   |                 |    immutable borrow later used by call
+   |                 mutable borrow occurs here
+
+error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:119:51
+   |
+LL |     reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut)));
+   |     ----------------------------------------------^^^^^^^^^^^^^^^^^---
+   |     |   |                                         |
+   |     |   |                                         second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:122:54
+   |
+LL |     reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
+   |     -------------------------------------------------^^^^^^^^^^^^^^^^^---
+   |     |   |                                            |
+   |     |   |                                            second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:125:53
+   |
+LL |     reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
+   |     ------------------------------------------------^^^^^^^^^^^^^^^^^---
+   |     |   |                                           |
+   |     |   |                                           second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:128:44
+   |
+LL |     reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut));
+   |     ---------------------------------------^^^^^^^^^^^^^^^^^--
+   |     |   |                                  |
+   |     |   |                                  second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-surprise-no-conflict.rs:138:5
+   |
+LL |     reg.register_bound(Box::new(CapturePass::new(&reg.sess_mut)));
+   |     ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^
+   |     |   |                                        |
+   |     |   |                                        immutable borrow occurs here
+   |     |   immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-surprise-no-conflict.rs:141:5
+   |
+LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
+   |                     -- lifetime `'a` defined here
+...
+LL |     reg.register_univ(Box::new(CapturePass::new(&reg.sess_mut)));
+   |     ^^^^^^^^^^^^^^^^^^-----------------------------------------^
+   |     |                 |                         |
+   |     |                 |                         immutable borrow occurs here
+   |     |                 cast requires that `reg.sess_mut` is borrowed for `'a`
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-surprise-no-conflict.rs:144:5
+   |
+LL |     reg.register_ref(&CapturePass::new(&reg.sess_mut));
+   |     ^^^^------------^^^^^^^^^^^^^^^^^^^-------------^^
+   |     |   |                              |
+   |     |   |                              immutable borrow occurs here
+   |     |   immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0499]: cannot borrow `*reg` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:154:5
+   |
+LL |     reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
+   |     ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^
+   |     |   |                                            |
+   |     |   |                                            first mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     second mutable borrow occurs here
+
+error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:154:54
+   |
+LL |     reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
+   |     -------------------------------------------------^^^^^^^^^^^^^^^^^---
+   |     |   |                                            |
+   |     |   |                                            second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error[E0499]: cannot borrow `*reg` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:158:5
+   |
+LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
+   |                     -- lifetime `'a` defined here
+...
+LL |     reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
+   |     ^^^^^^^^^^^^^^^^^^-------------------------------------------------^
+   |     |                 |                             |
+   |     |                 |                             first mutable borrow occurs here
+   |     |                 cast requires that `reg.sess_mut` is borrowed for `'a`
+   |     second mutable borrow occurs here
+
+error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:158:53
+   |
+LL |     reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
+   |     ------------------------------------------------^^^^^^^^^^^^^^^^^---
+   |     |   |                                           |
+   |     |   |                                           second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error[E0499]: cannot borrow `*reg` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:162:5
+   |
+LL |     reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
+   |     ^^^^------------^^^^^^^^^^^^^^^^^^^^^^^-----------------^^
+   |     |   |                                  |
+   |     |   |                                  first mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     second mutable borrow occurs here
+
+error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
+  --> $DIR/two-phase-surprise-no-conflict.rs:162:44
+   |
+LL |     reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
+   |     ---------------------------------------^^^^^^^^^^^^^^^^^--
+   |     |   |                                  |
+   |     |   |                                  second mutable borrow occurs here
+   |     |   first borrow later used by call
+   |     first mutable borrow occurs here
+
+error: aborting due to 15 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0503.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed
new file mode 100644
index 00000000000..b0c5376105b
--- /dev/null
+++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+// Test that a by-ref `FnMut` closure gets an error when it tries to
+// consume a value.
+
+fn call<F>(f: F) where F : Fn() {
+    f();
+}
+
+fn main() {
+    let y = vec![format!("World")];
+    call(|| {
+        y.clone().into_iter();
+        //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
+    });
+}
diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs
new file mode 100644
index 00000000000..4666b8a3373
--- /dev/null
+++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+// Test that a by-ref `FnMut` closure gets an error when it tries to
+// consume a value.
+
+fn call<F>(f: F) where F : Fn() {
+    f();
+}
+
+fn main() {
+    let y = vec![format!("World")];
+    call(|| {
+        y.into_iter();
+        //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
+    });
+}
diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
new file mode 100644
index 00000000000..f033d53bf8e
--- /dev/null
+++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
@@ -0,0 +1,22 @@
+error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure
+  --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:12:9
+   |
+LL |     let y = vec![format!("World")];
+   |         - captured outer variable
+LL |     call(|| {
+   |          -- captured by this `Fn` closure
+LL |         y.into_iter();
+   |         ^ ----------- `y` moved due to this method call
+   |         |
+   |         move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
+   |
+note: `into_iter` takes ownership of the receiver `self`, which moves `y`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |         y.clone().into_iter();
+   |           ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.