summaryrefslogtreecommitdiffstats
path: root/tests/ui/borrowck
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/borrowck
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
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-92157.rs40
-rw-r--r--tests/ui/borrowck/issue-92157.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
634 files changed, 21907 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 000000000..9bd90e70a
--- /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 000000000..abee72ba8
--- /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 000000000..7799a7cb1
--- /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 000000000..9e100f8ac
--- /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 000000000..4f30ea146
--- /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 000000000..b60726d0c
--- /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 000000000..1ed92865d
--- /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 000000000..487d1ac81
--- /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 000000000..af720ad29
--- /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 000000000..baf31bd89
--- /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 000000000..50eee1049
--- /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 000000000..57198cb95
--- /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 000000000..6235e0db0
--- /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 000000000..a3350024e
--- /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 000000000..a0eaf1f16
--- /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 000000000..f25fd7f66
--- /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 000000000..6f7b7e080
--- /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 000000000..e381384fe
--- /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 000000000..712873528
--- /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 000000000..4cc1d821d
--- /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 000000000..e1cf2dc53
--- /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 000000000..320c54b80
--- /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 000000000..a77482091
--- /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 000000000..c628fa49e
--- /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 000000000..befa751a6
--- /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 000000000..469ad508b
--- /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 000000000..26f3e2bbd
--- /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 000000000..eeb4f05d6
--- /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 000000000..5abf07a31
--- /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 000000000..a05dfe62b
--- /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 000000000..7a959fb6e
--- /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 000000000..de2a8d832
--- /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 000000000..88a8867f5
--- /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 000000000..6e63de913
--- /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 000000000..98f6f00a7
--- /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 000000000..5d776d4fc
--- /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 000000000..1c992dfcc
--- /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 000000000..f4dffeb8c
--- /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 000000000..b80174ae6
--- /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 000000000..98bb2d85a
--- /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 000000000..2b7cef7b3
--- /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 000000000..879c03791
--- /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 000000000..cbacc87a0
--- /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 000000000..f7aee2b8a
--- /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 000000000..0b21d113f
--- /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 000000000..5881dccf6
--- /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 000000000..864d933da
--- /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 000000000..050d702b6
--- /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 000000000..72bf43da9
--- /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 000000000..247e3da18
--- /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 000000000..19ef0301a
--- /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 000000000..2ff3d5bd3
--- /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 000000000..c2dfb687e
--- /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 000000000..b0bb9a035
--- /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 000000000..e273a778f
--- /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 000000000..b2afb6391
--- /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 000000000..371bcf2b6
--- /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 000000000..c2d2e02ec
--- /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 000000000..8d13b25a3
--- /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 000000000..f47921a97
--- /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 000000000..24efadc30
--- /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 000000000..353e4e9f7
--- /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 000000000..c2351aacd
--- /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 000000000..231f6beab
--- /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 000000000..8fcaaa883
--- /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 000000000..92f3ffd57
--- /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 000000000..71bf052c9
--- /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 000000000..6b5544a8a
--- /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 000000000..3c28ff56e
--- /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 000000000..7a88c3df2
--- /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 000000000..ce9f7aa05
--- /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 000000000..b4d85b60c
--- /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 000000000..42b6c34cd
--- /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 000000000..5ef282c0c
--- /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 000000000..83eab7fde
--- /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 000000000..fdf6568d8
--- /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 000000000..2b98a7b94
--- /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 000000000..9ed9d2924
--- /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 000000000..e384aacb7
--- /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 000000000..4eeec09b9
--- /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 000000000..8bf6a2f6d
--- /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 000000000..85481336a
--- /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 000000000..c62d5f903
--- /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 000000000..e880f876f
--- /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 000000000..3abca33a8
--- /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 000000000..ea93a8f40
--- /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 000000000..824f91dbc
--- /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 000000000..a7a8fc2ff
--- /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 000000000..a8225f2fa
--- /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 000000000..fadcd11a5
--- /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 000000000..d7e187a2b
--- /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 000000000..537ec9895
--- /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 000000000..50c6f2c58
--- /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 000000000..e5ee5a401
--- /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 000000000..0229ca37a
--- /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 000000000..32057d5c1
--- /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 000000000..411d85b8e
--- /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 000000000..ab135194a
--- /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 000000000..63a75cdff
--- /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 000000000..fe8e7a29e
--- /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 000000000..cdff8f9e8
--- /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 000000000..21e329f43
--- /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 000000000..0dd004769
--- /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 000000000..0c5fd39b7
--- /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 000000000..67f91dfa8
--- /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 000000000..23d3cc0e7
--- /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 000000000..be5f1f873
--- /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 000000000..30900a3b6
--- /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 000000000..347f0212c
--- /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 000000000..d2e9497d0
--- /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 000000000..6b32d185b
--- /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 000000000..ed7e883ca
--- /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 000000000..cdcff69d6
--- /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 000000000..2c1b9c10d
--- /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 000000000..0f320af26
--- /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 000000000..9fa28efd8
--- /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 000000000..11c0610aa
--- /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 000000000..acf6b37b7
--- /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 000000000..b50d45563
--- /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 000000000..814042539
--- /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 000000000..dd6708582
--- /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 000000000..03edf445e
--- /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 000000000..e009f5913
--- /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 000000000..126323d8d
--- /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 000000000..d4ceae296
--- /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 000000000..e7491afda
--- /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 000000000..c638cd08b
--- /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 000000000..d48866dce
--- /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 000000000..389b8a43c
--- /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 000000000..f9ced03e0
--- /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 000000000..a84b695aa
--- /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 000000000..f47dce453
--- /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 000000000..f619c045b
--- /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 000000000..fc1a44c3c
--- /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 000000000..199931d6d
--- /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 000000000..534d771be
--- /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 000000000..9eafc2c2a
--- /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 000000000..69d450c59
--- /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 000000000..3f0fe291c
--- /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 000000000..97107c2e3
--- /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 000000000..a66db05cc
--- /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 000000000..a45f7b18e
--- /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 000000000..2033e4a57
--- /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 000000000..e6476b9c1
--- /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 000000000..1a22b5f09
--- /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 000000000..7eb204a0d
--- /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 000000000..f1b9b9aa7
--- /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 000000000..c07957ab1
--- /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 000000000..39b28811a
--- /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 000000000..3d08c1b81
--- /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 000000000..ef0fa6df4
--- /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 000000000..2a52a3f4e
--- /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 000000000..cec053318
--- /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 000000000..df967e611
--- /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 000000000..99d08e905
--- /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 000000000..003533a51
--- /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 000000000..42a55b7a8
--- /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 000000000..0fb2267b9
--- /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 000000000..390bb9384
--- /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 000000000..625e7c3ca
--- /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 000000000..f79a846e7
--- /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 000000000..850bb9ae3
--- /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 000000000..86061c8cd
--- /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 000000000..ee174f673
--- /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 000000000..d0ef2dcdd
--- /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 000000000..19a0dd0c6
--- /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 000000000..e47efc0e0
--- /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 000000000..548ffbd51
--- /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 000000000..df7c86b85
--- /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 000000000..9737bc769
--- /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 000000000..66f1cd9bd
--- /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 000000000..564c57044
--- /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 000000000..40c14f54c
--- /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 000000000..e536d4040
--- /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 000000000..3548da35b
--- /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 000000000..f3f443721
--- /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 000000000..b5c6b101f
--- /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 000000000..33d6af303
--- /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 000000000..fa5308c29
--- /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 000000000..b8f1650fc
--- /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 000000000..e1b991620
--- /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 000000000..cb801ef1b
--- /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 000000000..6994c837d
--- /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 000000000..4da10fd44
--- /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 000000000..24cc4933e
--- /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 000000000..d2234e17a
--- /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 000000000..1d6bd4e2e
--- /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 000000000..300ec88c5
--- /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 000000000..6691a2396
--- /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 000000000..b6eebd4e3
--- /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 000000000..9d19de211
--- /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 000000000..ffb2da280
--- /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 000000000..6ea6951ad
--- /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 000000000..0aaa4e4c6
--- /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 000000000..4e969f6ed
--- /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 000000000..a925cbbf5
--- /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 000000000..39047be9d
--- /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 000000000..064bf69ae
--- /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 000000000..dd22d7e2e
--- /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 000000000..e7a48ebf6
--- /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 000000000..6f0eb1870
--- /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 000000000..8ddc48b2a
--- /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 000000000..cf6c382a6
--- /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 000000000..f336ac4f9
--- /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 000000000..722c2c144
--- /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 000000000..71405f7a7
--- /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 000000000..f833abcc0
--- /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 000000000..824da5ceb
--- /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 000000000..43fc102bd
--- /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 000000000..f4f402dd9
--- /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 000000000..21bd07332
--- /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 000000000..72e7b5a71
--- /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 000000000..9509ebb7c
--- /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 000000000..fa2d5531b
--- /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 000000000..d5ff0c501
--- /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 000000000..ced4d002b
--- /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 000000000..67b00c1dd
--- /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 000000000..97db70f34
--- /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 000000000..47429ea3e
--- /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 000000000..c91b4286b
--- /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 000000000..604a25cdc
--- /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 000000000..bfab13d42
--- /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 000000000..017ca90b8
--- /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 000000000..8412c24fe
--- /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 000000000..e3498cef3
--- /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 000000000..ad08367a3
--- /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 000000000..e2aeaafc6
--- /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 000000000..83755812f
--- /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 000000000..dd456681f
--- /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 000000000..0b9e7102c
--- /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 000000000..87135f0bb
--- /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 000000000..ecb135f68
--- /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 000000000..599fa1e88
--- /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 000000000..d01fb2618
--- /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 000000000..edf8c954f
--- /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 000000000..c463c6559
--- /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 000000000..93183062d
--- /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 000000000..58f706c65
--- /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 000000000..bc2ddf85f
--- /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 000000000..f050bce87
--- /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 000000000..160a1f99f
--- /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 000000000..8ece81a3c
--- /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 000000000..9ff20a1f4
--- /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 000000000..38abd1932
--- /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 000000000..8c9083fcf
--- /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 000000000..96d266350
--- /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 000000000..57b3819ac
--- /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 000000000..f94cbc30d
--- /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 000000000..a79a239cb
--- /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 000000000..20528e3f0
--- /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 000000000..e3d76398b
--- /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 000000000..d2b845619
--- /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 000000000..6174893ba
--- /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 000000000..ef811b849
--- /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 000000000..8e23571ce
--- /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 000000000..8ab472e64
--- /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 000000000..255b4995b
--- /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 000000000..d2b0c0154
--- /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 000000000..d80a9e815
--- /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 000000000..dbb3272fd
--- /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 000000000..f035049d8
--- /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 000000000..3462b7610
--- /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 000000000..137a9adbc
--- /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 000000000..215ed760a
--- /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 000000000..079cf899e
--- /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 000000000..16d66bf40
--- /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 000000000..7b16bf666
--- /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 000000000..723b19f41
--- /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 000000000..0e3e01a93
--- /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 000000000..5d52e4919
--- /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 000000000..3d3a3afd3
--- /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 000000000..087f2ac79
--- /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 000000000..344d75cc5
--- /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 000000000..f5f4817e9
--- /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 000000000..00f448314
--- /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 000000000..fb0e274c2
--- /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 000000000..8adafaa8e
--- /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 000000000..2f92c1ebe
--- /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 000000000..4e6951581
--- /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 000000000..65f2bd6cf
--- /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 000000000..06cd322e7
--- /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 000000000..36a871fbb
--- /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 000000000..ca484315b
--- /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 000000000..05f5411ee
--- /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 000000000..a43a19366
--- /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 000000000..d12a482cb
--- /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 000000000..7f9c5544d
--- /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 000000000..f02c46fb8
--- /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 000000000..9e65ccf5a
--- /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 000000000..1362fd8ce
--- /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 000000000..eef83c5ac
--- /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 000000000..d9590e446
--- /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 000000000..779cb3bbe
--- /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 000000000..f28c42ce2
--- /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 000000000..ae5bb8591
--- /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 000000000..5cfd81bd0
--- /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 000000000..866b3a2a8
--- /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 000000000..f785900d5
--- /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 000000000..6f323d912
--- /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 000000000..d05996413
--- /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 000000000..75e5e7fd4
--- /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 000000000..d54449ac4
--- /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 000000000..a63ffcff7
--- /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 000000000..9799357c9
--- /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 000000000..c4695c942
--- /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 000000000..e89332ae3
--- /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 000000000..a8e56f648
--- /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 000000000..6b210d732
--- /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 000000000..f4324110c
--- /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 000000000..4367596c6
--- /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 000000000..6390dc3a9
--- /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 000000000..0e1c90a1c
--- /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 000000000..f9a63bd49
--- /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 000000000..5f4379325
--- /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 000000000..fe9844610
--- /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 000000000..3a413153a
--- /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 000000000..1f6ed6d46
--- /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 000000000..af32f2791
--- /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 000000000..8170323ef
--- /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 000000000..b39215b9a
--- /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 000000000..1cf8d187c
--- /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 000000000..26453b42f
--- /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 000000000..8a6dfe76d
--- /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 000000000..3b4c0731f
--- /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 000000000..aab225ed4
--- /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 000000000..f0048dd7d
--- /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 000000000..363467646
--- /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 000000000..e97ce6aa4
--- /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 000000000..071598b42
--- /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 000000000..bc931eef9
--- /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 000000000..f0f4ad704
--- /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 000000000..92c3692bd
--- /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 000000000..fdbb451bd
--- /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 000000000..c36b9707d
--- /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 000000000..73fded754
--- /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 000000000..5d0ebabb0
--- /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 000000000..eeafc4ce1
--- /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 000000000..b3a6670fa
--- /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 000000000..4bd7d54cf
--- /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 000000000..f01915398
--- /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 000000000..090c7b6b5
--- /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 000000000..4c96ccdb2
--- /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 000000000..af6f6fac4
--- /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 000000000..510547ad5
--- /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 000000000..731607fbd
--- /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 000000000..bbe9f22aa
--- /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 000000000..b7ff5f395
--- /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 000000000..25d3e0b54
--- /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 000000000..6dbe4c74b
--- /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 000000000..bdf7cc57a
--- /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 000000000..c78e94752
--- /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 000000000..adc7dfd54
--- /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 000000000..23ef975cb
--- /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 000000000..d30b1de5c
--- /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 000000000..18e808f10
--- /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 000000000..1cf763f66
--- /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 000000000..94f88395f
--- /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 000000000..91d69c51e
--- /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 000000000..3ce721618
--- /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 000000000..55f3ff553
--- /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 000000000..a355a546d
--- /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 000000000..ea3d0d3ef
--- /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 000000000..cd853b833
--- /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 000000000..170982b16
--- /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 000000000..05859c95d
--- /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 000000000..eb0f24b9b
--- /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 000000000..9b8ba2ea8
--- /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 000000000..0ac7df944
--- /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 000000000..0e9284a2c
--- /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 000000000..0dc5e64e4
--- /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 000000000..39872825c
--- /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 000000000..7e21c55f2
--- /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 000000000..7100b7130
--- /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 000000000..13143d436
--- /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 000000000..62a9bdd20
--- /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 000000000..5d0194989
--- /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 000000000..f49a778eb
--- /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 000000000..c45235990
--- /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 000000000..dff952834
--- /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 000000000..1685acf87
--- /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 000000000..17de40d5b
--- /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 000000000..9a84c6fef
--- /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 000000000..524459291
--- /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 000000000..78ca090fe
--- /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 000000000..85e0a840a
--- /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 000000000..242a33e82
--- /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 000000000..d5392e7d6
--- /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 000000000..2352d1bbe
--- /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 000000000..bddb0633a
--- /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 000000000..44b57c4a0
--- /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 000000000..69dca7e7b
--- /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 000000000..35266e113
--- /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 000000000..f42d7e015
--- /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 000000000..64e52eaac
--- /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 000000000..a22afdc67
--- /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 000000000..37628bff7
--- /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 000000000..351de8217
--- /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 000000000..0340f3924
--- /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 000000000..46565f61c
--- /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 000000000..4a2378352
--- /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 000000000..f1fa95f92
--- /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 000000000..e6a35dd88
--- /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 000000000..db1f8f8d5
--- /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 000000000..22eaa119f
--- /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 000000000..139bd9a07
--- /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 000000000..cb77f89fb
--- /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 000000000..2720b09b0
--- /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 000000000..4f560b065
--- /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 000000000..ced6fff31
--- /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 000000000..3ae7e64d2
--- /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 000000000..015487a06
--- /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 000000000..65aea5b18
--- /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 000000000..c3f136f28
--- /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 000000000..215bf0100
--- /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 000000000..d45aaa843
--- /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 000000000..c419c5840
--- /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 000000000..58d1c8c0f
--- /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 000000000..6c8dacc22
--- /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 000000000..da3412f11
--- /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 000000000..1e48878f6
--- /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 000000000..ca819ba39
--- /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 000000000..5b824adc6
--- /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 000000000..18f371c20
--- /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 000000000..fff5015cd
--- /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 000000000..f77fdbf2b
--- /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 000000000..8fc963a85
--- /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 000000000..20f66b4d4
--- /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 000000000..a6357f818
--- /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 000000000..38a01b138
--- /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 000000000..716cc9d0c
--- /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 000000000..a7636edf2
--- /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 000000000..29b4c8c38
--- /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 000000000..ded46e56e
--- /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 000000000..47aa30908
--- /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 000000000..6784f6f86
--- /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 000000000..feb098c59
--- /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 000000000..59ddb60c9
--- /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 000000000..8922005d2
--- /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 000000000..935414c1f
--- /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 000000000..e95a6b7c8
--- /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 000000000..8d4918867
--- /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 000000000..e4664e4f3
--- /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 000000000..ef1a16ea9
--- /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 000000000..7e0a5190f
--- /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 000000000..6ec920cb8
--- /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 000000000..7d5acb957
--- /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 000000000..92943f6c9
--- /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 000000000..56ed57a61
--- /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 000000000..0d486b455
--- /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 000000000..671e83dfa
--- /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 000000000..4abb6fb2c
--- /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 000000000..fc8a07554
--- /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 000000000..f1fd1b507
--- /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 000000000..f0b574846
--- /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 000000000..205ea10c9
--- /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 000000000..2a0eba396
--- /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 000000000..f7fb2fd4d
--- /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 000000000..b188766e2
--- /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 000000000..498ca01e9
--- /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 000000000..774b6cf0e
--- /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 000000000..50d0c40fd
--- /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 000000000..67a625830
--- /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 000000000..3e46ee6f0
--- /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 000000000..99c63e4db
--- /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 000000000..b3cce1b3a
--- /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 000000000..4c299cdc4
--- /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 000000000..b87ef3baa
--- /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 000000000..efa313a9d
--- /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 000000000..57803247b
--- /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 000000000..f6fbea821
--- /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 000000000..5b21c0838
--- /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 000000000..93ce34d2f
--- /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 000000000..9683da919
--- /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 000000000..33d55be58
--- /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 000000000..245c3a40e
--- /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 000000000..f6d0e9e04
--- /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 000000000..369a8c61d
--- /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 000000000..42100edea
--- /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 000000000..7c0741153
--- /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 000000000..9d86286b8
--- /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 000000000..1b8caa3f8
--- /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 000000000..8e212a770
--- /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 000000000..d79394834
--- /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 000000000..7602e184a
--- /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 000000000..27123ef2b
--- /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 000000000..6b558c65d
--- /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 000000000..0770c1366
--- /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 000000000..fbbdd93b9
--- /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 000000000..764eaaa7c
--- /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 000000000..9a9e3a313
--- /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 000000000..9447174fd
--- /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 000000000..b2643eb33
--- /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 000000000..0ab3fa927
--- /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 000000000..d36b79615
--- /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 000000000..20ff229ff
--- /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 000000000..85ea77756
--- /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 000000000..575aed73b
--- /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 000000000..cbf70f11a
--- /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 000000000..52d2d9e75
--- /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 000000000..0bb1033fb
--- /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 000000000..fd83e10a2
--- /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 000000000..cd57afa28
--- /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 000000000..c7d48214f
--- /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 000000000..1f1af5c7e
--- /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 000000000..1b03bc3af
--- /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 000000000..4a01b60c1
--- /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 000000000..25f343117
--- /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 000000000..dd0320bc5
--- /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 000000000..d2b927fb6
--- /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 000000000..5a3c64255
--- /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 000000000..a2c291f77
--- /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 000000000..d301e7b35
--- /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 000000000..26ce007dd
--- /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 000000000..e25b4f727
--- /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 000000000..a585bff0c
--- /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 000000000..ccc120c54
--- /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 000000000..59ca4867f
--- /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 000000000..1598cd5d3
--- /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 000000000..7da7dba68
--- /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 000000000..9fc12ba74
--- /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 000000000..afd141125
--- /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 000000000..b75abcb73
--- /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 000000000..a5a571c6d
--- /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 000000000..f9134e669
--- /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 000000000..00023c459
--- /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 000000000..67407c1ea
--- /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 000000000..12d8d27c5
--- /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 000000000..16d651717
--- /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 000000000..62b1183e7
--- /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-92157.rs b/tests/ui/borrowck/issue-92157.rs
new file mode 100644
index 000000000..6ee2320a6
--- /dev/null
+++ b/tests/ui/borrowck/issue-92157.rs
@@ -0,0 +1,40 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+
+#![no_core]
+
+#[cfg(target_os = "linux")]
+#[link(name = "c")]
+extern {}
+
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+ //~^ ERROR: incorrect number of parameters for the `start` lang item
+ 40+2
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ drop_in_place(to_drop)
+}
+
+#[lang = "add"]
+trait Add<RHS> {
+ type Output;
+ fn add(self, other: RHS) -> Self::Output;
+}
+
+impl Add<isize> for isize {
+ type Output = isize;
+ fn add(self, other: isize) -> isize {
+ self + other
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr
new file mode 100644
index 000000000..a4010d73d
--- /dev/null
+++ b/tests/ui/borrowck/issue-92157.stderr
@@ -0,0 +1,11 @@
+error: incorrect number of parameters for the `start` lang item
+ --> $DIR/issue-92157.rs:11:1
+ |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `start` lang item should have four parameters, but found 3
+ = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/borrowck/issue-93078.rs b/tests/ui/borrowck/issue-93078.rs
new file mode 100644
index 000000000..2e608c5db
--- /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 000000000..771a652a1
--- /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 000000000..f4db5ecaf
--- /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 000000000..afa76594f
--- /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 000000000..95847d8d3
--- /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 000000000..2eae614a2
--- /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 000000000..5b5d86eec
--- /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 000000000..a4b5d18bb
--- /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 000000000..3e6ea9d25
--- /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 000000000..aa0cbcffd
--- /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 000000000..13da34f39
--- /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 000000000..38dba94bd
--- /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 000000000..b94db6451
--- /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 000000000..a4432e38d
--- /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 000000000..c77f6c827
--- /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 000000000..64f956538
--- /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 000000000..8ac711e9e
--- /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 000000000..0bd2147f4
--- /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 000000000..700785827
--- /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 000000000..4b42f9d4c
--- /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 000000000..55948afca
--- /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 000000000..b5c275bf2
--- /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 000000000..dd3471e2c
--- /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 000000000..145893d33
--- /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 000000000..14851d0f6
--- /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 000000000..250acbe59
--- /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 000000000..c2a59a105
--- /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 000000000..6619fb42c
--- /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 000000000..ceeba30a9
--- /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 000000000..d13fb7e56
--- /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 000000000..74e7067c9
--- /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 000000000..22667906e
--- /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 000000000..b621694a5
--- /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 000000000..477a2aa48
--- /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 000000000..c6f75b1c0
--- /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 000000000..c02bfbf87
--- /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 000000000..e6895b27f
--- /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 000000000..82116425f
--- /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 000000000..d7c602718
--- /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 000000000..aeab3b92e
--- /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 000000000..9501798bb
--- /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 000000000..3576734de
--- /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 000000000..60af41237
--- /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 000000000..fd2ab62a4
--- /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 000000000..e6b25573e
--- /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 000000000..d7aad6c01
--- /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 000000000..81e5bc45d
--- /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 000000000..2775a54c8
--- /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 000000000..ba0457809
--- /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 000000000..31eba0740
--- /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 000000000..ecd916a59
--- /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 000000000..141ad5bd2
--- /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 000000000..930fea915
--- /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 000000000..0e98d98cf
--- /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 000000000..14393bc8e
--- /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 000000000..f896ae7bd
--- /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 000000000..a23fdacde
--- /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 000000000..f01e47122
--- /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 000000000..153f77c89
--- /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 000000000..c6643edf5
--- /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 000000000..9f952542e
--- /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 000000000..0e0e3cda6
--- /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 000000000..f9ed16f19
--- /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 000000000..1dcf04618
--- /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 000000000..4621d8793
--- /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 000000000..aaca9d47f
--- /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 000000000..92acba640
--- /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 000000000..d5996ba68
--- /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 000000000..3a43c18a7
--- /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 000000000..40f013f6a
--- /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 000000000..615fffcd5
--- /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 000000000..bf167ba79
--- /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 000000000..eb934e7b7
--- /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 000000000..40f013f6a
--- /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 000000000..e3a16eddf
--- /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 000000000..3fcea7d17
--- /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 000000000..22f9b39df
--- /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 000000000..aacf17893
--- /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 000000000..8b880ff64
--- /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 000000000..a57ceb847
--- /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 000000000..67d084207
--- /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 000000000..994dc823d
--- /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 000000000..1242ae307
--- /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 000000000..dd2ef4e27
--- /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 000000000..21b0eddb9
--- /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 000000000..0b20e1945
--- /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 000000000..6b879af5a
--- /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 000000000..bb646d7ca
--- /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 000000000..2e53e17a3
--- /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 000000000..53fb71ebe
--- /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 000000000..efd63a08a
--- /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 000000000..da238205b
--- /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 000000000..27e599c6c
--- /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 000000000..9e0f68b65
--- /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 000000000..e3e4057d6
--- /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 000000000..0463e22b3
--- /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 000000000..bf06366de
--- /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 000000000..117d7ceae
--- /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 000000000..6d37d1ded
--- /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 000000000..5a240d900
--- /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 000000000..b0c537610
--- /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 000000000..4666b8a33
--- /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 000000000..f033d53bf
--- /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`.