summaryrefslogtreecommitdiffstats
path: root/tests/ui/nll
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/nll')
-rw-r--r--tests/ui/nll/assign-while-to-immutable.rs11
-rw-r--r--tests/ui/nll/borrow-use-issue-46875.rs18
-rw-r--r--tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs25
-rw-r--r--tests/ui/nll/borrowed-local-error.rs12
-rw-r--r--tests/ui/nll/borrowed-local-error.stderr15
-rw-r--r--tests/ui/nll/borrowed-match-issue-45045.rs18
-rw-r--r--tests/ui/nll/borrowed-match-issue-45045.stderr15
-rw-r--r--tests/ui/nll/borrowed-referent-issue-38899.rs17
-rw-r--r--tests/ui/nll/borrowed-referent-issue-38899.stderr15
-rw-r--r--tests/ui/nll/borrowed-temporary-error.rs12
-rw-r--r--tests/ui/nll/borrowed-temporary-error.stderr16
-rw-r--r--tests/ui/nll/borrowed-universal-error-2.rs7
-rw-r--r--tests/ui/nll/borrowed-universal-error-2.stderr9
-rw-r--r--tests/ui/nll/borrowed-universal-error.rs11
-rw-r--r--tests/ui/nll/borrowed-universal-error.stderr12
-rw-r--r--tests/ui/nll/cannot-move-block-spans.rs22
-rw-r--r--tests/ui/nll/cannot-move-block-spans.stderr118
-rw-r--r--tests/ui/nll/capture-mut-ref.fixed16
-rw-r--r--tests/ui/nll/capture-mut-ref.rs16
-rw-r--r--tests/ui/nll/capture-mut-ref.stderr16
-rw-r--r--tests/ui/nll/capture-ref-in-struct.rs36
-rw-r--r--tests/ui/nll/capture-ref-in-struct.stderr15
-rw-r--r--tests/ui/nll/closure-access-spans.rs56
-rw-r--r--tests/ui/nll/closure-access-spans.stderr120
-rw-r--r--tests/ui/nll/closure-borrow-spans.rs100
-rw-r--r--tests/ui/nll/closure-borrow-spans.stderr172
-rw-r--r--tests/ui/nll/closure-captures.rs55
-rw-r--r--tests/ui/nll/closure-captures.stderr148
-rw-r--r--tests/ui/nll/closure-malformed-projection-input-issue-102800.rs21
-rw-r--r--tests/ui/nll/closure-malformed-projection-input-issue-102800.stderr20
-rw-r--r--tests/ui/nll/closure-move-spans.rs21
-rw-r--r--tests/ui/nll/closure-move-spans.stderr39
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument-callee.rs42
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument-callee.stderr31
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument.rs42
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument.stderr35
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-nested.rs33
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-nested.stderr53
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-ref.rs33
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-ref.stderr39
-rw-r--r--tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs36
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs51
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr36
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-ref.rs50
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr39
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs40
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr69
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs40
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr49
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs43
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr49
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-val.rs43
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-val.stderr39
-rw-r--r--tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs50
-rw-r--r--tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr23
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs42
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr35
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs46
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr35
-rw-r--r--tests/ui/nll/closure-requirements/propagate-from-trait-match.rs48
-rw-r--r--tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr38
-rw-r--r--tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs23
-rw-r--r--tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr17
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs13
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs13
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs13
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr14
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs11
-rw-r--r--tests/ui/nll/closure-requirements/return-wrong-bound-region.rs23
-rw-r--r--tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr31
-rw-r--r--tests/ui/nll/closure-use-spans.rs21
-rw-r--r--tests/ui/nll/closure-use-spans.stderr33
-rw-r--r--tests/ui/nll/closures-in-loops.rs24
-rw-r--r--tests/ui/nll/closures-in-loops.stderr35
-rw-r--r--tests/ui/nll/constant-thread-locals-issue-47053.rs10
-rw-r--r--tests/ui/nll/constant-thread-locals-issue-47053.stderr9
-rw-r--r--tests/ui/nll/constant.rs10
-rw-r--r--tests/ui/nll/continue-after-missing-main.rs29
-rw-r--r--tests/ui/nll/continue-after-missing-main.stderr9
-rw-r--r--tests/ui/nll/decl-macro-illegal-copy.rs28
-rw-r--r--tests/ui/nll/decl-macro-illegal-copy.stderr14
-rw-r--r--tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.rs12
-rw-r--r--tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr14
-rw-r--r--tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.rs11
-rw-r--r--tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr14
-rw-r--r--tests/ui/nll/dont-print-desugared.rs21
-rw-r--r--tests/ui/nll/dont-print-desugared.stderr24
-rw-r--r--tests/ui/nll/drop-may-dangle.rs34
-rw-r--r--tests/ui/nll/drop-no-may-dangle.rs30
-rw-r--r--tests/ui/nll/drop-no-may-dangle.stderr26
-rw-r--r--tests/ui/nll/empty-type-predicate-2.rs18
-rw-r--r--tests/ui/nll/empty-type-predicate.rs11
-rw-r--r--tests/ui/nll/enum-drop-access.rs49
-rw-r--r--tests/ui/nll/enum-drop-access.stderr31
-rw-r--r--tests/ui/nll/extra-unused-mut.rs66
-rw-r--r--tests/ui/nll/generator-distinct-lifetime.rs25
-rw-r--r--tests/ui/nll/generator-upvar-mutability.rs14
-rw-r--r--tests/ui/nll/generator-upvar-mutability.stderr12
-rw-r--r--tests/ui/nll/get_default.polonius.stderr18
-rw-r--r--tests/ui/nll/get_default.rs44
-rw-r--r--tests/ui/nll/get_default.stderr48
-rw-r--r--tests/ui/nll/guarantor-issue-46974.rs19
-rw-r--r--tests/ui/nll/guarantor-issue-46974.stderr23
-rw-r--r--tests/ui/nll/issue-16223.rs52
-rw-r--r--tests/ui/nll/issue-21114-ebfull.rs18
-rw-r--r--tests/ui/nll/issue-21114-kixunil.rs17
-rw-r--r--tests/ui/nll/issue-21232-partial-init-and-erroneous-use.rs60
-rw-r--r--tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr64
-rw-r--r--tests/ui/nll/issue-21232-partial-init-and-use.rs297
-rw-r--r--tests/ui/nll/issue-21232-partial-init-and-use.stderr260
-rw-r--r--tests/ui/nll/issue-22323-temp-destruction.rs30
-rw-r--r--tests/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs63
-rw-r--r--tests/ui/nll/issue-27282-move-match-input-into-guard.rs34
-rw-r--r--tests/ui/nll/issue-27282-move-match-input-into-guard.stderr29
-rw-r--r--tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs23
-rw-r--r--tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr23
-rw-r--r--tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.rs31
-rw-r--r--tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.stderr14
-rw-r--r--tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.rs40
-rw-r--r--tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.stderr14
-rw-r--r--tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.rs30
-rw-r--r--tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.stderr14
-rw-r--r--tests/ui/nll/issue-27282-mutation-in-guard.rs26
-rw-r--r--tests/ui/nll/issue-27282-mutation-in-guard.stderr23
-rw-r--r--tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs30
-rw-r--r--tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr23
-rw-r--r--tests/ui/nll/issue-27868.rs28
-rw-r--r--tests/ui/nll/issue-27868.stderr18
-rw-r--r--tests/ui/nll/issue-30104.rs40
-rw-r--r--tests/ui/nll/issue-31567.rs25
-rw-r--r--tests/ui/nll/issue-31567.stderr16
-rw-r--r--tests/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs41
-rw-r--r--tests/ui/nll/issue-42574-diagnostic-in-nested-closure.rs11
-rw-r--r--tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr26
-rw-r--r--tests/ui/nll/issue-43058.rs26
-rw-r--r--tests/ui/nll/issue-45157.rs31
-rw-r--r--tests/ui/nll/issue-45157.stderr17
-rw-r--r--tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs114
-rw-r--r--tests/ui/nll/issue-45696-no-variant-box-recur.rs47
-rw-r--r--tests/ui/nll/issue-45696-scribble-on-boxed-borrow.rs67
-rw-r--r--tests/ui/nll/issue-45696-scribble-on-boxed-borrow.stderr33
-rw-r--r--tests/ui/nll/issue-46023.rs8
-rw-r--r--tests/ui/nll/issue-46023.stderr12
-rw-r--r--tests/ui/nll/issue-46036.rs12
-rw-r--r--tests/ui/nll/issue-46036.stderr15
-rw-r--r--tests/ui/nll/issue-46589.rs31
-rw-r--r--tests/ui/nll/issue-46589.stderr15
-rw-r--r--tests/ui/nll/issue-47022.rs33
-rw-r--r--tests/ui/nll/issue-47153-generic-const.rs18
-rw-r--r--tests/ui/nll/issue-47388.rs10
-rw-r--r--tests/ui/nll/issue-47388.stderr14
-rw-r--r--tests/ui/nll/issue-47470.rs22
-rw-r--r--tests/ui/nll/issue-47470.stderr9
-rw-r--r--tests/ui/nll/issue-47589.rs23
-rw-r--r--tests/ui/nll/issue-48070.rs22
-rw-r--r--tests/ui/nll/issue-48238.rs10
-rw-r--r--tests/ui/nll/issue-48238.stderr13
-rw-r--r--tests/ui/nll/issue-48623-closure.rs16
-rw-r--r--tests/ui/nll/issue-48623-generator.rs18
-rw-r--r--tests/ui/nll/issue-48623-generator.stderr11
-rw-r--r--tests/ui/nll/issue-48697.rs10
-rw-r--r--tests/ui/nll/issue-48697.stderr11
-rw-r--r--tests/ui/nll/issue-48803.rs13
-rw-r--r--tests/ui/nll/issue-48803.stderr15
-rw-r--r--tests/ui/nll/issue-50343.rs8
-rw-r--r--tests/ui/nll/issue-50461-used-mut-from-moves.rs17
-rw-r--r--tests/ui/nll/issue-50716-1.rs10
-rw-r--r--tests/ui/nll/issue-50716.rs17
-rw-r--r--tests/ui/nll/issue-50716.stderr11
-rw-r--r--tests/ui/nll/issue-51191.rs34
-rw-r--r--tests/ui/nll/issue-51191.stderr72
-rw-r--r--tests/ui/nll/issue-51244.rs5
-rw-r--r--tests/ui/nll/issue-51244.stderr14
-rw-r--r--tests/ui/nll/issue-51268.rs21
-rw-r--r--tests/ui/nll/issue-51268.stderr17
-rw-r--r--tests/ui/nll/issue-51345-2.rs8
-rw-r--r--tests/ui/nll/issue-51351.rs21
-rw-r--r--tests/ui/nll/issue-51512.rs6
-rw-r--r--tests/ui/nll/issue-51512.stderr18
-rw-r--r--tests/ui/nll/issue-51770.rs19
-rw-r--r--tests/ui/nll/issue-52057.rs22
-rw-r--r--tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs30
-rw-r--r--tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr48
-rw-r--r--tests/ui/nll/issue-52078.rs24
-rw-r--r--tests/ui/nll/issue-52086.rs14
-rw-r--r--tests/ui/nll/issue-52086.stderr15
-rw-r--r--tests/ui/nll/issue-52113.rs35
-rw-r--r--tests/ui/nll/issue-52113.stderr15
-rw-r--r--tests/ui/nll/issue-52213.rs15
-rw-r--r--tests/ui/nll/issue-52213.stderr15
-rw-r--r--tests/ui/nll/issue-52533-1.rs11
-rw-r--r--tests/ui/nll/issue-52533-1.stderr11
-rw-r--r--tests/ui/nll/issue-52534-1.rs48
-rw-r--r--tests/ui/nll/issue-52534-1.stderr57
-rw-r--r--tests/ui/nll/issue-52534-2.rs14
-rw-r--r--tests/ui/nll/issue-52534-2.stderr15
-rw-r--r--tests/ui/nll/issue-52534.rs19
-rw-r--r--tests/ui/nll/issue-52534.stderr31
-rw-r--r--tests/ui/nll/issue-52663-span-decl-captured-variable.rs11
-rw-r--r--tests/ui/nll/issue-52663-span-decl-captured-variable.stderr13
-rw-r--r--tests/ui/nll/issue-52663-trait-object.rs16
-rw-r--r--tests/ui/nll/issue-52663-trait-object.stderr13
-rw-r--r--tests/ui/nll/issue-52669.rs17
-rw-r--r--tests/ui/nll/issue-52669.stderr14
-rw-r--r--tests/ui/nll/issue-52742.rs17
-rw-r--r--tests/ui/nll/issue-52742.stderr12
-rw-r--r--tests/ui/nll/issue-52992.rs25
-rw-r--r--tests/ui/nll/issue-53040.rs5
-rw-r--r--tests/ui/nll/issue-53040.stderr17
-rw-r--r--tests/ui/nll/issue-53119.rs23
-rw-r--r--tests/ui/nll/issue-53123-raw-pointer-cast.rs26
-rw-r--r--tests/ui/nll/issue-53570.rs32
-rw-r--r--tests/ui/nll/issue-53773.rs47
-rw-r--r--tests/ui/nll/issue-53773.stderr14
-rw-r--r--tests/ui/nll/issue-53807.rs8
-rw-r--r--tests/ui/nll/issue-53807.stderr15
-rw-r--r--tests/ui/nll/issue-54189.rs6
-rw-r--r--tests/ui/nll/issue-54189.stderr9
-rw-r--r--tests/ui/nll/issue-54382-use-span-of-tail-of-block.rs29
-rw-r--r--tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr23
-rw-r--r--tests/ui/nll/issue-54556-niconii.rs31
-rw-r--r--tests/ui/nll/issue-54556-niconii.stderr23
-rw-r--r--tests/ui/nll/issue-54556-stephaneyfx.rs35
-rw-r--r--tests/ui/nll/issue-54556-stephaneyfx.stderr24
-rw-r--r--tests/ui/nll/issue-54556-temps-in-tail-diagnostic.rs23
-rw-r--r--tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr22
-rw-r--r--tests/ui/nll/issue-54556-used-vs-unused-tails.rs56
-rw-r--r--tests/ui/nll/issue-54556-used-vs-unused-tails.stderr146
-rw-r--r--tests/ui/nll/issue-54556-wrap-it-up.rs28
-rw-r--r--tests/ui/nll/issue-54556-wrap-it-up.stderr14
-rw-r--r--tests/ui/nll/issue-54779-anon-static-lifetime.rs49
-rw-r--r--tests/ui/nll/issue-54779-anon-static-lifetime.stderr11
-rw-r--r--tests/ui/nll/issue-54943-3.rs19
-rw-r--r--tests/ui/nll/issue-54943.rs10
-rw-r--r--tests/ui/nll/issue-54943.stderr11
-rw-r--r--tests/ui/nll/issue-55288.rs9
-rw-r--r--tests/ui/nll/issue-55344.rs14
-rw-r--r--tests/ui/nll/issue-55394.rs13
-rw-r--r--tests/ui/nll/issue-55394.stderr12
-rw-r--r--tests/ui/nll/issue-55401.rs6
-rw-r--r--tests/ui/nll/issue-55401.stderr11
-rw-r--r--tests/ui/nll/issue-55511.rs19
-rw-r--r--tests/ui/nll/issue-55511.stderr15
-rw-r--r--tests/ui/nll/issue-55651.rs28
-rw-r--r--tests/ui/nll/issue-55825-const-fn.rs8
-rw-r--r--tests/ui/nll/issue-55850.rs35
-rw-r--r--tests/ui/nll/issue-55850.stderr19
-rw-r--r--tests/ui/nll/issue-57100.rs67
-rw-r--r--tests/ui/nll/issue-57100.stderr31
-rw-r--r--tests/ui/nll/issue-57265-return-type-wf-check.rs24
-rw-r--r--tests/ui/nll/issue-57265-return-type-wf-check.stderr12
-rw-r--r--tests/ui/nll/issue-57280-1-flipped.rs23
-rw-r--r--tests/ui/nll/issue-57280-1-flipped.stderr11
-rw-r--r--tests/ui/nll/issue-57280-1.rs19
-rw-r--r--tests/ui/nll/issue-57280.rs20
-rw-r--r--tests/ui/nll/issue-57642-higher-ranked-subtype.rs38
-rw-r--r--tests/ui/nll/issue-57642-higher-ranked-subtype.stderr31
-rw-r--r--tests/ui/nll/issue-57843.rs26
-rw-r--r--tests/ui/nll/issue-57843.stderr11
-rw-r--r--tests/ui/nll/issue-57960.rs38
-rw-r--r--tests/ui/nll/issue-57989.rs10
-rw-r--r--tests/ui/nll/issue-57989.stderr26
-rw-r--r--tests/ui/nll/issue-58053.rs11
-rw-r--r--tests/ui/nll/issue-58053.stderr20
-rw-r--r--tests/ui/nll/issue-58299.rs27
-rw-r--r--tests/ui/nll/issue-58299.stderr20
-rw-r--r--tests/ui/nll/issue-61311-normalize.rs34
-rw-r--r--tests/ui/nll/issue-61320-normalize.rs160
-rw-r--r--tests/ui/nll/issue-61424.fixed9
-rw-r--r--tests/ui/nll/issue-61424.rs9
-rw-r--r--tests/ui/nll/issue-61424.stderr16
-rw-r--r--tests/ui/nll/issue-62007-assign-const-index.rs32
-rw-r--r--tests/ui/nll/issue-62007-assign-const-index.stderr27
-rw-r--r--tests/ui/nll/issue-62007-assign-differing-fields.rs25
-rw-r--r--tests/ui/nll/issue-62007-assign-differing-fields.stderr27
-rw-r--r--tests/ui/nll/issue-63154-normalize.rs34
-rw-r--r--tests/ui/nll/issue-67007-escaping-data.rs24
-rw-r--r--tests/ui/nll/issue-67007-escaping-data.stderr14
-rw-r--r--tests/ui/nll/issue-68550.rs15
-rw-r--r--tests/ui/nll/issue-68550.stderr16
-rw-r--r--tests/ui/nll/issue-69114-static-mut-ty.rs30
-rw-r--r--tests/ui/nll/issue-69114-static-mut-ty.stderr27
-rw-r--r--tests/ui/nll/issue-69114-static-ty.rs9
-rw-r--r--tests/ui/nll/issue-69114-static-ty.stderr15
-rw-r--r--tests/ui/nll/issue-73159-rpit-static.rs13
-rw-r--r--tests/ui/nll/issue-73159-rpit-static.stderr12
-rw-r--r--tests/ui/nll/issue-78561.rs23
-rw-r--r--tests/ui/nll/issue-95272.rs15
-rw-r--r--tests/ui/nll/issue-95272.stderr17
-rw-r--r--tests/ui/nll/issue-97997.rs16
-rw-r--r--tests/ui/nll/issue-97997.stderr20
-rw-r--r--tests/ui/nll/issue-98170.rs25
-rw-r--r--tests/ui/nll/issue-98170.stderr44
-rw-r--r--tests/ui/nll/issue-98589-closures-relate-named-regions.rs36
-rw-r--r--tests/ui/nll/issue-98589-closures-relate-named-regions.stderr61
-rw-r--r--tests/ui/nll/issue-98693.rs21
-rw-r--r--tests/ui/nll/issue-98693.stderr14
-rw-r--r--tests/ui/nll/lint-no-err.rs21
-rw-r--r--tests/ui/nll/loan_ends_mid_block_pair.rs29
-rw-r--r--tests/ui/nll/loan_ends_mid_block_pair.stderr15
-rw-r--r--tests/ui/nll/loan_ends_mid_block_vec.rs30
-rw-r--r--tests/ui/nll/loan_ends_mid_block_vec.stderr39
-rw-r--r--tests/ui/nll/local-outlives-static-via-hrtb.rs26
-rw-r--r--tests/ui/nll/local-outlives-static-via-hrtb.stderr38
-rw-r--r--tests/ui/nll/lub-if.rs44
-rw-r--r--tests/ui/nll/lub-if.stderr20
-rw-r--r--tests/ui/nll/lub-match.rs47
-rw-r--r--tests/ui/nll/lub-match.stderr20
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.rs70
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.stderr72
-rw-r--r--tests/ui/nll/match-cfg-fake-edges2.rs18
-rw-r--r--tests/ui/nll/match-cfg-fake-edges2.stderr15
-rw-r--r--tests/ui/nll/match-guards-always-borrow.rs64
-rw-r--r--tests/ui/nll/match-guards-always-borrow.stderr23
-rw-r--r--tests/ui/nll/match-guards-partially-borrow.rs332
-rw-r--r--tests/ui/nll/match-guards-partially-borrow.stderr170
-rw-r--r--tests/ui/nll/match-on-borrowed.rs96
-rw-r--r--tests/ui/nll/match-on-borrowed.stderr52
-rw-r--r--tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs19
-rw-r--r--tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr15
-rw-r--r--tests/ui/nll/maybe-initialized-drop-uninitialized.rs18
-rw-r--r--tests/ui/nll/maybe-initialized-drop-with-fragment.rs20
-rw-r--r--tests/ui/nll/maybe-initialized-drop-with-fragment.stderr14
-rw-r--r--tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs22
-rw-r--r--tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr15
-rw-r--r--tests/ui/nll/maybe-initialized-drop.rs15
-rw-r--r--tests/ui/nll/maybe-initialized-drop.stderr13
-rw-r--r--tests/ui/nll/mir_check_cast_closure.rs9
-rw-r--r--tests/ui/nll/mir_check_cast_closure.stderr15
-rw-r--r--tests/ui/nll/mir_check_cast_reify.rs39
-rw-r--r--tests/ui/nll/mir_check_cast_reify.stderr11
-rw-r--r--tests/ui/nll/mir_check_cast_unsafe_fn.rs11
-rw-r--r--tests/ui/nll/mir_check_cast_unsafe_fn.stderr11
-rw-r--r--tests/ui/nll/mir_check_cast_unsize.rs10
-rw-r--r--tests/ui/nll/mir_check_cast_unsize.stderr15
-rw-r--r--tests/ui/nll/move-errors.rs117
-rw-r--r--tests/ui/nll/move-errors.stderr210
-rw-r--r--tests/ui/nll/move-subpaths-moves-root.rs5
-rw-r--r--tests/ui/nll/move-subpaths-moves-root.stderr13
-rw-r--r--tests/ui/nll/mutating_references.rs24
-rw-r--r--tests/ui/nll/normalization-bounds-error.rs15
-rw-r--r--tests/ui/nll/normalization-bounds-error.stderr27
-rw-r--r--tests/ui/nll/normalization-bounds.rs15
-rw-r--r--tests/ui/nll/outlives-suggestion-more.rs26
-rw-r--r--tests/ui/nll/outlives-suggestion-more.stderr96
-rw-r--r--tests/ui/nll/outlives-suggestion-simple.polonius.stderr124
-rw-r--r--tests/ui/nll/outlives-suggestion-simple.rs75
-rw-r--r--tests/ui/nll/outlives-suggestion-simple.stderr104
-rw-r--r--tests/ui/nll/polonius/assignment-kills-loans.rs87
-rw-r--r--tests/ui/nll/polonius/assignment-to-differing-field.rs49
-rw-r--r--tests/ui/nll/polonius/assignment-to-differing-field.stderr51
-rw-r--r--tests/ui/nll/polonius/call-kills-loans.rs23
-rw-r--r--tests/ui/nll/polonius/issue-46589.rs31
-rw-r--r--tests/ui/nll/polonius/polonius-smoke-test.rs46
-rw-r--r--tests/ui/nll/polonius/polonius-smoke-test.stderr43
-rw-r--r--tests/ui/nll/polonius/storagedead-kills-loans.rs28
-rw-r--r--tests/ui/nll/polonius/subset-relations.rs29
-rw-r--r--tests/ui/nll/polonius/subset-relations.stderr14
-rw-r--r--tests/ui/nll/process_or_insert_default.rs27
-rw-r--r--tests/ui/nll/projection-return.rs17
-rw-r--r--tests/ui/nll/promotable-mutable-zst-doesnt-conflict.rs11
-rw-r--r--tests/ui/nll/promoted-bounds.rs25
-rw-r--r--tests/ui/nll/promoted-bounds.stderr15
-rw-r--r--tests/ui/nll/promoted-closure-pair.rs10
-rw-r--r--tests/ui/nll/promoted-closure-pair.stderr12
-rw-r--r--tests/ui/nll/promoted-liveness.rs8
-rw-r--r--tests/ui/nll/rc-loop.rs28
-rw-r--r--tests/ui/nll/ref-suggestion.rs17
-rw-r--r--tests/ui/nll/ref-suggestion.stderr48
-rw-r--r--tests/ui/nll/reference-carried-through-struct-field.rs10
-rw-r--r--tests/ui/nll/reference-carried-through-struct-field.stderr13
-rw-r--r--tests/ui/nll/region-ends-after-if-condition.rs32
-rw-r--r--tests/ui/nll/region-ends-after-if-condition.stderr15
-rw-r--r--tests/ui/nll/relate_tys/fn-subtype.rs8
-rw-r--r--tests/ui/nll/relate_tys/fn-subtype.stderr12
-rw-r--r--tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs24
-rw-r--r--tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr21
-rw-r--r--tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs23
-rw-r--r--tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs15
-rw-r--r--tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs34
-rw-r--r--tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr29
-rw-r--r--tests/ui/nll/relate_tys/issue-48071.rs24
-rw-r--r--tests/ui/nll/relate_tys/opaque-hrtb.rs14
-rw-r--r--tests/ui/nll/relate_tys/opaque-hrtb.stderr11
-rw-r--r--tests/ui/nll/relate_tys/trait-hrtb.rs14
-rw-r--r--tests/ui/nll/relate_tys/trait-hrtb.stderr12
-rw-r--r--tests/ui/nll/relate_tys/universe-violation.rs15
-rw-r--r--tests/ui/nll/relate_tys/universe-violation.stderr12
-rw-r--r--tests/ui/nll/relate_tys/var-appears-twice.rs25
-rw-r--r--tests/ui/nll/relate_tys/var-appears-twice.stderr14
-rw-r--r--tests/ui/nll/return-ref-mut-issue-46557.rs8
-rw-r--r--tests/ui/nll/return-ref-mut-issue-46557.stderr11
-rw-r--r--tests/ui/nll/return_from_loop.rs35
-rw-r--r--tests/ui/nll/return_from_loop.stderr15
-rw-r--r--tests/ui/nll/self-assign-ref-mut.rs20
-rw-r--r--tests/ui/nll/snocat-regression.rs16
-rw-r--r--tests/ui/nll/snocat-regression.stderr14
-rw-r--r--tests/ui/nll/trait-associated-constant.rs31
-rw-r--r--tests/ui/nll/trait-associated-constant.stderr22
-rw-r--r--tests/ui/nll/ty-outlives/impl-trait-captures.rs15
-rw-r--r--tests/ui/nll/ty-outlives/impl-trait-captures.stderr16
-rw-r--r--tests/ui/nll/ty-outlives/impl-trait-outlives.rs38
-rw-r--r--tests/ui/nll/ty-outlives/impl-trait-outlives.stderr25
-rw-r--r--tests/ui/nll/ty-outlives/issue-53789-1.rs87
-rw-r--r--tests/ui/nll/ty-outlives/issue-53789-2.rs249
-rw-r--r--tests/ui/nll/ty-outlives/issue-55756.rs37
-rw-r--r--tests/ui/nll/ty-outlives/projection-body.rs27
-rw-r--r--tests/ui/nll/ty-outlives/projection-implied-bounds.rs40
-rw-r--r--tests/ui/nll/ty-outlives/projection-implied-bounds.stderr14
-rw-r--r--tests/ui/nll/ty-outlives/projection-no-regions-closure.rs55
-rw-r--r--tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr118
-rw-r--r--tests/ui/nll/ty-outlives/projection-no-regions-fn.rs40
-rw-r--r--tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr21
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-closure.rs83
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-closure.stderr155
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs84
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr152
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs88
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr114
-rw-r--r--tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs112
-rw-r--r--tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr236
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs34
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr12
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs25
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr12
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-env.rs28
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-none.rs24
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-none.stderr14
-rw-r--r--tests/ui/nll/ty-outlives/projection-where-clause-trait.rs25
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs39
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr59
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs53
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr49
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs82
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr122
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-fn-body.rs27
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-fn-body.stderr14
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-fn.rs36
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-fn.stderr25
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-implied-bounds.rs28
-rw-r--r--tests/ui/nll/ty-outlives/wf-unreachable.rs52
-rw-r--r--tests/ui/nll/ty-outlives/wf-unreachable.stderr73
-rw-r--r--tests/ui/nll/type-alias-free-regions.rs31
-rw-r--r--tests/ui/nll/type-alias-free-regions.stderr22
-rw-r--r--tests/ui/nll/type-check-pointer-coercions.rs37
-rw-r--r--tests/ui/nll/type-check-pointer-coercions.stderr111
-rw-r--r--tests/ui/nll/type-check-pointer-comparisons.rs31
-rw-r--r--tests/ui/nll/type-check-pointer-comparisons.stderr98
-rw-r--r--tests/ui/nll/type-test-universe.rs21
-rw-r--r--tests/ui/nll/type-test-universe.stderr22
-rw-r--r--tests/ui/nll/unused-mut-issue-50343.fixed9
-rw-r--r--tests/ui/nll/unused-mut-issue-50343.rs9
-rw-r--r--tests/ui/nll/unused-mut-issue-50343.stderr16
-rw-r--r--tests/ui/nll/user-annotations/adt-brace-enums.rs50
-rw-r--r--tests/ui/nll/user-annotations/adt-brace-enums.stderr42
-rw-r--r--tests/ui/nll/user-annotations/adt-brace-structs.rs48
-rw-r--r--tests/ui/nll/user-annotations/adt-brace-structs.stderr42
-rw-r--r--tests/ui/nll/user-annotations/adt-nullary-enums.rs69
-rw-r--r--tests/ui/nll/user-annotations/adt-nullary-enums.stderr45
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-enums.rs53
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-enums.stderr42
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-struct-calls.rs71
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr56
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-struct.rs48
-rw-r--r--tests/ui/nll/user-annotations/adt-tuple-struct.stderr42
-rw-r--r--tests/ui/nll/user-annotations/ascribed-type-wf.rs17
-rw-r--r--tests/ui/nll/user-annotations/ascribed-type-wf.stderr10
-rw-r--r--tests/ui/nll/user-annotations/cast_static_lifetime.rs6
-rw-r--r--tests/ui/nll/user-annotations/cast_static_lifetime.stderr14
-rw-r--r--tests/ui/nll/user-annotations/closure-sig.rs15
-rw-r--r--tests/ui/nll/user-annotations/closure-substs.polonius.stderr61
-rw-r--r--tests/ui/nll/user-annotations/closure-substs.rs31
-rw-r--r--tests/ui/nll/user-annotations/closure-substs.stderr42
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-inherent-1.rs12
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr10
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-inherent-2.rs27
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr50
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-normalize.rs22
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-normalize.stderr10
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs14
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr10
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs14
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr10
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs14
-rw-r--r--tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr10
-rw-r--r--tests/ui/nll/user-annotations/downcast-infer.rs11
-rw-r--r--tests/ui/nll/user-annotations/dump-adt-brace-struct.rs20
-rw-r--r--tests/ui/nll/user-annotations/dump-adt-brace-struct.stderr8
-rw-r--r--tests/ui/nll/user-annotations/dump-fn-method.rs57
-rw-r--r--tests/ui/nll/user-annotations/dump-fn-method.stderr26
-rw-r--r--tests/ui/nll/user-annotations/fns.rs48
-rw-r--r--tests/ui/nll/user-annotations/fns.stderr42
-rw-r--r--tests/ui/nll/user-annotations/inherent-associated-constants.rs15
-rw-r--r--tests/ui/nll/user-annotations/inherent-associated-constants.stderr10
-rw-r--r--tests/ui/nll/user-annotations/issue-54124.rs8
-rw-r--r--tests/ui/nll/user-annotations/issue-54124.stderr20
-rw-r--r--tests/ui/nll/user-annotations/issue-54570-bootstrapping.rs30
-rw-r--r--tests/ui/nll/user-annotations/issue-55219.rs18
-rw-r--r--tests/ui/nll/user-annotations/issue-55241.rs26
-rw-r--r--tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs68
-rw-r--r--tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr29
-rw-r--r--tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs40
-rw-r--r--tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr38
-rw-r--r--tests/ui/nll/user-annotations/method-call.rs69
-rw-r--r--tests/ui/nll/user-annotations/method-call.stderr42
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-1.rs63
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-1.stderr46
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-2.rs63
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-2.stderr46
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-3.rs69
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-3.stderr42
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-1.rs18
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr18
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-2.rs19
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr33
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-3.rs18
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr18
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-4.rs20
-rw-r--r--tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr33
-rw-r--r--tests/ui/nll/user-annotations/normalization-2.rs152
-rw-r--r--tests/ui/nll/user-annotations/normalization-2.stderr296
-rw-r--r--tests/ui/nll/user-annotations/normalization-default.rs22
-rw-r--r--tests/ui/nll/user-annotations/normalization-default.stderr36
-rw-r--r--tests/ui/nll/user-annotations/normalization-infer.rs40
-rw-r--r--tests/ui/nll/user-annotations/normalization-infer.stderr101
-rw-r--r--tests/ui/nll/user-annotations/normalization-self.rs26
-rw-r--r--tests/ui/nll/user-annotations/normalization-self.stderr36
-rw-r--r--tests/ui/nll/user-annotations/normalization.rs17
-rw-r--r--tests/ui/nll/user-annotations/normalization.stderr25
-rw-r--r--tests/ui/nll/user-annotations/normalize-self-ty.rs23
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs22
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr26
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs20
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr26
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs22
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr26
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs20
-rw-r--r--tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr26
-rw-r--r--tests/ui/nll/user-annotations/patterns.rs136
-rw-r--r--tests/ui/nll/user-annotations/patterns.stderr189
-rw-r--r--tests/ui/nll/user-annotations/promoted-annotation.rs10
-rw-r--r--tests/ui/nll/user-annotations/promoted-annotation.stderr17
-rw-r--r--tests/ui/nll/user-annotations/type-annotation-with-hrtb.rs33
-rw-r--r--tests/ui/nll/user-annotations/type_ascription_static_lifetime.rs7
-rw-r--r--tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr14
-rw-r--r--tests/ui/nll/user-annotations/wf-self-type.rs13
-rw-r--r--tests/ui/nll/user-annotations/wf-self-type.stderr14
-rw-r--r--tests/ui/nll/vimwiki-core-regression.rs37
-rw-r--r--tests/ui/nll/where_clauses_in_functions.rs15
-rw-r--r--tests/ui/nll/where_clauses_in_functions.stderr14
-rw-r--r--tests/ui/nll/where_clauses_in_structs.rs15
-rw-r--r--tests/ui/nll/where_clauses_in_structs.stderr17
554 files changed, 18827 insertions, 0 deletions
diff --git a/tests/ui/nll/assign-while-to-immutable.rs b/tests/ui/nll/assign-while-to-immutable.rs
new file mode 100644
index 000000000..c803321b5
--- /dev/null
+++ b/tests/ui/nll/assign-while-to-immutable.rs
@@ -0,0 +1,11 @@
+// We used to incorrectly assign to `x` twice when generating MIR for this
+// function, preventing this from compiling.
+
+// check-pass
+
+fn main() {
+ let x = while false {
+ break;
+ };
+ let y = 'l: while break 'l {};
+}
diff --git a/tests/ui/nll/borrow-use-issue-46875.rs b/tests/ui/nll/borrow-use-issue-46875.rs
new file mode 100644
index 000000000..42e28b967
--- /dev/null
+++ b/tests/ui/nll/borrow-use-issue-46875.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+fn vec() {
+ let mut _x = vec!['c'];
+ let _y = &_x;
+ _x = Vec::new();
+}
+
+fn int() {
+ let mut _x = 5;
+ let _y = &_x;
+ _x = 7;
+}
+
+fn main() {
+ vec();
+ int();
+}
diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
new file mode 100644
index 000000000..7d3b00dfc
--- /dev/null
+++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
@@ -0,0 +1,25 @@
+//
+// run-pass
+//
+// FIXME(#54366) - We probably shouldn't allow #[thread_local] static mut to get a 'static lifetime.
+
+#![feature(thread_local)]
+
+#[thread_local]
+static mut X1: u64 = 0;
+
+struct S1 {
+ a: &'static mut u64,
+}
+
+impl S1 {
+ fn new(_x: u64) -> S1 {
+ S1 {
+ a: unsafe { &mut X1 },
+ }
+ }
+}
+
+fn main() {
+ S1::new(0).a;
+}
diff --git a/tests/ui/nll/borrowed-local-error.rs b/tests/ui/nll/borrowed-local-error.rs
new file mode 100644
index 000000000..d333356d9
--- /dev/null
+++ b/tests/ui/nll/borrowed-local-error.rs
@@ -0,0 +1,12 @@
+fn gimme(x: &(u32,)) -> &u32 {
+ &x.0
+}
+
+fn main() {
+ let x = gimme({
+ let v = (22,);
+ &v
+ //~^ ERROR `v` does not live long enough [E0597]
+ });
+ println!("{:?}", x);
+}
diff --git a/tests/ui/nll/borrowed-local-error.stderr b/tests/ui/nll/borrowed-local-error.stderr
new file mode 100644
index 000000000..d629caa43
--- /dev/null
+++ b/tests/ui/nll/borrowed-local-error.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `v` does not live long enough
+ --> $DIR/borrowed-local-error.rs:8:9
+ |
+LL | let x = gimme({
+ | ----- borrow later used by call
+LL | let v = (22,);
+LL | &v
+ | ^^ borrowed value does not live long enough
+LL |
+LL | });
+ | - `v` 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/nll/borrowed-match-issue-45045.rs b/tests/ui/nll/borrowed-match-issue-45045.rs
new file mode 100644
index 000000000..978eeb868
--- /dev/null
+++ b/tests/ui/nll/borrowed-match-issue-45045.rs
@@ -0,0 +1,18 @@
+// Regression test for issue #45045
+
+enum Xyz {
+ A,
+ B,
+}
+
+fn main() {
+ let mut e = Xyz::A;
+ let f = &mut e;
+ let g = f;
+ match e {
+ //~^ cannot use `e` because it was mutably borrowed [E0503]
+ Xyz::A => println!("a"),
+ Xyz::B => println!("b"),
+ };
+ *g = Xyz::B;
+}
diff --git a/tests/ui/nll/borrowed-match-issue-45045.stderr b/tests/ui/nll/borrowed-match-issue-45045.stderr
new file mode 100644
index 000000000..9d4682667
--- /dev/null
+++ b/tests/ui/nll/borrowed-match-issue-45045.stderr
@@ -0,0 +1,15 @@
+error[E0503]: cannot use `e` because it was mutably borrowed
+ --> $DIR/borrowed-match-issue-45045.rs:12:11
+ |
+LL | let f = &mut e;
+ | ------ borrow of `e` occurs here
+LL | let g = f;
+LL | match e {
+ | ^ use of borrowed `e`
+...
+LL | *g = Xyz::B;
+ | ----------- 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/nll/borrowed-referent-issue-38899.rs b/tests/ui/nll/borrowed-referent-issue-38899.rs
new file mode 100644
index 000000000..1fe133283
--- /dev/null
+++ b/tests/ui/nll/borrowed-referent-issue-38899.rs
@@ -0,0 +1,17 @@
+// Regression test for issue #38899
+
+pub struct Block<'a> {
+ current: &'a u8,
+ unrelated: &'a u8,
+}
+
+fn bump<'a>(mut block: &mut Block<'a>) {
+ let x = &mut block;
+ println!("{}", x.current);
+ let p: &'a u8 = &*block.current;
+ //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+ drop(x);
+ drop(p);
+}
+
+fn main() {}
diff --git a/tests/ui/nll/borrowed-referent-issue-38899.stderr b/tests/ui/nll/borrowed-referent-issue-38899.stderr
new file mode 100644
index 000000000..16588cbcf
--- /dev/null
+++ b/tests/ui/nll/borrowed-referent-issue-38899.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+ --> $DIR/borrowed-referent-issue-38899.rs:11:21
+ |
+LL | let x = &mut block;
+ | ---------- mutable borrow occurs here
+LL | println!("{}", x.current);
+LL | let p: &'a u8 = &*block.current;
+ | ^^^^^^^^^^^^^^^ immutable borrow occurs here
+LL |
+LL | drop(x);
+ | - mutable 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/nll/borrowed-temporary-error.rs b/tests/ui/nll/borrowed-temporary-error.rs
new file mode 100644
index 000000000..37d0e670d
--- /dev/null
+++ b/tests/ui/nll/borrowed-temporary-error.rs
@@ -0,0 +1,12 @@
+fn gimme(x: &(u32,)) -> &u32 {
+ &x.0
+}
+
+fn main() {
+ let x = gimme({
+ let v = 22;
+ &(v,)
+ //~^ ERROR temporary value dropped while borrowed [E0716]
+ });
+ println!("{:?}", x);
+}
diff --git a/tests/ui/nll/borrowed-temporary-error.stderr b/tests/ui/nll/borrowed-temporary-error.stderr
new file mode 100644
index 000000000..89781d96f
--- /dev/null
+++ b/tests/ui/nll/borrowed-temporary-error.stderr
@@ -0,0 +1,16 @@
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/borrowed-temporary-error.rs:8:10
+ |
+LL | &(v,)
+ | ^^^^ creates a temporary value which is freed while still in use
+LL |
+LL | });
+ | - temporary value is freed at the end of this statement
+LL | println!("{:?}", x);
+ | - borrow later used here
+ |
+ = note: consider using a `let` binding to create a longer lived value
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/nll/borrowed-universal-error-2.rs b/tests/ui/nll/borrowed-universal-error-2.rs
new file mode 100644
index 000000000..3f9b2f292
--- /dev/null
+++ b/tests/ui/nll/borrowed-universal-error-2.rs
@@ -0,0 +1,7 @@
+fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
+ let v = 22;
+ &v
+ //~^ ERROR cannot return reference to local variable `v` [E0515]
+}
+
+fn main() {}
diff --git a/tests/ui/nll/borrowed-universal-error-2.stderr b/tests/ui/nll/borrowed-universal-error-2.stderr
new file mode 100644
index 000000000..7213ed3ba
--- /dev/null
+++ b/tests/ui/nll/borrowed-universal-error-2.stderr
@@ -0,0 +1,9 @@
+error[E0515]: cannot return reference to local variable `v`
+ --> $DIR/borrowed-universal-error-2.rs:3:5
+ |
+LL | &v
+ | ^^ 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/nll/borrowed-universal-error.rs b/tests/ui/nll/borrowed-universal-error.rs
new file mode 100644
index 000000000..fc9ffd470
--- /dev/null
+++ b/tests/ui/nll/borrowed-universal-error.rs
@@ -0,0 +1,11 @@
+fn gimme(x: &(u32,)) -> &u32 {
+ &x.0
+}
+
+fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
+ let v = 22;
+ gimme(&(v,))
+ //~^ ERROR cannot return value referencing temporary value [E0515]
+}
+
+fn main() {}
diff --git a/tests/ui/nll/borrowed-universal-error.stderr b/tests/ui/nll/borrowed-universal-error.stderr
new file mode 100644
index 000000000..88a2d8fcf
--- /dev/null
+++ b/tests/ui/nll/borrowed-universal-error.stderr
@@ -0,0 +1,12 @@
+error[E0515]: cannot return value referencing temporary value
+ --> $DIR/borrowed-universal-error.rs:7:5
+ |
+LL | gimme(&(v,))
+ | ^^^^^^^----^
+ | | |
+ | | temporary value created here
+ | 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/nll/cannot-move-block-spans.rs b/tests/ui/nll/cannot-move-block-spans.rs
new file mode 100644
index 000000000..e994fd3d5
--- /dev/null
+++ b/tests/ui/nll/cannot-move-block-spans.rs
@@ -0,0 +1,22 @@
+// Test that the we point to the inner expression when moving out to initialize
+// a variable, and that we don't give a useless suggestion such as &{ *r }.
+
+pub fn deref(r: &String) {
+ let x = { *r }; //~ ERROR
+ let y = unsafe { *r }; //~ ERROR
+ let z = loop { break *r; }; //~ ERROR
+}
+
+pub fn index(arr: [String; 2]) {
+ let x = { arr[0] }; //~ ERROR
+ let y = unsafe { arr[0] }; //~ ERROR
+ let z = loop { break arr[0]; }; //~ ERROR
+}
+
+pub fn additional_statement_cases(r: &String) {
+ let x = { let mut u = 0; u += 1; *r }; //~ ERROR
+ let y = unsafe { let mut u = 0; u += 1; *r }; //~ ERROR
+ let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; //~ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/cannot-move-block-spans.stderr b/tests/ui/nll/cannot-move-block-spans.stderr
new file mode 100644
index 000000000..0dc5c08ea
--- /dev/null
+++ b/tests/ui/nll/cannot-move-block-spans.stderr
@@ -0,0 +1,118 @@
+error[E0507]: cannot move out of `*r` which is behind a shared reference
+ --> $DIR/cannot-move-block-spans.rs:5:15
+ |
+LL | let x = { *r };
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = { *r };
+LL + let x = { r };
+ |
+
+error[E0507]: cannot move out of `*r` which is behind a shared reference
+ --> $DIR/cannot-move-block-spans.rs:6:22
+ |
+LL | let y = unsafe { *r };
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let y = unsafe { *r };
+LL + let y = unsafe { r };
+ |
+
+error[E0507]: cannot move out of `*r` which is behind a shared reference
+ --> $DIR/cannot-move-block-spans.rs:7:26
+ |
+LL | let z = loop { break *r; };
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let z = loop { break *r; };
+LL + let z = loop { break r; };
+ |
+
+error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
+ --> $DIR/cannot-move-block-spans.rs:11:15
+ |
+LL | let x = { arr[0] };
+ | ^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let x = { &arr[0] };
+ | +
+
+error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
+ --> $DIR/cannot-move-block-spans.rs:12:22
+ |
+LL | let y = unsafe { arr[0] };
+ | ^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let y = unsafe { &arr[0] };
+ | +
+
+error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
+ --> $DIR/cannot-move-block-spans.rs:13:26
+ |
+LL | let z = loop { break arr[0]; };
+ | ^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let z = loop { break &arr[0]; };
+ | +
+
+error[E0507]: cannot move out of `*r` which is behind a shared reference
+ --> $DIR/cannot-move-block-spans.rs:17:38
+ |
+LL | let x = { let mut u = 0; u += 1; *r };
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = { let mut u = 0; u += 1; *r };
+LL + let x = { let mut u = 0; u += 1; r };
+ |
+
+error[E0507]: cannot move out of `*r` which is behind a shared reference
+ --> $DIR/cannot-move-block-spans.rs:18:45
+ |
+LL | let y = unsafe { let mut u = 0; u += 1; *r };
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let y = unsafe { let mut u = 0; u += 1; *r };
+LL + let y = unsafe { let mut u = 0; u += 1; r };
+ |
+
+error[E0507]: cannot move out of `*r` which is behind a shared reference
+ --> $DIR/cannot-move-block-spans.rs:19:49
+ |
+LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
+LL + let z = loop { let mut u = 0; u += 1; break r; u += 2; };
+ |
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0507, E0508.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/nll/capture-mut-ref.fixed b/tests/ui/nll/capture-mut-ref.fixed
new file mode 100644
index 000000000..2dacb26b6
--- /dev/null
+++ b/tests/ui/nll/capture-mut-ref.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+
+// Check that capturing a mutable reference by move and assigning to its
+// referent doesn't make the unused mut lint think that it is mutable.
+
+#![deny(unused_mut)]
+
+pub fn mutable_upvar() {
+ let x = &mut 0;
+ //~^ ERROR
+ let _ = move || {
+ *x = 1;
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/capture-mut-ref.rs b/tests/ui/nll/capture-mut-ref.rs
new file mode 100644
index 000000000..56e01f7b7
--- /dev/null
+++ b/tests/ui/nll/capture-mut-ref.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+
+// Check that capturing a mutable reference by move and assigning to its
+// referent doesn't make the unused mut lint think that it is mutable.
+
+#![deny(unused_mut)]
+
+pub fn mutable_upvar() {
+ let mut x = &mut 0;
+ //~^ ERROR
+ let _ = move || {
+ *x = 1;
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/capture-mut-ref.stderr b/tests/ui/nll/capture-mut-ref.stderr
new file mode 100644
index 000000000..4898d5692
--- /dev/null
+++ b/tests/ui/nll/capture-mut-ref.stderr
@@ -0,0 +1,16 @@
+error: variable does not need to be mutable
+ --> $DIR/capture-mut-ref.rs:9:9
+ |
+LL | let mut x = &mut 0;
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+note: the lint level is defined here
+ --> $DIR/capture-mut-ref.rs:6:9
+ |
+LL | #![deny(unused_mut)]
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/capture-ref-in-struct.rs b/tests/ui/nll/capture-ref-in-struct.rs
new file mode 100644
index 000000000..db6ac7d66
--- /dev/null
+++ b/tests/ui/nll/capture-ref-in-struct.rs
@@ -0,0 +1,36 @@
+// Test that a structure which tries to store a pointer to `y` into
+// `p` (indirectly) fails to compile.
+
+struct SomeStruct<'a, 'b: 'a> {
+ p: &'a mut &'b i32,
+ y: &'b i32,
+}
+
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+
+ let closure = SomeStruct {
+ p: &mut p,
+ y: &y,
+ //~^ ERROR `y` does not live long enough [E0597]
+ };
+
+ closure.invoke();
+ }
+
+ deref(p);
+}
+
+impl<'a, 'b> SomeStruct<'a, 'b> {
+ fn invoke(self) {
+ *self.p = self.y;
+ }
+}
+
+fn deref(_: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/capture-ref-in-struct.stderr b/tests/ui/nll/capture-ref-in-struct.stderr
new file mode 100644
index 000000000..cdfe7f6db
--- /dev/null
+++ b/tests/ui/nll/capture-ref-in-struct.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `y` does not live long enough
+ --> $DIR/capture-ref-in-struct.rs:18:16
+ |
+LL | y: &y,
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+LL |
+LL | deref(p);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-access-spans.rs b/tests/ui/nll/closure-access-spans.rs
new file mode 100644
index 000000000..2a59e80b2
--- /dev/null
+++ b/tests/ui/nll/closure-access-spans.rs
@@ -0,0 +1,56 @@
+// check that accesses due to a closure capture give a special note
+
+fn closure_imm_capture_conflict(mut x: i32) {
+ let r = &mut x;
+ || x; //~ ERROR
+ r.use_mut();
+}
+
+fn closure_mut_capture_conflict(mut x: i32) {
+ let r = &mut x;
+ || x = 2; //~ ERROR
+ r.use_mut();
+}
+
+fn closure_unique_capture_conflict(mut x: &mut i32) {
+ let r = &mut x;
+ || *x = 2; //~ ERROR
+ r.use_mut();
+}
+
+fn closure_copy_capture_conflict(mut x: i32) {
+ let r = &mut x;
+ move || x; //~ ERROR
+ r.use_ref();
+}
+
+fn closure_move_capture_conflict(mut x: String) {
+ let r = &x;
+ || x; //~ ERROR
+ r.use_ref();
+}
+
+fn closure_imm_capture_moved(mut x: String) {
+ let r = x;
+ || x.len(); //~ ERROR
+}
+
+fn closure_mut_capture_moved(mut x: String) {
+ let r = x;
+ || x = String::new(); //~ ERROR
+}
+
+fn closure_unique_capture_moved(x: &mut String) {
+ let r = x;
+ || *x = String::new(); //~ ERROR
+}
+
+fn closure_move_capture_moved(x: &mut String) {
+ let r = x;
+ || x; //~ ERROR
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } }
+impl<T> Fake for T { }
diff --git a/tests/ui/nll/closure-access-spans.stderr b/tests/ui/nll/closure-access-spans.stderr
new file mode 100644
index 000000000..0a09353b8
--- /dev/null
+++ b/tests/ui/nll/closure-access-spans.stderr
@@ -0,0 +1,120 @@
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+ --> $DIR/closure-access-spans.rs:5:5
+ |
+LL | let r = &mut x;
+ | ------ mutable borrow occurs here
+LL | || x;
+ | ^^ - second borrow occurs due to use of `x` in closure
+ | |
+ | immutable borrow occurs here
+LL | r.use_mut();
+ | ----------- mutable borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+ --> $DIR/closure-access-spans.rs:11:5
+ |
+LL | let r = &mut x;
+ | ------ first mutable borrow occurs here
+LL | || x = 2;
+ | ^^ - second borrow occurs due to use of `x` in closure
+ | |
+ | second mutable borrow occurs here
+LL | r.use_mut();
+ | ----------- first borrow later used here
+
+error[E0500]: closure requires unique access to `x` but it is already borrowed
+ --> $DIR/closure-access-spans.rs:17:5
+ |
+LL | let r = &mut x;
+ | ------ borrow occurs here
+LL | || *x = 2;
+ | ^^ -- second borrow occurs due to use of `x` in closure
+ | |
+ | closure construction occurs here
+LL | r.use_mut();
+ | ----------- first borrow later used here
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+ --> $DIR/closure-access-spans.rs:23:13
+ |
+LL | let r = &mut x;
+ | ------ borrow of `x` occurs here
+LL | move || x;
+ | ^ use of borrowed `x`
+LL | r.use_ref();
+ | ----------- borrow later used here
+
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/closure-access-spans.rs:29:5
+ |
+LL | let r = &x;
+ | -- borrow of `x` occurs here
+LL | || x;
+ | ^^ - move occurs due to use in closure
+ | |
+ | move out of `x` occurs here
+LL | r.use_ref();
+ | ----------- borrow later used here
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-access-spans.rs:35:5
+ |
+LL | fn closure_imm_capture_moved(mut x: String) {
+ | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | let r = x;
+ | - value moved here
+LL | || x.len();
+ | ^^ - borrow occurs due to use in closure
+ | |
+ | value borrowed here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | let r = x.clone();
+ | ++++++++
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-access-spans.rs:40:5
+ |
+LL | fn closure_mut_capture_moved(mut x: String) {
+ | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | let r = x;
+ | - value moved here
+LL | || x = String::new();
+ | ^^ - borrow occurs due to use in closure
+ | |
+ | value borrowed here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | let r = x.clone();
+ | ++++++++
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-access-spans.rs:45:5
+ |
+LL | fn closure_unique_capture_moved(x: &mut String) {
+ | - move occurs because `x` has type `&mut String`, which does not implement the `Copy` trait
+LL | let r = x;
+ | - value moved here
+LL | || *x = String::new();
+ | ^^ -- borrow occurs due to use in closure
+ | |
+ | value borrowed here after move
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/closure-access-spans.rs:50:5
+ |
+LL | fn closure_move_capture_moved(x: &mut String) {
+ | - move occurs because `x` has type `&mut String`, which does not implement the `Copy` trait
+LL | let r = x;
+ | - value moved here
+LL | || x;
+ | ^^ - use occurs due to use in closure
+ | |
+ | value used here after move
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0382, E0499, E0500, E0502, E0503, E0505.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/nll/closure-borrow-spans.rs b/tests/ui/nll/closure-borrow-spans.rs
new file mode 100644
index 000000000..b38f7900e
--- /dev/null
+++ b/tests/ui/nll/closure-borrow-spans.rs
@@ -0,0 +1,100 @@
+// check that existing borrows due to a closure capture give a special note
+
+fn move_while_borrowed(x: String) {
+ let f = || x.len();
+ let y = x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_mut_while_borrowed(mut x: i32) {
+ let f = || x;
+ let y = &mut x; //~ ERROR
+ f.use_ref();
+}
+
+fn drop_while_borrowed() {
+ let f;
+ {
+ let x = 1;
+ f = || x; //~ ERROR
+ }
+ f.use_ref();
+}
+
+fn assign_while_borrowed(mut x: i32) {
+ let f = || x;
+ x = 1; //~ ERROR
+ f.use_ref();
+}
+
+fn copy_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ let y = x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ let y = &x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_mut_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ let y = &mut x; //~ ERROR
+ f.use_ref();
+}
+
+fn drop_while_borrowed_mut() {
+ let f;
+ {
+ let mut x = 1;
+ f = || x = 0; //~ ERROR
+ }
+ f.use_ref();
+}
+
+fn assign_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ x = 1; //~ ERROR
+ f.use_ref();
+}
+
+fn copy_while_borrowed_unique(x: &mut i32) {
+ let f = || *x = 0;
+ let y = x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_while_borrowed_unique(x: &mut i32) {
+ let f = || *x = 0;
+ let y = &x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_mut_while_borrowed_unique(mut x: &mut i32) {
+ let f = || *x = 0;
+ let y = &mut x; //~ ERROR
+ f.use_ref();
+}
+
+fn drop_while_borrowed_unique() {
+ let mut z = 1;
+ let f;
+ {
+ let x = &mut z;
+ f = || *x = 0; //~ ERROR
+ }
+ f.use_ref();
+}
+
+fn assign_while_borrowed_unique(x: &mut i32) {
+ let f = || *x = 0;
+ *x = 1; //~ ERROR
+ f.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/nll/closure-borrow-spans.stderr b/tests/ui/nll/closure-borrow-spans.stderr
new file mode 100644
index 000000000..bada4e1b8
--- /dev/null
+++ b/tests/ui/nll/closure-borrow-spans.stderr
@@ -0,0 +1,172 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:5:13
+ |
+LL | let f = || x.len();
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | let y = x;
+ | ^ move out of `x` occurs here
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+ --> $DIR/closure-borrow-spans.rs:11:13
+ |
+LL | let f = || x;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | immutable borrow occurs here
+LL | let y = &mut x;
+ | ^^^^^^ mutable borrow occurs here
+LL | f.use_ref();
+ | ----------- immutable borrow later used here
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/closure-borrow-spans.rs:19:16
+ |
+LL | f = || x;
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
+LL | }
+ | - `x` dropped here while still borrowed
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:26:5
+ |
+LL | let f = || x;
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | x = 1;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+ --> $DIR/closure-borrow-spans.rs:32:13
+ |
+LL | let f = || x = 0;
+ | -- - borrow occurs due to use of `x` in closure
+ | |
+ | borrow of `x` occurs here
+LL | let y = x;
+ | ^ use of borrowed `x`
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+ --> $DIR/closure-borrow-spans.rs:38:13
+ |
+LL | let f = || x = 0;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | mutable borrow occurs here
+LL | let y = &x;
+ | ^^ immutable borrow occurs here
+LL | f.use_ref();
+ | ----------- mutable borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+ --> $DIR/closure-borrow-spans.rs:44:13
+ |
+LL | let f = || x = 0;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | first mutable borrow occurs here
+LL | let y = &mut x;
+ | ^^^^^^ second mutable borrow occurs here
+LL | f.use_ref();
+ | ----------- first borrow later used here
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/closure-borrow-spans.rs:52:16
+ |
+LL | f = || x = 0;
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
+LL | }
+ | - `x` dropped here while still borrowed
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:59:5
+ |
+LL | let f = || x = 0;
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | x = 1;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:65:13
+ |
+LL | let f = || *x = 0;
+ | -- -- borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | let y = x;
+ | ^ move out of `x` occurs here
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
+ --> $DIR/closure-borrow-spans.rs:71:13
+ |
+LL | let f = || *x = 0;
+ | -- -- first borrow occurs due to use of `x` in closure
+ | |
+ | closure construction occurs here
+LL | let y = &x;
+ | ^^ second borrow occurs here
+LL | f.use_ref();
+ | ----------- first borrow later used here
+
+error[E0501]: cannot borrow `x` as mutable because previous closure requires unique access
+ --> $DIR/closure-borrow-spans.rs:77:13
+ |
+LL | let f = || *x = 0;
+ | -- -- first borrow occurs due to use of `x` in closure
+ | |
+ | closure construction occurs here
+LL | let y = &mut x;
+ | ^^^^^^ second borrow occurs here
+LL | f.use_ref();
+ | ----------- first borrow later used here
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/closure-borrow-spans.rs:86:16
+ |
+LL | f = || *x = 0;
+ | -- ^^ borrowed value does not live long enough
+ | |
+ | value captured here
+LL | }
+ | - `x` dropped here while still borrowed
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error[E0506]: cannot assign to `*x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:93:5
+ |
+LL | let f = || *x = 0;
+ | -- -- borrow occurs due to use in closure
+ | |
+ | borrow of `*x` occurs here
+LL | *x = 1;
+ | ^^^^^^ assignment to borrowed `*x` occurs here
+LL | f.use_ref();
+ | ----------- borrow later used here
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0499, E0501, E0502, E0503, E0505, E0506, E0597.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/nll/closure-captures.rs b/tests/ui/nll/closure-captures.rs
new file mode 100644
index 000000000..16d90b971
--- /dev/null
+++ b/tests/ui/nll/closure-captures.rs
@@ -0,0 +1,55 @@
+// Some cases with closures that might be problems
+
+// Should have one error per assignment
+
+fn one_closure(x: i32) {
+ ||
+ x = 1; //~ ERROR
+ move ||
+ x = 1; //~ ERROR
+}
+
+fn two_closures(x: i32) {
+ || {
+ ||
+ x = 1; //~ ERROR
+ };
+ move || {
+ ||
+ x = 1; //~ ERROR
+ };
+}
+
+fn fn_ref<F: Fn()>(f: F) -> F { f }
+
+fn two_closures_ref_mut(mut x: i32) {
+ fn_ref(|| {
+ || //~ ERROR
+ x = 1;}
+ );
+ fn_ref(move || {
+ || //~ ERROR
+ x = 1;});
+}
+
+// This still gives two messages, but it requires two things to be fixed.
+fn two_closures_ref(x: i32) {
+ fn_ref(|| {
+ || //~ ERROR
+ x = 1;} //~ ERROR
+ );
+ fn_ref(move || {
+ || //~ ERROR
+ x = 1;}); //~ ERROR
+}
+
+fn two_closures_two_refs(x: &mut i32) {
+ fn_ref(|| {
+ || //~ ERROR
+ *x = 1;});
+ fn_ref(move || {
+ || //~ ERROR
+ *x = 1;});
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-captures.stderr b/tests/ui/nll/closure-captures.stderr
new file mode 100644
index 000000000..5233f0b24
--- /dev/null
+++ b/tests/ui/nll/closure-captures.stderr
@@ -0,0 +1,148 @@
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/closure-captures.rs:7:5
+ |
+LL | fn one_closure(x: i32) {
+ | - help: consider changing this to be mutable: `mut x`
+LL | ||
+LL | x = 1;
+ | ^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/closure-captures.rs:9:5
+ |
+LL | fn one_closure(x: i32) {
+ | - help: consider changing this to be mutable: `mut x`
+...
+LL | x = 1;
+ | ^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/closure-captures.rs:15:9
+ |
+LL | fn two_closures(x: i32) {
+ | - help: consider changing this to be mutable: `mut x`
+...
+LL | x = 1;
+ | ^^^^^ cannot assign
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/closure-captures.rs:19:9
+ |
+LL | fn two_closures(x: i32) {
+ | - help: consider changing this to be mutable: `mut x`
+...
+LL | x = 1;
+ | ^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+ --> $DIR/closure-captures.rs:27: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 | ||
+ | ^^ cannot borrow as mutable
+LL | x = 1;}
+ | - mutable borrow occurs due to use of `x` in closure
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+ --> $DIR/closure-captures.rs:31: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 | ||
+ | ^^ cannot borrow as mutable
+LL | x = 1;});
+ | - mutable borrow occurs due to use of `x` in closure
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/closure-captures.rs:39:10
+ |
+LL | fn two_closures_ref(x: i32) {
+ | - help: consider changing this to be mutable: `mut x`
+...
+LL | x = 1;}
+ | ^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+ --> $DIR/closure-captures.rs:38: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 | ||
+ | ^^ cannot borrow as mutable
+LL | x = 1;}
+ | - mutable borrow occurs due to use of `x` in closure
+
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/closure-captures.rs:43:5
+ |
+LL | fn two_closures_ref(x: i32) {
+ | - help: consider changing this to be mutable: `mut x`
+...
+LL | x = 1;});
+ | ^^^^^ cannot assign
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+ --> $DIR/closure-captures.rs:42: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 | ||
+ | ^^ cannot borrow as mutable
+LL | x = 1;});
+ | - mutable borrow occurs due to use of `x` in closure
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+ --> $DIR/closure-captures.rs:48: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 | ||
+ | ^^ cannot borrow as mutable
+LL | *x = 1;});
+ | -- mutable borrow occurs due to use of `x` in closure
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+ --> $DIR/closure-captures.rs:51: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 | ||
+ | ^^ cannot borrow as mutable
+LL | *x = 1;});
+ | -- mutable borrow occurs due to use of `x` in closure
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/tests/ui/nll/closure-malformed-projection-input-issue-102800.rs b/tests/ui/nll/closure-malformed-projection-input-issue-102800.rs
new file mode 100644
index 000000000..260c16c17
--- /dev/null
+++ b/tests/ui/nll/closure-malformed-projection-input-issue-102800.rs
@@ -0,0 +1,21 @@
+// Regression test for #102800
+//
+// Here we are generating higher-ranked region constraints when normalizing and relating closure
+// input types. Previously this was an ICE in the error path because we didn't register enough
+// diagnostic information to render the higher-ranked subtyping error.
+
+// check-fail
+
+trait Trait {
+ type Ty;
+}
+
+impl Trait for &'static () {
+ type Ty = ();
+}
+
+fn main() {
+ let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+ //~^ ERROR implementation of `Trait` is not general enough
+ //~| ERROR implementation of `Trait` is not general enough
+}
diff --git a/tests/ui/nll/closure-malformed-projection-input-issue-102800.stderr b/tests/ui/nll/closure-malformed-projection-input-issue-102800.stderr
new file mode 100644
index 000000000..46dba0064
--- /dev/null
+++ b/tests/ui/nll/closure-malformed-projection-input-issue-102800.stderr
@@ -0,0 +1,20 @@
+error: implementation of `Trait` is not general enough
+ --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
+ |
+LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+ |
+ = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+ = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+ --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
+ |
+LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+ |
+ = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+ = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/closure-move-spans.rs b/tests/ui/nll/closure-move-spans.rs
new file mode 100644
index 000000000..bf2431870
--- /dev/null
+++ b/tests/ui/nll/closure-move-spans.rs
@@ -0,0 +1,21 @@
+// check that moves due to a closure capture give a special note
+
+fn move_after_move(x: String) {
+ || x;
+ let y = x; //~ ERROR
+}
+
+fn borrow_after_move(x: String) {
+ || x;
+ let y = &x; //~ ERROR
+}
+
+fn borrow_mut_after_move(mut x: String) {
+ || x;
+ let y = &mut x; //~ ERROR
+}
+
+fn fn_ref<F: Fn()>(f: F) -> F { f }
+fn fn_mut<F: FnMut()>(f: F) -> F { f }
+
+fn main() {}
diff --git a/tests/ui/nll/closure-move-spans.stderr b/tests/ui/nll/closure-move-spans.stderr
new file mode 100644
index 000000000..0446ef7b0
--- /dev/null
+++ b/tests/ui/nll/closure-move-spans.stderr
@@ -0,0 +1,39 @@
+error[E0382]: use of moved value: `x`
+ --> $DIR/closure-move-spans.rs:5:13
+ |
+LL | fn move_after_move(x: String) {
+ | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | || x;
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+LL | let y = x;
+ | ^ value used here after move
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-move-spans.rs:10:13
+ |
+LL | fn borrow_after_move(x: String) {
+ | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | || x;
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+LL | let y = &x;
+ | ^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-move-spans.rs:15:13
+ |
+LL | fn borrow_mut_after_move(mut x: String) {
+ | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | || x;
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+LL | let y = &mut x;
+ | ^^^^^^ value borrowed 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/nll/closure-requirements/escape-argument-callee.rs b/tests/ui/nll/closure-requirements/escape-argument-callee.rs
new file mode 100644
index 000000000..3aea511b0
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.rs
@@ -0,0 +1,42 @@
+// Test closure that:
+//
+// - takes an argument `y` with lifetime `'a` (in the code, it's anonymous)
+// - stores `y` into another, longer-lived spot with lifetime `'b`
+//
+// Because `'a` and `'b` are two different, unrelated higher-ranked
+// regions with no relationship to one another, this is an error. This
+// error is reported by the closure itself and is not propagated to
+// its creator: this is because `'a` and `'b` are higher-ranked
+// (late-bound) regions and the closure is not allowed to propagate
+// additional where clauses between higher-ranked regions, only those
+// that appear free in its type (hence, we see it before the closure's
+// "external requirements" report).
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+ let mut closure = expect_sig(|p, y| *p = y);
+ //~^ ERROR
+ closure(&mut p, &y);
+ }
+
+ deref(p);
+}
+
+fn expect_sig<F>(f: F) -> F
+ where F: FnMut(&mut &i32, &i32)
+{
+ f
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
new file mode 100644
index 000000000..363ddfaff
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -0,0 +1,31 @@
+note: no external requirements
+ --> $DIR/escape-argument-callee.rs:26:38
+ |
+LL | let mut closure = expect_sig(|p, y| *p = y);
+ | ^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) i32)),
+ (),
+ ]
+
+error: lifetime may not live long enough
+ --> $DIR/escape-argument-callee.rs:26:45
+ |
+LL | let mut closure = expect_sig(|p, y| *p = y);
+ | - - ^^^^^^ assignment requires that `'1` must outlive `'2`
+ | | |
+ | | has type `&'1 i32`
+ | has type `&'_#2r mut &'2 i32`
+
+note: no external requirements
+ --> $DIR/escape-argument-callee.rs:20:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/escape-argument.rs b/tests/ui/nll/closure-requirements/escape-argument.rs
new file mode 100644
index 000000000..066cd4360
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument.rs
@@ -0,0 +1,42 @@
+// Test closure that:
+//
+// - takes an argument `y`
+// - stores `y` into another, longer-lived spot
+//
+// but is invoked with a spot that doesn't live long
+// enough to store `y`.
+//
+// The error is reported in the caller: invoking the closure links the
+// lifetime of the variable that is given as `y` (via subtyping) and
+// thus forces the corresponding borrow to live too long. This is
+// basically checking that the MIR type checker correctly enforces the
+// closure signature.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+ let mut closure = expect_sig(|p, y| *p = y);
+ closure(&mut p, &y);
+ //~^ ERROR `y` does not live long enough [E0597]
+ }
+
+ deref(p);
+}
+
+fn expect_sig<F>(f: F) -> F
+ where F: for<'a, 'b> FnMut(&'a mut &'b i32, &'b i32)
+{
+ f
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-argument.stderr b/tests/ui/nll/closure-requirements/escape-argument.stderr
new file mode 100644
index 000000000..f67c312b9
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument.stderr
@@ -0,0 +1,35 @@
+note: no external requirements
+ --> $DIR/escape-argument.rs:26:38
+ |
+LL | let mut closure = expect_sig(|p, y| *p = y);
+ | ^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/escape-argument.rs:20:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/escape-argument.rs:27:25
+ |
+LL | closure(&mut p, &y);
+ | ^^ borrowed value does not live long enough
+LL |
+LL | }
+ | - `y` dropped here while still borrowed
+LL |
+LL | deref(p);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.rs b/tests/ui/nll/closure-requirements/escape-upvar-nested.rs
new file mode 100644
index 000000000..765a3cf96
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.rs
@@ -0,0 +1,33 @@
+// As in `escape-upvar-ref.rs`, test closure that:
+//
+// - captures a variable `y`
+// - stores reference to `y` into another, longer-lived spot
+//
+// except that the closure does so via a second closure.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+
+ let mut closure = || {
+ let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597]
+ closure1();
+ };
+
+ closure();
+ }
+
+ deref(p);
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
new file mode 100644
index 000000000..4fbd5eb19
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -0,0 +1,53 @@
+note: external requirements
+ --> $DIR/escape-upvar-nested.rs:21:32
+ |
+LL | let mut closure1 = || p = &y;
+ | ^^
+ |
+ = note: defining type: test::{closure#0}::{closure#0} with closure substs [
+ i16,
+ extern "rust-call" fn(()),
+ (&'_#1r mut &'_#2r i32, &'_#3r i32),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#3r: '_#2r
+
+note: external requirements
+ --> $DIR/escape-upvar-nested.rs:20:27
+ |
+LL | let mut closure = || {
+ | ^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ extern "rust-call" fn(()),
+ (&'_#1r mut &'_#2r i32, &'_#3r i32),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#3r: '_#2r
+
+note: no external requirements
+ --> $DIR/escape-upvar-nested.rs:13:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/escape-upvar-nested.rs:21:40
+ |
+LL | let mut closure = || {
+ | -- value captured here
+LL | let mut closure1 = || p = &y;
+ | ^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+LL |
+LL | deref(p);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.rs b/tests/ui/nll/closure-requirements/escape-upvar-ref.rs
new file mode 100644
index 000000000..0a562a0a1
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.rs
@@ -0,0 +1,33 @@
+// Test closure that:
+//
+// - captures a variable `y` by reference
+// - stores that reference to `y` into another, longer-lived place (`p`)
+//
+// Both of these are upvars of reference type (the capture of `y` is
+// of type `&'a i32`, the capture of `p` is of type `&mut &'b
+// i32`). The closure thus computes a relationship between `'a` and
+// `'b`. This relationship is propagated to the closure creator,
+// which reports an error.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+ let mut closure = || p = &y;
+ //~^ ERROR `y` does not live long enough [E0597]
+ closure();
+ }
+
+ deref(p);
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
new file mode 100644
index 000000000..bc1ceac5b
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -0,0 +1,39 @@
+note: external requirements
+ --> $DIR/escape-upvar-ref.rs:23:27
+ |
+LL | let mut closure = || p = &y;
+ | ^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ extern "rust-call" fn(()),
+ (&'_#1r mut &'_#2r i32, &'_#3r i32),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#3r: '_#2r
+
+note: no external requirements
+ --> $DIR/escape-upvar-ref.rs:17:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/escape-upvar-ref.rs:23:35
+ |
+LL | let mut closure = || p = &y;
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
+...
+LL | }
+ | - `y` dropped here while still borrowed
+LL |
+LL | deref(p);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs b/tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs
new file mode 100644
index 000000000..a83ebc21f
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+// Test that we propagate region relations from closures precisely when there is
+// more than one non-local lower bound.
+
+// In this case the closure has signature
+// |x: &'4 mut (&'5 (&'1 str, &'2 str), &'3 str)| -> ..
+// We end up with a `'3: '5` constraint that we can propagate as
+// `'3: '1`, `'3: '2`, but previously we approximated it as `'3: 'static`.
+
+// As an optimization, we primarily propagate bounds for the "representative"
+// of each SCC. As such we have these two similar cases where hopefully one
+// of them will test the case we want (case2, when this test was added).
+mod case1 {
+ fn f(s: &str) {
+ g(s, |x| h(x));
+ }
+
+ fn g<T, F>(_: T, _: F)
+ where F: Fn(&mut (&(T, T), T)) {}
+
+ fn h<T>(_: &mut (&(T, T), T)) {}
+}
+
+mod case2 {
+ fn f(s: &str) {
+ g(s, |x| h(x));
+ }
+
+ fn g<T, F>(_: T, _: F)
+ where F: Fn(&mut (T, &(T, T))) {}
+
+ fn h<T>(_: &mut (T, &(T, T))) {}
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs
new file mode 100644
index 000000000..35a864b88
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs
@@ -0,0 +1,51 @@
+// Test where we fail to approximate due to demanding a postdom
+// relationship between our upper bounds.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'x: 'b
+// 'c: 'y
+//
+// we have to prove that `'x: 'y`. We currently can only approximate
+// via a postdominator -- hence we fail to choose between `'a` and
+// `'b` here and report the error in the closure.
+fn establish_relationships<'a, 'b, 'c, F>(
+ _cell_a: Cell<&'a u32>,
+ _cell_b: Cell<&'b u32>,
+ _cell_c: Cell<&'c u32>,
+ _closure: F,
+) where
+ F: for<'x, 'y> FnMut(
+ Cell<&'a &'x u32>, // shows that 'x: 'a
+ Cell<&'b &'x u32>, // shows that 'x: 'b
+ Cell<&'y &'c u32>, // shows that 'c: 'y
+ Cell<&'x u32>,
+ Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
+ establish_relationships(
+ cell_a,
+ cell_b,
+ cell_c,
+ |_outlives1, _outlives2, _outlives3, x, y| {
+ // Only works if 'x: 'y:
+ let p = x.get();
+ demand_y(x, y, p) //~ ERROR
+ },
+ );
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
new file mode 100644
index 000000000..7da6ce58b
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -0,0 +1,36 @@
+note: no external requirements
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:43:9
+ |
+LL | |_outlives1, _outlives2, _outlives3, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#4r
+ = note: late-bound region is '_#5r
+ = note: late-bound region is '_#6r
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13
+ |
+LL | |_outlives1, _outlives2, _outlives3, x, y| {
+ | ---------- ---------- has type `Cell<&'2 &'_#3r u32>`
+ | |
+ | has type `Cell<&'_#1r &'1 u32>`
+...
+LL | demand_y(x, y, p)
+ | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+note: no external requirements
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:38:1
+ |
+LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs b/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs
new file mode 100644
index 000000000..7291c6e97
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs
@@ -0,0 +1,50 @@
+// Rather convoluted setup where we infer a relationship between two
+// free regions in the closure signature (`'a` and `'b`) on the basis
+// of a relationship between two bound regions (`'x` and `'y`).
+//
+// The idea is that, thanks to invoking `demand_y`, `'x: 'y` must
+// hold, where `'x` and `'y` are bound regions. The closure can't
+// prove that directly, and because `'x` and `'y` are bound it cannot
+// ask the caller to prove it either. But it has bounds on `'x` and
+// `'y` in terms of `'a` and `'b`, and it can propagate a relationship
+// between `'a` and `'b` to the caller.
+//
+// Note: the use of `Cell` here is to introduce invariance. One less
+// variable.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'b: 'y
+//
+// so if we are going to ensure that `'x: 'y`, then `'a: 'b` must
+// hold.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'a &'x u32>, // shows that 'x: 'a
+ &Cell<&'y &'b u32>, // shows that 'b: 'y
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ //~^ ERROR lifetime may not live long enough
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
new file mode 100644
index 000000000..993687605
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -0,0 +1,39 @@
+note: external requirements
+ --> $DIR/propagate-approximated-ref.rs:43:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-ref.rs:42:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-approximated-ref.rs:45:9
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
new file mode 100644
index 000000000..afe6f10a5
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
@@ -0,0 +1,40 @@
+// Test a case where we setup relationships like `'x: 'a` or `'a: 'x`,
+// where `'x` is bound in closure type but `'a` is free. This forces
+// us to approximate `'x` one way or the other.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+fn foo<'a, F>(_cell: Cell<&'a u32>, _f: F)
+where
+ F: for<'x> FnOnce(Cell<&'a u32>, Cell<&'x u32>),
+{
+}
+
+#[rustc_regions]
+fn case1() {
+ let a = 0;
+ let cell = Cell::new(&a);
+ foo(cell, |cell_a, cell_x| {
+ cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
+ //~^ ERROR
+ })
+}
+
+#[rustc_regions]
+fn case2() {
+ let a = 0;
+ let cell = Cell::new(&a);
+ //~^ ERROR `a` does not live long enough
+
+ // As you can see in the stderr output, this closure propoagates a
+ // requirement that `'a: 'static'.
+ foo(cell, |cell_a, cell_x| {
+ cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
+ })
+}
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
new file mode 100644
index 000000000..7991abeb7
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -0,0 +1,69 @@
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:21:15
+ |
+LL | foo(cell, |cell_a, cell_x| {
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: case1::{closure#0} with closure substs [
+ i32,
+ for<Region(BrAnon(0, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
+ (),
+ ]
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:22:9
+ |
+LL | foo(cell, |cell_a, cell_x| {
+ | ------ ------ `cell_x` is a reference that is only valid in the closure body
+ | |
+ | `cell_a` declared here, outside of the closure body
+LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:18:1
+ |
+LL | fn case1() {
+ | ^^^^^^^^^^
+ |
+ = note: defining type: case1
+
+note: external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:35:15
+ |
+LL | foo(cell, |cell_a, cell_x| {
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: case2::{closure#0} with closure substs [
+ i32,
+ for<Region(BrAnon(0, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
+ (),
+ ]
+ = note: number of external vids: 2
+ = note: where '_#1r: '_#0r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1
+ |
+LL | fn case2() {
+ | ^^^^^^^^^^
+ |
+ = note: defining type: case2
+
+error[E0597]: `a` does not live long enough
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
+ |
+LL | let cell = Cell::new(&a);
+ | ^^ borrowed value does not live long enough
+...
+LL | / foo(cell, |cell_a, cell_x| {
+LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
+LL | | })
+ | |______- argument requires that `a` is borrowed for `'static`
+LL | }
+ | - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0521, E0597.
+For more information about an error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
new file mode 100644
index 000000000..372209075
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
@@ -0,0 +1,40 @@
+// Test a case where we are trying to prove `'x: 'y` and are forced to
+// approximate the shorter end-point (`'y`) to with `'static`. This is
+// because `'y` is higher-ranked but we know of no relations to other
+// regions. Note that `'static` shows up in the stderr output as `'0`.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+//
+// so the only way we can ensure that `'x: 'y` is to show that
+// `'a: 'static`.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'a &'x u32>, // shows that 'x: 'a
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ //~^ ERROR borrowed data escapes outside of function
+
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
new file mode 100644
index 000000000..43dfc3bb9
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -0,0 +1,49 @@
+note: external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where '_#1r: '_#0r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:31:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- ------ `cell_a` is a reference that is only valid in the function body
+ | |
+ | lifetime `'a` defined here
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+LL | |
+LL | |
+LL | | // Only works if 'x: 'y:
+LL | | demand_y(x, y, x.get())
+LL | | });
+ | | ^
+ | | |
+ | |______`cell_a` escapes the function body here
+ | argument requires that `'a` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `Cell<&'_#9r u32>`, which makes the generic argument `&'_#9r u32` invariant
+ = note: the struct `Cell<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
new file mode 100644
index 000000000..9898777c7
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
@@ -0,0 +1,43 @@
+// Test a case where we are trying to prove `'x: 'y` and are forced to
+// approximate the shorter end-point (`'y`) to with `'static`. This is
+// because `'y` is higher-ranked but we know of only irrelevant
+// relations to other regions. Note that `'static` shows up in the
+// stderr output as `'0`.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'y: 'b
+//
+// so the only way we can ensure that `'x: 'y` is to show that
+// `'a: 'static`.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'a &'x u32>, // shows that 'x: 'a
+ &Cell<&'b &'y u32>, // shows that 'y: 'b
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ //~^ ERROR borrowed data escapes outside of function
+
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
new file mode 100644
index 000000000..96c734226
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -0,0 +1,49 @@
+note: external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where '_#1r: '_#0r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:34:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- ------ `cell_a` is a reference that is only valid in the function body
+ | |
+ | lifetime `'a` defined here
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+LL | |
+LL | |
+LL | | // Only works if 'x: 'y:
+LL | | demand_y(x, y, x.get())
+LL | | });
+ | | ^
+ | | |
+ | |______`cell_a` escapes the function body here
+ | argument requires that `'a` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `Cell<&'_#10r u32>`, which makes the generic argument `&'_#10r u32` invariant
+ = note: the struct `Cell<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.rs b/tests/ui/nll/closure-requirements/propagate-approximated-val.rs
new file mode 100644
index 000000000..5bb5eea99
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.rs
@@ -0,0 +1,43 @@
+// A simpler variant of `outlives-from-argument` where cells are
+// passed by value.
+//
+// This is simpler because there are no "extraneous" region
+// relationships. In the 'main' variant, there are a number of
+// anonymous regions as well.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'b: 'y
+//
+// so if we are going to ensure that `'x: 'y`, then `'a: 'b` must
+// hold.
+fn establish_relationships<'a, 'b, F>(_cell_a: Cell<&'a u32>, _cell_b: Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ Cell<&'a &'x u32>, // shows that 'x: 'a
+ Cell<&'y &'b u32>, // shows that 'b: 'y
+ Cell<&'x u32>,
+ Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_outlives1: Cell<&&'x u32>, _outlives2: Cell<&'y &u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(outlives1, outlives2, x.get())
+ //~^ ERROR lifetime may not live long enough
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
new file mode 100644
index 000000000..03dbd686e
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -0,0 +1,39 @@
+note: external requirements
+ --> $DIR/propagate-approximated-val.rs:36:45
+ |
+LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-val.rs:35:1
+ |
+LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: test
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-approximated-val.rs:38:9
+ |
+LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(outlives1, outlives2, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs
new file mode 100644
index 000000000..704a026d2
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs
@@ -0,0 +1,50 @@
+// Test where we might in theory be able to see that the relationship
+// between two bound regions is true within closure and hence have no
+// need to propagate; but in fact we do because identity of free
+// regions is erased.
+
+// compile-flags:-Zverbose
+// check-pass
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// In theory, callee knows that:
+//
+// 'x: 'a
+// 'a: 'y
+//
+// and hence could satisfy that `'x: 'y` locally. However, in our
+// checking, we ignore the precise free regions that come into the
+// region and just assign each position a distinct universally bound
+// region. Hence, we propagate a constraint to our caller that will
+// wind up being solvable.
+fn establish_relationships<'a, F>(
+ _cell_a: Cell<&'a u32>,
+ _closure: F,
+) where
+ F: for<'x, 'y> FnMut(
+ Cell<&'a &'x u32>, // shows that 'x: 'a
+ Cell<&'y &'a u32>, // shows that 'a: 'y
+ Cell<&'x u32>,
+ Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a>(cell_a: Cell<&'a u32>) {
+ establish_relationships(
+ cell_a,
+ |_outlives1, _outlives2, x, y| {
+ // Only works if 'x: 'y:
+ let p = x.get();
+ demand_y(x, y, p)
+ },
+ );
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
new file mode 100644
index 000000000..d716d3de2
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -0,0 +1,23 @@
+note: external requirements
+ --> $DIR/propagate-despite-same-free-region.rs:42:9
+ |
+LL | |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/propagate-despite-same-free-region.rs:39:1
+ |
+LL | fn supply<'a>(cell_a: Cell<&'a u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
new file mode 100644
index 000000000..dcd05d7fa
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
@@ -0,0 +1,42 @@
+// Similarly to escape-argument-callee, a test case where the closure
+// requires a relationship between 2 unrelated higher-ranked regions,
+// with no helpful relations between the HRRs and free regions.
+//
+// In this case, the error is reported by the closure itself. This is
+// because it is unable to approximate the higher-ranked region `'x`,
+// as it knows of no relationships between `'x` and any
+// non-higher-ranked regions.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'b: 'y
+//
+// but this doesn't really help us in proving that `'x: 'y`, so closure gets an error.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'y &'b u32>, // shows that 'b: 'y
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ //~^ ERROR
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
new file mode 100644
index 000000000..b924873fc
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -0,0 +1,35 @@
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:35:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: late-bound region is '_#3r
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ | --------- - has type `&'_#7r Cell<&'1 u32>`
+ | |
+ | has type `&'_#5r Cell<&'2 &'_#1r u32>`
+LL | // Only works if 'x: 'y:
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:34:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs
new file mode 100644
index 000000000..98be92d1c
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs
@@ -0,0 +1,46 @@
+// Similarly to escape-argument-callee, a test case where the closure
+// requires a relationship between 2 unrelated higher-ranked regions,
+// with no helpful relations between the HRRs and free regions.
+//
+// In this case, the error is reported by the closure itself. This is
+// because it is unable to approximate the higher-ranked region `'x`,
+// as it only knows of regions that `'x` is outlived by, and none that
+// `'x` outlives.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'a: 'x
+// 'b: 'y
+//
+// but this doesn't really help us in proving that `'x: 'y`, so
+// closure gets an error. In particular, we would need to know that
+// `'x: 'a`, so that we could approximate `'x` "downwards" to `'a`.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'x &'a u32>, // shows that 'a: 'x
+ &Cell<&'y &'b u32>, // shows that 'b: 'y
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ //~^ ERROR
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
new file mode 100644
index 000000000..9b25efd0b
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -0,0 +1,35 @@
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:39:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ---------- ---------- has type `&'_#8r Cell<&'2 &'_#2r u32>`
+ | |
+ | has type `&'_#6r Cell<&'1 &'_#1r u32>`
+LL | // Only works if 'x: 'y:
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:38:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-from-trait-match.rs b/tests/ui/nll/closure-requirements/propagate-from-trait-match.rs
new file mode 100644
index 000000000..cda781d8e
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-from-trait-match.rs
@@ -0,0 +1,48 @@
+// Test that regions which appear only in the closure's generics (in
+// this case, `'a`) are properly mapped to the creator's generics. In
+// this case, the closure constrains its type parameter `T` to outlive
+// the same `'a` for which it implements `Trait`, which can only be the `'a`
+// from the function definition.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+trait Trait<'a> {}
+
+fn establish_relationships<T, F>(value: T, closure: F)
+where
+ F: FnOnce(T),
+{
+ closure(value)
+}
+
+fn require<'a, T>(t: T)
+where
+ T: Trait<'a> + 'a,
+{
+}
+
+#[rustc_regions]
+fn supply<'a, T>(value: T)
+where
+ T: Trait<'a>,
+{
+ establish_relationships(value, |value| {
+ // This function call requires that
+ //
+ // (a) T: Trait<'a>
+ //
+ // and
+ //
+ // (b) T: 'a
+ //
+ // The latter does not hold.
+
+ require(value);
+ //~^ ERROR the parameter type `T` may not live long enough
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
new file mode 100644
index 000000000..038a5e11f
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -0,0 +1,38 @@
+note: external requirements
+ --> $DIR/propagate-from-trait-match.rs:32:36
+ |
+LL | establish_relationships(value, |value| {
+ | ^^^^^^^
+ |
+ = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((T,)),
+ (),
+ ]
+ = note: number of external vids: 2
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/propagate-from-trait-match.rs:28:1
+ |
+LL | / fn supply<'a, T>(value: T)
+LL | | where
+LL | | T: Trait<'a>,
+ | |_________________^
+ |
+ = note: defining type: supply::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/propagate-from-trait-match.rs:43:9
+ |
+LL | require(value);
+ | ^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Trait<'a> + 'a,
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs
new file mode 100644
index 000000000..a9d2a0771
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs
@@ -0,0 +1,23 @@
+// Test that we propagate *all* requirements to the caller, not just the first
+// one.
+
+fn once<S, T, U, F: FnOnce(S, T) -> U>(f: F, s: S, t: T) -> U {
+ f(s, t)
+}
+
+pub fn dangle() -> &'static [i32] {
+ let other_local_arr = [0, 2, 4];
+ let local_arr = other_local_arr;
+ let mut out: &mut &'static [i32] = &mut (&[1] as _);
+ once(|mut z: &[i32], mut out_val: &mut &[i32]| {
+ // We unfortunately point to the first use in the closure in the error
+ // message
+ z = &local_arr; //~ ERROR
+ *out_val = &local_arr;
+ }, &[] as &[_], &mut *out);
+ *out
+}
+
+fn main() {
+ println!("{:?}", dangle());
+}
diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
new file mode 100644
index 000000000..2fec9bc62
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
@@ -0,0 +1,17 @@
+error[E0597]: `local_arr` does not live long enough
+ --> $DIR/propagate-multiple-requirements.rs:15:14
+ |
+LL | let mut out: &mut &'static [i32] = &mut (&[1] as _);
+ | ------------------- type annotation requires that `local_arr` is borrowed for `'static`
+LL | once(|mut z: &[i32], mut out_val: &mut &[i32]| {
+ | ----------------------------------------- value captured here
+...
+LL | z = &local_arr;
+ | ^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `local_arr` 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/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs
new file mode 100644
index 000000000..8147da09d
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs
@@ -0,0 +1,13 @@
+// Basic test for free regions in the NLL code. This test ought to
+// report an error due to a reborrowing constraint. Right now, we get
+// a variety of errors from the older, AST-based machinery (notably
+// borrowck), and then we get the NLL error at the end.
+
+// compile-flags:-Zverbose
+
+fn foo(x: &u32) -> &'static u32 {
+ &*x
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr
new file mode 100644
index 000000000..7034492ce
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/region-lbr-anon-does-not-outlive-static.rs:9:5
+ |
+LL | fn foo(x: &u32) -> &'static u32 {
+ | - let's call the lifetime of this reference `'1`
+LL | &*x
+ | ^^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs
new file mode 100644
index 000000000..4acd2fc92
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs
@@ -0,0 +1,13 @@
+// Basic test for free regions in the NLL code. This test ought to
+// report an error due to a reborrowing constraint. Right now, we get
+// a variety of errors from the older, AST-based machinery (notably
+// borrowck), and then we get the NLL error at the end.
+
+// compile-flags:-Zverbose
+
+fn foo<'a>(x: &'a u32) -> &'static u32 {
+ &*x
+ //~^ ERROR
+}
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr
new file mode 100644
index 000000000..d0a24a267
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/region-lbr-named-does-not-outlive-static.rs:9:5
+ |
+LL | fn foo<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | &*x
+ | ^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs
new file mode 100644
index 000000000..06e96be80
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs
@@ -0,0 +1,13 @@
+// Basic test for free regions in the NLL code. This test ought to
+// report an error due to a reborrowing constraint. Right now, we get
+// a variety of errors from the older, AST-based machinery (notably
+// borrowck), and then we get the NLL error at the end.
+
+// compile-flags:-Zverbose
+
+fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
+ &*x
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr
new file mode 100644
index 000000000..d0ba53925
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/region-lbr1-does-not-outlive-ebr2.rs:9:5
+ |
+LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | &*x
+ | ^^^ 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/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs b/tests/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs
new file mode 100644
index 000000000..014959fdb
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs
@@ -0,0 +1,11 @@
+// Basic test for free regions in the NLL code. This test does not
+// report an error because of the (implied) bound that `'b: 'a`.
+
+// check-pass
+// compile-flags:-Zverbose
+
+fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 {
+ &**x
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/return-wrong-bound-region.rs b/tests/ui/nll/closure-requirements/return-wrong-bound-region.rs
new file mode 100644
index 000000000..e34a3f6f2
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/return-wrong-bound-region.rs
@@ -0,0 +1,23 @@
+// Test closure that takes two references and is supposed to return
+// the first, but actually returns the second. This should fail within
+// the closure.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ expect_sig(|a, b| b); // ought to return `a`
+ //~^ ERROR
+}
+
+fn expect_sig<F>(f: F) -> F
+ where F: for<'a> FnMut(&'a i32, &i32) -> &'a i32
+{
+ f
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
new file mode 100644
index 000000000..6db72b886
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -0,0 +1,31 @@
+note: no external requirements
+ --> $DIR/return-wrong-bound-region.rs:11:16
+ |
+LL | expect_sig(|a, b| b); // ought to return `a`
+ | ^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32,
+ (),
+ ]
+
+error: lifetime may not live long enough
+ --> $DIR/return-wrong-bound-region.rs:11:23
+ |
+LL | expect_sig(|a, b| b); // ought to return `a`
+ | - - ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ | | |
+ | | has type `&'1 i32`
+ | has type `&'2 i32`
+
+note: no external requirements
+ --> $DIR/return-wrong-bound-region.rs:10:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-use-spans.rs b/tests/ui/nll/closure-use-spans.rs
new file mode 100644
index 000000000..6768250dc
--- /dev/null
+++ b/tests/ui/nll/closure-use-spans.rs
@@ -0,0 +1,21 @@
+// check that liveness due to a closure capture gives a special note
+
+fn use_as_borrow_capture(mut x: i32) {
+ let y = &x;
+ x = 0; //~ ERROR
+ || *y;
+}
+
+fn use_as_borrow_mut_capture(mut x: i32) {
+ let y = &mut x;
+ x = 0; //~ ERROR
+ || *y = 1;
+}
+
+fn use_as_move_capture(mut x: i32) {
+ let y = &x;
+ x = 0; //~ ERROR
+ move || *y;
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-use-spans.stderr b/tests/ui/nll/closure-use-spans.stderr
new file mode 100644
index 000000000..ad928f1bb
--- /dev/null
+++ b/tests/ui/nll/closure-use-spans.stderr
@@ -0,0 +1,33 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-use-spans.rs:5:5
+ |
+LL | let y = &x;
+ | -- borrow of `x` occurs here
+LL | x = 0;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | || *y;
+ | -- borrow later captured here by closure
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-use-spans.rs:11:5
+ |
+LL | let y = &mut x;
+ | ------ borrow of `x` occurs here
+LL | x = 0;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | || *y = 1;
+ | -- borrow later captured here by closure
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-use-spans.rs:17:5
+ |
+LL | let y = &x;
+ | -- borrow of `x` occurs here
+LL | x = 0;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | move || *y;
+ | -- borrow later captured here by closure
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/closures-in-loops.rs b/tests/ui/nll/closures-in-loops.rs
new file mode 100644
index 000000000..491c186ec
--- /dev/null
+++ b/tests/ui/nll/closures-in-loops.rs
@@ -0,0 +1,24 @@
+// Test messages where a closure capture conflicts with itself because it's in
+// a loop.
+
+fn repreated_move(x: String) {
+ for i in 0..10 {
+ || x; //~ ERROR
+ }
+}
+
+fn repreated_mut_borrow(mut x: String) {
+ let mut v = Vec::new();
+ for i in 0..10 {
+ v.push(|| x = String::new()); //~ ERROR
+ }
+}
+
+fn repreated_unique_borrow(x: &mut String) {
+ let mut v = Vec::new();
+ for i in 0..10 {
+ v.push(|| *x = String::new()); //~ ERROR
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closures-in-loops.stderr b/tests/ui/nll/closures-in-loops.stderr
new file mode 100644
index 000000000..1c1a31d35
--- /dev/null
+++ b/tests/ui/nll/closures-in-loops.stderr
@@ -0,0 +1,35 @@
+error[E0382]: use of moved value: `x`
+ --> $DIR/closures-in-loops.rs:6:9
+ |
+LL | fn repreated_move(x: String) {
+ | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | for i in 0..10 {
+LL | || x;
+ | ^^ - use occurs due to use in closure
+ | |
+ | value moved into closure here, in previous iteration of loop
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+ --> $DIR/closures-in-loops.rs:13:16
+ |
+LL | v.push(|| x = String::new());
+ | -------^^-------------------
+ | | | |
+ | | | borrows occur due to use of `x` in closure
+ | | `x` was mutably borrowed here in the previous iteration of the loop
+ | first borrow used here, in later iteration of loop
+
+error[E0524]: two closures require unique access to `x` at the same time
+ --> $DIR/closures-in-loops.rs:20:16
+ |
+LL | v.push(|| *x = String::new());
+ | -------^^--------------------
+ | | | |
+ | | | borrows occur due to use of `x` in closure
+ | | closures are constructed here in different iterations of loop
+ | first borrow used here, in later iteration of loop
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0499, E0524.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/nll/constant-thread-locals-issue-47053.rs b/tests/ui/nll/constant-thread-locals-issue-47053.rs
new file mode 100644
index 000000000..dde0ef7a5
--- /dev/null
+++ b/tests/ui/nll/constant-thread-locals-issue-47053.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #47053
+
+#![feature(thread_local)]
+
+#[thread_local]
+static FOO: isize = 5;
+
+fn main() {
+ FOO = 6; //~ ERROR cannot assign to immutable static item `FOO` [E0594]
+}
diff --git a/tests/ui/nll/constant-thread-locals-issue-47053.stderr b/tests/ui/nll/constant-thread-locals-issue-47053.stderr
new file mode 100644
index 000000000..a44acfb5f
--- /dev/null
+++ b/tests/ui/nll/constant-thread-locals-issue-47053.stderr
@@ -0,0 +1,9 @@
+error[E0594]: cannot assign to immutable static item `FOO`
+ --> $DIR/constant-thread-locals-issue-47053.rs:9: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/nll/constant.rs b/tests/ui/nll/constant.rs
new file mode 100644
index 000000000..47f0eadf9
--- /dev/null
+++ b/tests/ui/nll/constant.rs
@@ -0,0 +1,10 @@
+// Test that MIR borrowck and NLL analysis can handle constants of
+// arbitrary types without ICEs.
+
+// check-pass
+
+const HI: &str = "hi";
+
+fn main() {
+ assert_eq!(HI, "hi");
+}
diff --git a/tests/ui/nll/continue-after-missing-main.rs b/tests/ui/nll/continue-after-missing-main.rs
new file mode 100644
index 000000000..778639158
--- /dev/null
+++ b/tests/ui/nll/continue-after-missing-main.rs
@@ -0,0 +1,29 @@
+#![allow(dead_code)]
+
+struct Tableau<'a, MP> {
+ provider: &'a MP,
+}
+
+impl<'adapted_matrix_provider, 'original_data, MP>
+ Tableau<'adapted_matrix_provider, AdaptedMatrixProvider<'original_data, MP>>
+{
+ fn provider(&self) -> &'adapted_matrix_provider AdaptedMatrixProvider</*'original_data,*/ MP> {
+ self.provider
+ }
+}
+
+struct AdaptedMatrixProvider<'a, T> {
+ original_problem: &'a T,
+}
+
+impl<'a, T> AdaptedMatrixProvider<'a, T> {
+ fn clone_with_extra_bound(&self) -> Self {
+ AdaptedMatrixProvider { original_problem: self.original_problem }
+ }
+}
+
+fn create_and_solve_subproblems<'data_provider, 'original_data, MP>(
+ tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
+) {
+ let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
+} //~ ERROR `main` function not found in crate
diff --git a/tests/ui/nll/continue-after-missing-main.stderr b/tests/ui/nll/continue-after-missing-main.stderr
new file mode 100644
index 000000000..0df8d8d70
--- /dev/null
+++ b/tests/ui/nll/continue-after-missing-main.stderr
@@ -0,0 +1,9 @@
+error[E0601]: `main` function not found in crate `continue_after_missing_main`
+ --> $DIR/continue-after-missing-main.rs:29:2
+ |
+LL | }
+ | ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/nll/decl-macro-illegal-copy.rs b/tests/ui/nll/decl-macro-illegal-copy.rs
new file mode 100644
index 000000000..f72432946
--- /dev/null
+++ b/tests/ui/nll/decl-macro-illegal-copy.rs
@@ -0,0 +1,28 @@
+// Regression test for #46314
+
+#![feature(decl_macro)]
+
+struct NonCopy(String);
+
+struct Wrapper {
+ inner: NonCopy,
+}
+
+macro inner_copy($wrapper:ident) {
+ $wrapper.inner
+}
+
+fn main() {
+ let wrapper = Wrapper {
+ inner: NonCopy("foo".into()),
+ };
+ assert_two_non_copy(
+ inner_copy!(wrapper),
+ wrapper.inner,
+ //~^ ERROR use of moved value: `wrapper.inner` [E0382]
+ );
+}
+
+fn assert_two_non_copy(a: NonCopy, b: NonCopy) {
+ assert_eq!(a.0, b.0);
+}
diff --git a/tests/ui/nll/decl-macro-illegal-copy.stderr b/tests/ui/nll/decl-macro-illegal-copy.stderr
new file mode 100644
index 000000000..7948485bd
--- /dev/null
+++ b/tests/ui/nll/decl-macro-illegal-copy.stderr
@@ -0,0 +1,14 @@
+error[E0382]: use of moved value: `wrapper.inner`
+ --> $DIR/decl-macro-illegal-copy.rs:21:9
+ |
+LL | $wrapper.inner
+ | -------------- value moved here
+...
+LL | wrapper.inner,
+ | ^^^^^^^^^^^^^ value used here after move
+ |
+ = note: move occurs because `wrapper.inner` has type `NonCopy`, 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/nll/do-not-ignore-lifetime-bounds-in-copy-proj.rs b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.rs
new file mode 100644
index 000000000..96c871946
--- /dev/null
+++ b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.rs
@@ -0,0 +1,12 @@
+// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
+
+#[derive(Clone)]
+struct Foo<'a>(&'a u32);
+impl Copy for Foo<'static> {}
+
+fn main() {
+ let s = 2;
+ let a = (Foo(&s),); //~ ERROR `s` does not live long enough [E0597]
+ drop(a.0);
+ drop(a.0);
+}
diff --git a/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr
new file mode 100644
index 000000000..65be3b37e
--- /dev/null
+++ b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `s` does not live long enough
+ --> $DIR/do-not-ignore-lifetime-bounds-in-copy-proj.rs:9:18
+ |
+LL | let a = (Foo(&s),);
+ | ^^ borrowed value does not live long enough
+LL | drop(a.0);
+ | --- copying this value requires that `s` is borrowed for `'static`
+LL | drop(a.0);
+LL | }
+ | - `s` 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/nll/do-not-ignore-lifetime-bounds-in-copy.rs b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.rs
new file mode 100644
index 000000000..99922cc51
--- /dev/null
+++ b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.rs
@@ -0,0 +1,11 @@
+// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
+
+#[derive(Clone)] struct Foo<'a>(&'a u32);
+impl Copy for Foo<'static> {}
+
+fn main() {
+ let s = 2;
+ let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597]
+ drop(a);
+ drop(a);
+}
diff --git a/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr
new file mode 100644
index 000000000..b811ba4fd
--- /dev/null
+++ b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `s` does not live long enough
+ --> $DIR/do-not-ignore-lifetime-bounds-in-copy.rs:8:17
+ |
+LL | let a = Foo(&s);
+ | ^^ borrowed value does not live long enough
+LL | drop(a);
+ | - copying this value requires that `s` is borrowed for `'static`
+LL | drop(a);
+LL | }
+ | - `s` 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/nll/dont-print-desugared.rs b/tests/ui/nll/dont-print-desugared.rs
new file mode 100644
index 000000000..829d78ed4
--- /dev/null
+++ b/tests/ui/nll/dont-print-desugared.rs
@@ -0,0 +1,21 @@
+// Test that we don't show variables with from for loop desugaring
+
+fn for_loop(s: &[i32]) {
+ for &ref mut x in s {}
+ //~^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
+}
+
+struct D<'a>(&'a ());
+
+impl Drop for D<'_> {
+ fn drop(&mut self) {}
+}
+
+fn for_loop_dropck(v: Vec<D<'static>>) {
+ for ref mut d in v {
+ let y = ();
+ *d = D(&y); //~ ERROR `y` does not live long enough
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/dont-print-desugared.stderr b/tests/ui/nll/dont-print-desugared.stderr
new file mode 100644
index 000000000..fad6121cb
--- /dev/null
+++ b/tests/ui/nll/dont-print-desugared.stderr
@@ -0,0 +1,24 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/dont-print-desugared.rs:4:10
+ |
+LL | for &ref mut x in s {}
+ | ^^^^^^^^^ cannot borrow as mutable
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/dont-print-desugared.rs:17:16
+ |
+LL | for ref mut d in v {
+ | - a temporary with access to the borrow is created here ...
+LL | let y = ();
+LL | *d = D(&y);
+ | ^^ borrowed value does not live long enough
+LL | }
+ | -
+ | |
+ | `y` dropped here while still borrowed
+ | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0596, E0597.
+For more information about an error, try `rustc --explain E0596`.
diff --git a/tests/ui/nll/drop-may-dangle.rs b/tests/ui/nll/drop-may-dangle.rs
new file mode 100644
index 000000000..b5531c29b
--- /dev/null
+++ b/tests/ui/nll/drop-may-dangle.rs
@@ -0,0 +1,34 @@
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` includes the points after `&v[0]` up to (but not
+// including) the call to `use_x`. The `else` branch is not included.
+
+// check-pass
+
+#![allow(warnings)]
+#![feature(dropck_eyepatch)]
+
+fn use_x(_: usize) -> bool { true }
+
+fn main() {
+ let mut v = [1, 2, 3];
+ let p: WrapMayDangle<& /* R4 */ usize> = WrapMayDangle { value: &v[0] };
+ if true {
+ // `p` will get dropped at end of this block. However, because of
+ // the `#[may_dangle]` attribute, we do not need to consider R4
+ // live after this point.
+ use_x(*p.value);
+ } else {
+ v[0] += 1;
+ use_x(22);
+ }
+
+ v[0] += 1;
+}
+
+struct WrapMayDangle<T> {
+ value: T
+}
+
+unsafe impl<#[may_dangle] T> Drop for WrapMayDangle<T> {
+ fn drop(&mut self) { }
+}
diff --git a/tests/ui/nll/drop-no-may-dangle.rs b/tests/ui/nll/drop-no-may-dangle.rs
new file mode 100644
index 000000000..a0ff0c398
--- /dev/null
+++ b/tests/ui/nll/drop-no-may-dangle.rs
@@ -0,0 +1,30 @@
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` must include everything until `p` is dropped
+// because of destructor. (Note that the stderr also identifies this
+// destructor in the error message.)
+
+#![allow(warnings)]
+#![feature(dropck_eyepatch)]
+
+fn use_x(_: usize) -> bool { true }
+
+fn main() {
+ let mut v = [1, 2, 3];
+ let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] };
+ if true {
+ use_x(*p.value);
+ } else {
+ use_x(22);
+ v[0] += 1; //~ ERROR cannot assign to `v[_]` because it is borrowed
+ }
+
+ v[0] += 1; //~ ERROR cannot assign to `v[_]` because it is borrowed
+}
+
+struct WrapMayNotDangle<T> {
+ value: T
+}
+
+impl<T> Drop for WrapMayNotDangle<T> {
+ fn drop(&mut self) { }
+}
diff --git a/tests/ui/nll/drop-no-may-dangle.stderr b/tests/ui/nll/drop-no-may-dangle.stderr
new file mode 100644
index 000000000..cb2808809
--- /dev/null
+++ b/tests/ui/nll/drop-no-may-dangle.stderr
@@ -0,0 +1,26 @@
+error[E0506]: cannot assign to `v[_]` because it is borrowed
+ --> $DIR/drop-no-may-dangle.rs:18:9
+ |
+LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] };
+ | ----- borrow of `v[_]` occurs here
+...
+LL | v[0] += 1;
+ | ^^^^^^^^^ assignment to borrowed `v[_]` occurs here
+...
+LL | }
+ | - borrow might be used here, when `p` is dropped and runs the `Drop` code for type `WrapMayNotDangle`
+
+error[E0506]: cannot assign to `v[_]` because it is borrowed
+ --> $DIR/drop-no-may-dangle.rs:21:5
+ |
+LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] };
+ | ----- borrow of `v[_]` occurs here
+...
+LL | v[0] += 1;
+ | ^^^^^^^^^ assignment to borrowed `v[_]` occurs here
+LL | }
+ | - borrow might be used here, when `p` is dropped and runs the `Drop` code for type `WrapMayNotDangle`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/empty-type-predicate-2.rs b/tests/ui/nll/empty-type-predicate-2.rs
new file mode 100644
index 000000000..20d6e47f7
--- /dev/null
+++ b/tests/ui/nll/empty-type-predicate-2.rs
@@ -0,0 +1,18 @@
+// Regression test for #65553
+//
+// `D::Error:` is lowered to `D::Error: ReEmpty` - check that we don't ICE in
+// NLL for the unexpected region.
+
+// check-pass
+
+trait Deserializer {
+ type Error;
+}
+
+fn d1<D: Deserializer>() where D::Error: {}
+
+fn d2<D: Deserializer>() {
+ d1::<D>();
+}
+
+fn main() {}
diff --git a/tests/ui/nll/empty-type-predicate.rs b/tests/ui/nll/empty-type-predicate.rs
new file mode 100644
index 000000000..d126a455d
--- /dev/null
+++ b/tests/ui/nll/empty-type-predicate.rs
@@ -0,0 +1,11 @@
+// Regression test for #61315
+//
+// `dyn T:` is lowered to `dyn T: ReEmpty` - check that we don't ICE in NLL for
+// the unexpected region.
+
+// check-pass
+
+trait T {}
+fn f() where dyn T: {}
+
+fn main() { f(); }
diff --git a/tests/ui/nll/enum-drop-access.rs b/tests/ui/nll/enum-drop-access.rs
new file mode 100644
index 000000000..5ef0c3fe7
--- /dev/null
+++ b/tests/ui/nll/enum-drop-access.rs
@@ -0,0 +1,49 @@
+enum DropOption<T> {
+ Some(T),
+ None,
+}
+
+impl<T> Drop for DropOption<T> {
+ fn drop(&mut self) {}
+}
+
+// Dropping opt could access the value behind the reference,
+fn drop_enum(opt: DropOption<&mut i32>) -> Option<&mut i32> {
+ match opt {
+ DropOption::Some(&mut ref mut r) => { //~ ERROR
+ Some(r)
+ },
+ DropOption::None => None,
+ }
+}
+
+fn optional_drop_enum(opt: Option<DropOption<&mut i32>>) -> Option<&mut i32> {
+ match opt {
+ Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR
+ Some(r)
+ },
+ Some(DropOption::None) | None => None,
+ }
+}
+
+// Ok, dropping opt doesn't access the reference
+fn optional_tuple(opt: Option<(&mut i32, String)>) -> Option<&mut i32> {
+ match opt {
+ Some((&mut ref mut r, _)) => {
+ Some(r)
+ },
+ None => None,
+ }
+}
+
+// Ok, dropping res doesn't access the Ok case.
+fn different_variants(res: Result<&mut i32, String>) -> Option<&mut i32> {
+ match res {
+ Ok(&mut ref mut r) => {
+ Some(r)
+ },
+ Err(_) => None,
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/enum-drop-access.stderr b/tests/ui/nll/enum-drop-access.stderr
new file mode 100644
index 000000000..a532ae121
--- /dev/null
+++ b/tests/ui/nll/enum-drop-access.stderr
@@ -0,0 +1,31 @@
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/enum-drop-access.rs:13:31
+ |
+LL | fn drop_enum(opt: DropOption<&mut i32>) -> Option<&mut i32> {
+ | - let's call the lifetime of this reference `'1`
+LL | match opt {
+LL | DropOption::Some(&mut ref mut r) => {
+ | ^^^^^^^^^
+LL | Some(r)
+ | ------- returning this value requires that `*opt.0` is borrowed for `'1`
+...
+LL | }
+ | - here, drop of `opt` needs exclusive access to `*opt.0`, because the type `DropOption<&mut i32>` implements the `Drop` trait
+
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/enum-drop-access.rs:22:36
+ |
+LL | fn optional_drop_enum(opt: Option<DropOption<&mut i32>>) -> Option<&mut i32> {
+ | - let's call the lifetime of this reference `'1`
+LL | match opt {
+LL | Some(DropOption::Some(&mut ref mut r)) => {
+ | ^^^^^^^^^
+LL | Some(r)
+ | ------- returning this value requires that `*opt.0.0` is borrowed for `'1`
+...
+LL | }
+ | - here, drop of `opt` needs exclusive access to `*opt.0.0`, because the type `DropOption<&mut i32>` implements the `Drop` trait
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0713`.
diff --git a/tests/ui/nll/extra-unused-mut.rs b/tests/ui/nll/extra-unused-mut.rs
new file mode 100644
index 000000000..340f2952a
--- /dev/null
+++ b/tests/ui/nll/extra-unused-mut.rs
@@ -0,0 +1,66 @@
+// extra unused mut lint tests for #51918
+
+// check-pass
+
+#![feature(generators)]
+#![deny(unused_mut)]
+
+fn ref_argument(ref _y: i32) {}
+
+// #51801
+fn mutable_upvar() {
+ let mut x = 0;
+ move || {
+ x = 1;
+ };
+}
+
+// #50897
+fn generator_mutable_upvar() {
+ let mut x = 0;
+ move || {
+ x = 1;
+ yield;
+ };
+}
+
+// #51830
+fn ref_closure_argument() {
+ let _ = Some(0).as_ref().map(|ref _a| true);
+}
+
+struct Expr {
+ attrs: Vec<u32>,
+}
+
+// #51904
+fn parse_dot_or_call_expr_with(mut attrs: Vec<u32>) {
+ let x = Expr { attrs: vec![] };
+ Some(Some(x)).map(|expr|
+ expr.map(|mut expr| {
+ attrs.push(666);
+ expr.attrs = attrs;
+ expr
+ })
+ );
+}
+
+// Found when trying to bootstrap rustc
+fn if_guard(x: Result<i32, i32>) {
+ match x {
+ Ok(mut r) | Err(mut r) if true => r = 1,
+ _ => (),
+ }
+}
+
+// #59620
+fn nested_closures() {
+ let mut i = 0;
+ [].iter().for_each(|_: &i32| {
+ [].iter().for_each(move |_: &i32| {
+ i += 1;
+ });
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/generator-distinct-lifetime.rs b/tests/ui/nll/generator-distinct-lifetime.rs
new file mode 100644
index 000000000..90fe6b569
--- /dev/null
+++ b/tests/ui/nll/generator-distinct-lifetime.rs
@@ -0,0 +1,25 @@
+#![feature(generators)]
+
+// Test for issue #47189. Here, both `s` and `t` are live for the
+// generator's lifetime, but within the generator they have distinct
+// lifetimes. We accept this code -- even though the borrow extends
+// over a yield -- because the data that is borrowed (`*x`) is not
+// stored on the stack.
+
+// check-pass
+
+fn foo(x: &mut u32) {
+ move || {
+ let s = &mut *x;
+ yield;
+ *s += 1;
+
+ let t = &mut *x;
+ yield;
+ *t += 1;
+ };
+}
+
+fn main() {
+ foo(&mut 0);
+}
diff --git a/tests/ui/nll/generator-upvar-mutability.rs b/tests/ui/nll/generator-upvar-mutability.rs
new file mode 100644
index 000000000..c49ea15b8
--- /dev/null
+++ b/tests/ui/nll/generator-upvar-mutability.rs
@@ -0,0 +1,14 @@
+// Check that generators respect the muatability of their upvars.
+
+#![feature(generators)]
+
+fn mutate_upvar() {
+ let x = 0;
+ move || {
+ x = 1;
+ //~^ ERROR
+ yield;
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/generator-upvar-mutability.stderr b/tests/ui/nll/generator-upvar-mutability.stderr
new file mode 100644
index 000000000..31b061b61
--- /dev/null
+++ b/tests/ui/nll/generator-upvar-mutability.stderr
@@ -0,0 +1,12 @@
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/generator-upvar-mutability.rs:8:9
+ |
+LL | let x = 0;
+ | - help: consider changing this to be mutable: `mut x`
+LL | move || {
+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/nll/get_default.polonius.stderr b/tests/ui/nll/get_default.polonius.stderr
new file mode 100644
index 000000000..476d86cfb
--- /dev/null
+++ b/tests/ui/nll/get_default.polonius.stderr
@@ -0,0 +1,18 @@
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+ --> $DIR/get_default.rs:32:17
+ |
+LL | fn err(map: &mut Map) -> &String {
+ | - let's call the lifetime of this reference `'1`
+LL | loop {
+LL | match map.get() {
+ | --- immutable borrow occurs here
+LL | Some(v) => {
+LL | map.set(String::new()); // Both AST and MIR error here
+ | ^^^ mutable borrow occurs here
+LL |
+LL | return v;
+ | - returning this value requires that `*map` is borrowed for `'1`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/nll/get_default.rs b/tests/ui/nll/get_default.rs
new file mode 100644
index 000000000..ffac8a33d
--- /dev/null
+++ b/tests/ui/nll/get_default.rs
@@ -0,0 +1,44 @@
+// Basic test for free regions in the NLL code. This test ought to
+// report an error due to a reborrowing constraint. Right now, we get
+// a variety of errors from the older, AST-based machinery (notably
+// borrowck), and then we get the NLL error at the end.
+
+struct Map {
+}
+
+impl Map {
+ fn get(&self) -> Option<&String> { None }
+ fn set(&mut self, v: String) { }
+}
+
+fn ok(map: &mut Map) -> &String {
+ loop {
+ match map.get() {
+ Some(v) => {
+ return v;
+ }
+ None => {
+ map.set(String::new()); // Ideally, this would not error.
+ //~^ ERROR borrowed as immutable
+ }
+ }
+ }
+}
+
+fn err(map: &mut Map) -> &String {
+ loop {
+ match map.get() {
+ Some(v) => {
+ map.set(String::new()); // Both AST and MIR error here
+ //~^ ERROR borrowed as immutable
+ return v;
+ }
+ None => {
+ map.set(String::new()); // Ideally, just AST would error here
+ //~^ ERROR borrowed as immutable
+ }
+ }
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/get_default.stderr b/tests/ui/nll/get_default.stderr
new file mode 100644
index 000000000..6998c0433
--- /dev/null
+++ b/tests/ui/nll/get_default.stderr
@@ -0,0 +1,48 @@
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+ --> $DIR/get_default.rs:21:17
+ |
+LL | fn ok(map: &mut Map) -> &String {
+ | - let's call the lifetime of this reference `'1`
+LL | loop {
+LL | match map.get() {
+ | --------- immutable borrow occurs here
+LL | Some(v) => {
+LL | return v;
+ | - returning this value requires that `*map` is borrowed for `'1`
+...
+LL | map.set(String::new()); // Ideally, this would not error.
+ | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+ --> $DIR/get_default.rs:32:17
+ |
+LL | fn err(map: &mut Map) -> &String {
+ | - let's call the lifetime of this reference `'1`
+LL | loop {
+LL | match map.get() {
+ | --------- immutable borrow occurs here
+LL | Some(v) => {
+LL | map.set(String::new()); // Both AST and MIR error here
+ | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL | return v;
+ | - returning this value requires that `*map` is borrowed for `'1`
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+ --> $DIR/get_default.rs:37:17
+ |
+LL | fn err(map: &mut Map) -> &String {
+ | - let's call the lifetime of this reference `'1`
+LL | loop {
+LL | match map.get() {
+ | --------- immutable borrow occurs here
+...
+LL | return v;
+ | - returning this value requires that `*map` is borrowed for `'1`
+...
+LL | map.set(String::new()); // Ideally, just AST would error here
+ | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/nll/guarantor-issue-46974.rs b/tests/ui/nll/guarantor-issue-46974.rs
new file mode 100644
index 000000000..96af4bf5c
--- /dev/null
+++ b/tests/ui/nll/guarantor-issue-46974.rs
@@ -0,0 +1,19 @@
+// Test that NLL analysis propagates lifetimes correctly through
+// field accesses, Box accesses, etc.
+
+fn foo(s: &mut (i32,)) -> i32 {
+ let t = &mut *s; // this borrow should last for the entire function
+ let x = &t.0;
+ *s = (2,); //~ ERROR cannot assign to `*s`
+ *x
+}
+
+fn bar(s: &Box<(i32,)>) -> &'static i32 {
+ // FIXME(#46983): error message should be better
+ &s.0 //~ ERROR lifetime may not live long enough
+}
+
+fn main() {
+ foo(&mut (0,));
+ bar(&Box::new((1,)));
+}
diff --git a/tests/ui/nll/guarantor-issue-46974.stderr b/tests/ui/nll/guarantor-issue-46974.stderr
new file mode 100644
index 000000000..8854dd8d6
--- /dev/null
+++ b/tests/ui/nll/guarantor-issue-46974.stderr
@@ -0,0 +1,23 @@
+error[E0506]: cannot assign to `*s` because it is borrowed
+ --> $DIR/guarantor-issue-46974.rs:7:5
+ |
+LL | let t = &mut *s; // this borrow should last for the entire function
+ | ------- borrow of `*s` occurs here
+LL | let x = &t.0;
+LL | *s = (2,);
+ | ^^^^^^^^^ assignment to borrowed `*s` occurs here
+LL | *x
+ | -- borrow later used here
+
+error: lifetime may not live long enough
+ --> $DIR/guarantor-issue-46974.rs:13:5
+ |
+LL | fn bar(s: &Box<(i32,)>) -> &'static i32 {
+ | - let's call the lifetime of this reference `'1`
+LL | // FIXME(#46983): error message should be better
+LL | &s.0
+ | ^^^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/issue-16223.rs b/tests/ui/nll/issue-16223.rs
new file mode 100644
index 000000000..0ae0ed3d8
--- /dev/null
+++ b/tests/ui/nll/issue-16223.rs
@@ -0,0 +1,52 @@
+// Regression test for #16223: without NLL the `if let` construct together with
+// the nested box-structure of `Root` causes an unwanted collateral move.
+
+// The exact error prevented here is:
+//
+// error[E0382]: use of collaterally moved value: `(root.boxed.rhs as SomeVariant::B).0`
+// --> src/main.rs:55:29
+// |
+// 56 | lhs: SomeVariant::A(a),
+// | - value moved here
+// 57 | rhs: SomeVariant::B(b),
+// | ^ value used here after move
+// |
+// = note: move occurs because the value has type `A`, which does not implement the `Copy` trait
+
+// check-pass
+
+#![feature(box_patterns)]
+
+struct Root {
+ boxed: Box<SetOfVariants>,
+}
+
+struct SetOfVariants {
+ lhs: SomeVariant,
+ rhs: SomeVariant,
+}
+
+enum SomeVariant {
+ A(A),
+ B(B),
+}
+
+struct A(String);
+struct B(String);
+
+fn main() {
+ let root = Root {
+ boxed: Box::new(SetOfVariants {
+ lhs: SomeVariant::A(A(String::from("This is A"))),
+ rhs: SomeVariant::B(B(String::from("This is B"))),
+ }),
+ };
+ if let box SetOfVariants {
+ lhs: SomeVariant::A(a),
+ rhs: SomeVariant::B(b),
+ } = root.boxed
+ {
+ println!("a = {}", a.0);
+ println!("b = {}", b.0);
+ }
+}
diff --git a/tests/ui/nll/issue-21114-ebfull.rs b/tests/ui/nll/issue-21114-ebfull.rs
new file mode 100644
index 000000000..fc4a6845a
--- /dev/null
+++ b/tests/ui/nll/issue-21114-ebfull.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+use std::collections::HashMap;
+use std::sync::Mutex;
+
+fn i_used_to_be_able_to(foo: &Mutex<HashMap<usize, usize>>) -> Vec<(usize, usize)> {
+ let mut foo = foo.lock().unwrap();
+
+ foo.drain().collect()
+}
+
+fn but_after_nightly_update_now_i_gotta(foo: &Mutex<HashMap<usize, usize>>) -> Vec<(usize, usize)> {
+ let mut foo = foo.lock().unwrap();
+
+ return foo.drain().collect();
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-21114-kixunil.rs b/tests/ui/nll/issue-21114-kixunil.rs
new file mode 100644
index 000000000..666f89f35
--- /dev/null
+++ b/tests/ui/nll/issue-21114-kixunil.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+fn from_stdin(min: u64) -> Vec<u64> {
+ use std::io::BufRead;
+
+ let stdin = std::io::stdin();
+ let stdin = stdin.lock();
+
+ stdin.lines()
+ .map(Result::unwrap)
+ .map(|val| val.parse())
+ .map(Result::unwrap)
+ .filter(|val| *val >= min)
+ .collect()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.rs b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
new file mode 100644
index 000000000..46a156d2a
--- /dev/null
+++ b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
@@ -0,0 +1,60 @@
+// This test enumerates various cases of interest where an ADT or tuple is
+// partially initialized and then used in some way that is wrong *even*
+// after rust-lang/rust#54987 is implemented.
+//
+// See rust-lang/rust#21232, rust-lang/rust#54986, and rust-lang/rust#54987.
+//
+// See issue-21232-partial-init-and-use.rs for cases of tests that are
+// meant to compile and run successfully once rust-lang/rust#54987 is
+// implemented.
+
+struct D {
+ x: u32,
+ s: S,
+}
+
+struct S {
+ y: u32,
+ z: u32,
+}
+
+
+impl Drop for D {
+ fn drop(&mut self) { }
+}
+
+fn cannot_partially_init_adt_with_drop() {
+ let d: D;
+ d.x = 10; //~ ERROR E0381
+}
+
+fn cannot_partially_init_mutable_adt_with_drop() {
+ let mut d: D;
+ d.x = 10; //~ ERROR E0381
+}
+
+fn cannot_partially_reinit_adt_with_drop() {
+ let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
+ drop(d);
+ d.x = 10;
+ //~^ ERROR assign of moved value: `d` [E0382]
+}
+
+fn cannot_partially_init_inner_adt_via_outer_with_drop() {
+ let d: D;
+ d.s.y = 20; //~ ERROR E0381
+}
+
+fn cannot_partially_init_inner_adt_via_mutable_outer_with_drop() {
+ let mut d: D;
+ d.s.y = 20; //~ ERROR E0381
+}
+
+fn cannot_partially_reinit_inner_adt_via_outer_with_drop() {
+ let mut d = D { x: 0, s: S{ y: 0, z: 0} };
+ drop(d);
+ d.s.y = 20;
+ //~^ ERROR assign to part of moved value: `d` [E0382]
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
new file mode 100644
index 000000000..63f230be7
--- /dev/null
+++ b/tests/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
@@ -0,0 +1,64 @@
+error[E0381]: assigned binding `d` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5
+ |
+LL | let d: D;
+ | - binding declared here but left uninitialized
+LL | d.x = 10;
+ | ^^^^^^^^ `d` 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]: assigned binding `d` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:33:5
+ |
+LL | let mut d: D;
+ | ----- binding declared here but left uninitialized
+LL | d.x = 10;
+ | ^^^^^^^^ `d` 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[E0382]: assign of moved value: `d`
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:39:5
+ |
+LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
+ | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
+LL | drop(d);
+ | - value moved here
+LL | d.x = 10;
+ | ^^^^^^^^ value assigned here after move
+
+error[E0381]: partially assigned binding `d` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5
+ |
+LL | let d: D;
+ | - binding declared here but left uninitialized
+LL | d.s.y = 20;
+ | ^^^^^^^^^^ `d.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 `d` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:50:5
+ |
+LL | let mut d: D;
+ | ----- binding declared here but left uninitialized
+LL | d.s.y = 20;
+ | ^^^^^^^^^^ `d.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[E0382]: assign to part of moved value: `d`
+ --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:56:5
+ |
+LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} };
+ | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
+LL | drop(d);
+ | - value moved here
+LL | d.s.y = 20;
+ | ^^^^^^^^^^ value partially assigned here after move
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0381, E0382.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.rs b/tests/ui/nll/issue-21232-partial-init-and-use.rs
new file mode 100644
index 000000000..ad3eb2483
--- /dev/null
+++ b/tests/ui/nll/issue-21232-partial-init-and-use.rs
@@ -0,0 +1,297 @@
+// This test enumerates various cases of interest for partial
+// [re]initialization of ADTs and tuples.
+//
+// See rust-lang/rust#21232, rust-lang/rust#54986, and rust-lang/rust#54987.
+//
+// All of tests in this file are expected to change from being
+// rejected, at least under NLL (by rust-lang/rust#54986) to being
+// **accepted** when rust-lang/rust#54987 is implemented.
+// (That's why there are assertions in the code.)
+//
+// See issue-21232-partial-init-and-erroneous-use.rs for cases of
+// tests that are meant to continue failing to compile once
+// rust-lang/rust#54987 is implemented.
+
+struct S<Y> {
+ x: u32,
+
+ // Note that even though `y` may implement `Drop`, under #54987 we
+ // will still allow partial initialization of `S` itself.
+ y: Y,
+}
+
+enum Void { }
+
+type B = Box<u32>;
+
+impl S<B> { fn new() -> Self { S { x: 0, y: Box::new(0) } } }
+
+fn borrow_s(s: &S<B>) { assert_eq!(s.x, 10); assert_eq!(*s.y, 20); }
+fn move_s(s: S<B>) { assert_eq!(s.x, 10); assert_eq!(*s.y, 20); }
+fn borrow_field(x: &u32) { assert_eq!(*x, 10); }
+
+type T = (u32, B);
+type Tvoid = (u32, Void);
+
+fn borrow_t(t: &T) { assert_eq!(t.0, 10); assert_eq!(*t.1, 20); }
+fn move_t(t: T) { assert_eq!(t.0, 10); assert_eq!(*t.1, 20); }
+
+struct Q<F> {
+ v: u32,
+ r: R<F>,
+}
+
+struct R<F> {
+ w: u32,
+ f: F,
+}
+
+impl<F> Q<F> { fn new(f: F) -> Self { Q { v: 0, r: R::new(f) } } }
+impl<F> R<F> { fn new(f: F) -> Self { R { w: 0, f } } }
+
+// Axes to cover:
+// * local/field: Is the structure in a local or a field
+// * fully/partial/void: Are we fully initializing it before using any part?
+// Is whole type empty due to a void component?
+// * init/reinit: First initialization, or did we previously initialize and then move out?
+// * struct/tuple: Is this a struct or a (X, Y).
+//
+// As a shorthand for the cases above, adding a numeric summary to
+// each test's fn name to denote each point on each axis.
+//
+// e.g., 1000 = field fully init struct; 0211 = local void reinit tuple
+
+// It got pretty monotonous writing the same code over and over, and I
+// feared I would forget details. So I abstracted some desiderata into
+// macros. But I left the initialization code inline, because that's
+// where the errors for #54986 will be emitted.
+
+macro_rules! use_fully {
+ (struct $s:expr) => { {
+ borrow_field(& $s.x );
+ borrow_s(& $s );
+ move_s( $s );
+ } };
+
+ (tuple $t:expr) => { {
+ borrow_field(& $t.0 );
+ borrow_t(& $t );
+ move_t( $t );
+ } }
+}
+
+macro_rules! use_part {
+ (struct $s:expr) => { {
+ borrow_field(& $s.x );
+ match $s { S { ref x, y: _ } => { borrow_field(x); } }
+ } };
+
+ (tuple $t:expr) => { {
+ borrow_field(& $t.0 );
+ match $t { (ref x, _) => { borrow_field(x); } }
+ } }
+}
+
+fn test_0000_local_fully_init_and_use_struct() {
+ let s: S<B>;
+ s.x = 10; s.y = Box::new(20); //~ ERROR E0381
+ use_fully!(struct s);
+}
+
+fn test_0001_local_fully_init_and_use_tuple() {
+ let t: T;
+ t.0 = 10; t.1 = Box::new(20); //~ ERROR E0381
+ use_fully!(tuple t);
+}
+
+fn test_0010_local_fully_reinit_and_use_struct() {
+ let mut s: S<B> = S::new(); drop(s);
+ s.x = 10; s.y = Box::new(20);
+ //~^ ERROR assign to part of moved value: `s` [E0382]
+ use_fully!(struct s);
+}
+
+fn test_0011_local_fully_reinit_and_use_tuple() {
+ let mut t: T = (0, Box::new(0)); drop(t);
+ t.0 = 10; t.1 = Box::new(20);
+ //~^ ERROR assign to part of moved value: `t` [E0382]
+ use_fully!(tuple t);
+}
+
+fn test_0100_local_partial_init_and_use_struct() {
+ let s: S<B>;
+ s.x = 10; //~ ERROR E0381
+ use_part!(struct s);
+}
+
+fn test_0101_local_partial_init_and_use_tuple() {
+ let t: T;
+ t.0 = 10; //~ ERROR E0381
+ use_part!(tuple t);
+}
+
+fn test_0110_local_partial_reinit_and_use_struct() {
+ let mut s: S<B> = S::new(); drop(s);
+ s.x = 10;
+ //~^ ERROR assign to part of moved value: `s` [E0382]
+ use_part!(struct s);
+}
+
+fn test_0111_local_partial_reinit_and_use_tuple() {
+ let mut t: T = (0, Box::new(0)); drop(t);
+ t.0 = 10;
+ //~^ ERROR assign to part of moved value: `t` [E0382]
+ use_part!(tuple t);
+}
+
+fn test_0200_local_void_init_and_use_struct() {
+ let s: S<Void>;
+ s.x = 10; //~ ERROR E0381
+ use_part!(struct s);
+}
+
+fn test_0201_local_void_init_and_use_tuple() {
+ let t: Tvoid;
+ t.0 = 10; //~ ERROR E0381
+ use_part!(tuple t);
+}
+
+// NOTE: uniform structure of tests here makes n21n (aka combining
+// Void with Reinit) an (even more) senseless case, as we cannot
+// safely create initial instance containing Void to move out of and
+// then reinitialize. While I was tempted to sidestep this via some
+// unsafe code (eek), lets just instead not encode such tests.
+
+// fn test_0210_local_void_reinit_and_use_struct() { unimplemented!() }
+// fn test_0211_local_void_reinit_and_use_tuple() { unimplemented!() }
+
+fn test_1000_field_fully_init_and_use_struct() {
+ let q: Q<S<B>>;
+ q.r.f.x = 10; q.r.f.y = Box::new(20); //~ ERROR E0381
+ use_fully!(struct q.r.f);
+}
+
+fn test_1001_field_fully_init_and_use_tuple() {
+ let q: Q<T>;
+ q.r.f.0 = 10; q.r.f.1 = Box::new(20); //~ ERROR E0381
+ use_fully!(tuple q.r.f);
+}
+
+fn test_1010_field_fully_reinit_and_use_struct() {
+ let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+ q.r.f.x = 10; q.r.f.y = Box::new(20);
+ //~^ ERROR assign to part of moved value: `q.r` [E0382]
+ use_fully!(struct q.r.f);
+}
+
+fn test_1011_field_fully_reinit_and_use_tuple() {
+ let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+ q.r.f.0 = 10; q.r.f.1 = Box::new(20);
+ //~^ ERROR assign to part of moved value: `q.r` [E0382]
+ use_fully!(tuple q.r.f);
+}
+
+fn test_1100_field_partial_init_and_use_struct() {
+ let q: Q<S<B>>;
+ q.r.f.x = 10; //~ ERROR E0381
+ use_part!(struct q.r.f);
+}
+
+fn test_1101_field_partial_init_and_use_tuple() {
+ let q: Q<T>;
+ q.r.f.0 = 10; //~ ERROR E0381
+ use_part!(tuple q.r.f);
+}
+
+fn test_1110_field_partial_reinit_and_use_struct() {
+ let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+ q.r.f.x = 10;
+ //~^ ERROR assign to part of moved value: `q.r` [E0382]
+ use_part!(struct q.r.f);
+}
+
+fn test_1111_field_partial_reinit_and_use_tuple() {
+ let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+ q.r.f.0 = 10;
+ //~^ ERROR assign to part of moved value: `q.r` [E0382]
+ use_part!(tuple q.r.f);
+}
+
+fn test_1200_field_void_init_and_use_struct() {
+ let mut q: Q<S<Void>>;
+ q.r.f.x = 10; //~ ERROR E0381
+ use_part!(struct q.r.f);
+}
+
+fn test_1201_field_void_init_and_use_tuple() {
+ let mut q: Q<Tvoid>;
+ q.r.f.0 = 10; //~ ERROR E0381
+ use_part!(tuple q.r.f);
+}
+
+// See NOTE abve.
+
+// fn test_1210_field_void_reinit_and_use_struct() { unimplemented!() }
+// fn test_1211_field_void_reinit_and_use_tuple() { unimplemented!() }
+
+// The below are some additional cases of interest that have been
+// transcribed from other bugs based on old erroneous codegen when we
+// encountered partial writes.
+
+fn issue_26996() {
+ let mut c = (1, "".to_owned());
+ match c {
+ c2 => {
+ c.0 = 2; //~ ERROR assign to part of moved value
+ assert_eq!(c2.0, 1);
+ }
+ }
+}
+
+fn issue_27021() {
+ let mut c = (1, (1, "".to_owned()));
+ match c {
+ c2 => {
+ (c.1).0 = 2; //~ ERROR assign to part of moved value
+ assert_eq!((c2.1).0, 1);
+ }
+ }
+
+ let mut c = (1, (1, (1, "".to_owned())));
+ match c.1 {
+ c2 => {
+ ((c.1).1).0 = 3; //~ ERROR assign to part of moved value
+ assert_eq!((c2.1).0, 1);
+ }
+ }
+}
+
+fn main() {
+ test_0000_local_fully_init_and_use_struct();
+ test_0001_local_fully_init_and_use_tuple();
+ test_0010_local_fully_reinit_and_use_struct();
+ test_0011_local_fully_reinit_and_use_tuple();
+ test_0100_local_partial_init_and_use_struct();
+ test_0101_local_partial_init_and_use_tuple();
+ test_0110_local_partial_reinit_and_use_struct();
+ test_0111_local_partial_reinit_and_use_tuple();
+ test_0200_local_void_init_and_use_struct();
+ test_0201_local_void_init_and_use_tuple();
+ // test_0210_local_void_reinit_and_use_struct();
+ // test_0211_local_void_reinit_and_use_tuple();
+ test_1000_field_fully_init_and_use_struct();
+ test_1001_field_fully_init_and_use_tuple();
+ test_1010_field_fully_reinit_and_use_struct();
+ test_1011_field_fully_reinit_and_use_tuple();
+ test_1100_field_partial_init_and_use_struct();
+ test_1101_field_partial_init_and_use_tuple();
+ test_1110_field_partial_reinit_and_use_struct();
+ test_1111_field_partial_reinit_and_use_tuple();
+ test_1200_field_void_init_and_use_struct();
+ test_1201_field_void_init_and_use_tuple();
+ // test_1210_field_void_reinit_and_use_struct();
+ // test_1211_field_void_reinit_and_use_tuple();
+
+ issue_26996();
+ issue_27021();
+}
diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
new file mode 100644
index 000000000..97ed414b1
--- /dev/null
+++ b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -0,0 +1,260 @@
+error[E0381]: partially assigned binding `s` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:97:5
+ |
+LL | let s: S<B>;
+ | - binding declared here but left uninitialized
+LL | s.x = 10; s.y = Box::new(20);
+ | ^^^^^^^^ `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 `t` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:103:5
+ |
+LL | let t: T;
+ | - binding declared here but left uninitialized
+LL | t.0 = 10; t.1 = Box::new(20);
+ | ^^^^^^^^ `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[E0382]: assign to part of moved value: `s`
+ --> $DIR/issue-21232-partial-init-and-use.rs:109:5
+ |
+LL | let mut s: S<B> = S::new(); drop(s);
+ | ----- - value moved here
+ | |
+ | move occurs because `s` has type `S<Box<u32>>`, which does not implement the `Copy` trait
+LL | s.x = 10; s.y = Box::new(20);
+ | ^^^^^^^^ value partially assigned here after move
+
+error[E0382]: assign to part of moved value: `t`
+ --> $DIR/issue-21232-partial-init-and-use.rs:116:5
+ |
+LL | let mut t: T = (0, Box::new(0)); drop(t);
+ | ----- - value moved here
+ | |
+ | move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait
+LL | t.0 = 10; t.1 = Box::new(20);
+ | ^^^^^^^^ value partially assigned here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | let mut t: T = (0, Box::new(0)); drop(t.clone());
+ | ++++++++
+
+error[E0381]: partially assigned binding `s` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:123:5
+ |
+LL | let s: S<B>;
+ | - binding declared here but left uninitialized
+LL | s.x = 10;
+ | ^^^^^^^^ `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 `t` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:129:5
+ |
+LL | let t: T;
+ | - binding declared here but left uninitialized
+LL | t.0 = 10;
+ | ^^^^^^^^ `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[E0382]: assign to part of moved value: `s`
+ --> $DIR/issue-21232-partial-init-and-use.rs:135:5
+ |
+LL | let mut s: S<B> = S::new(); drop(s);
+ | ----- - value moved here
+ | |
+ | move occurs because `s` has type `S<Box<u32>>`, which does not implement the `Copy` trait
+LL | s.x = 10;
+ | ^^^^^^^^ value partially assigned here after move
+
+error[E0382]: assign to part of moved value: `t`
+ --> $DIR/issue-21232-partial-init-and-use.rs:142:5
+ |
+LL | let mut t: T = (0, Box::new(0)); drop(t);
+ | ----- - value moved here
+ | |
+ | move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait
+LL | t.0 = 10;
+ | ^^^^^^^^ value partially assigned here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | let mut t: T = (0, Box::new(0)); drop(t.clone());
+ | ++++++++
+
+error[E0381]: partially assigned binding `s` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:149:5
+ |
+LL | let s: S<Void>;
+ | - binding declared here but left uninitialized
+LL | s.x = 10;
+ | ^^^^^^^^ `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 `t` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:155:5
+ |
+LL | let t: Tvoid;
+ | - binding declared here but left uninitialized
+LL | t.0 = 10;
+ | ^^^^^^^^ `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 `q` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:170:5
+ |
+LL | let q: Q<S<B>>;
+ | - binding declared here but left uninitialized
+LL | q.r.f.x = 10; q.r.f.y = Box::new(20);
+ | ^^^^^^^^^^^^ `q.r.f` 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 `q` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:176:5
+ |
+LL | let q: Q<T>;
+ | - binding declared here but left uninitialized
+LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20);
+ | ^^^^^^^^^^^^ `q.r.f` 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[E0382]: assign to part of moved value: `q.r`
+ --> $DIR/issue-21232-partial-init-and-use.rs:182:5
+ |
+LL | let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+ | --- value moved here
+LL | q.r.f.x = 10; q.r.f.y = Box::new(20);
+ | ^^^^^^^^^^^^ value partially assigned here after move
+ |
+ = note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `q.r`
+ --> $DIR/issue-21232-partial-init-and-use.rs:189:5
+ |
+LL | let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+ | --- value moved here
+LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20);
+ | ^^^^^^^^^^^^ value partially assigned here after move
+ |
+ = note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait
+
+error[E0381]: partially assigned binding `q` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:196:5
+ |
+LL | let q: Q<S<B>>;
+ | - binding declared here but left uninitialized
+LL | q.r.f.x = 10;
+ | ^^^^^^^^^^^^ `q.r.f` 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 `q` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:202:5
+ |
+LL | let q: Q<T>;
+ | - binding declared here but left uninitialized
+LL | q.r.f.0 = 10;
+ | ^^^^^^^^^^^^ `q.r.f` 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[E0382]: assign to part of moved value: `q.r`
+ --> $DIR/issue-21232-partial-init-and-use.rs:208:5
+ |
+LL | let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+ | --- value moved here
+LL | q.r.f.x = 10;
+ | ^^^^^^^^^^^^ value partially assigned here after move
+ |
+ = note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `q.r`
+ --> $DIR/issue-21232-partial-init-and-use.rs:215:5
+ |
+LL | let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+ | --- value moved here
+LL | q.r.f.0 = 10;
+ | ^^^^^^^^^^^^ value partially assigned here after move
+ |
+ = note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait
+
+error[E0381]: partially assigned binding `q` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:222:5
+ |
+LL | let mut q: Q<S<Void>>;
+ | ----- binding declared here but left uninitialized
+LL | q.r.f.x = 10;
+ | ^^^^^^^^^^^^ `q.r.f` 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 `q` isn't fully initialized
+ --> $DIR/issue-21232-partial-init-and-use.rs:228:5
+ |
+LL | let mut q: Q<Tvoid>;
+ | ----- binding declared here but left uninitialized
+LL | q.r.f.0 = 10;
+ | ^^^^^^^^^^^^ `q.r.f` 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[E0382]: assign to part of moved value: `c`
+ --> $DIR/issue-21232-partial-init-and-use.rs:245:13
+ |
+LL | let mut c = (1, "".to_owned());
+ | ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait
+LL | match c {
+LL | c2 => {
+ | -- value moved here
+LL | c.0 = 2;
+ | ^^^^^^^ value partially assigned here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref c2 => {
+ | +++
+
+error[E0382]: assign to part of moved value: `c`
+ --> $DIR/issue-21232-partial-init-and-use.rs:255:13
+ |
+LL | let mut c = (1, (1, "".to_owned()));
+ | ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait
+LL | match c {
+LL | c2 => {
+ | -- value moved here
+LL | (c.1).0 = 2;
+ | ^^^^^^^^^^^ value partially assigned here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref c2 => {
+ | +++
+
+error[E0382]: assign to part of moved value: `c.1`
+ --> $DIR/issue-21232-partial-init-and-use.rs:263:13
+ |
+LL | c2 => {
+ | -- value moved here
+LL | ((c.1).1).0 = 3;
+ | ^^^^^^^^^^^^^^^ value partially assigned here after move
+ |
+ = note: move occurs because `c.1` has type `(i32, (i32, String))`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref c2 => {
+ | +++
+
+error: aborting due to 23 previous errors
+
+Some errors have detailed explanations: E0381, E0382.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/nll/issue-22323-temp-destruction.rs b/tests/ui/nll/issue-22323-temp-destruction.rs
new file mode 100644
index 000000000..3f2ece1cf
--- /dev/null
+++ b/tests/ui/nll/issue-22323-temp-destruction.rs
@@ -0,0 +1,30 @@
+// rust-lang/rust#22323: regression test demonstrating that NLL
+// precisely tracks temporary destruction order.
+
+// check-pass
+
+fn main() {
+ let _s = construct().borrow().consume_borrowed();
+}
+
+fn construct() -> Value { Value }
+
+pub struct Value;
+
+impl Value {
+ fn borrow<'a>(&'a self) -> Borrowed<'a> { unimplemented!() }
+}
+
+pub struct Borrowed<'a> {
+ _inner: Guard<'a, Value>,
+}
+
+impl<'a> Borrowed<'a> {
+ fn consume_borrowed(self) -> String { unimplemented!() }
+}
+
+pub struct Guard<'a, T: ?Sized + 'a> {
+ _lock: &'a T,
+}
+
+impl<'a, T: ?Sized> Drop for Guard<'a, T> { fn drop(&mut self) {} }
diff --git a/tests/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs b/tests/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
new file mode 100644
index 000000000..ccfc8937f
--- /dev/null
+++ b/tests/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
@@ -0,0 +1,63 @@
+// run-pass
+// This test illustrates that under NLL, we can remove our overly
+// conservative approach for disallowing mutations of match inputs.
+
+// See further discussion on rust-lang/rust#24535,
+// rust-lang/rfcs#1006, and rust-lang/rfcs#107
+
+#![feature(if_let_guard)]
+
+fn main() {
+ rust_issue_24535();
+ rfcs_issue_1006_1();
+ rfcs_issue_1006_2();
+}
+
+fn rust_issue_24535() {
+ fn compare(a: &u8, b: &mut u8) -> bool {
+ a == b
+ }
+
+ let a = 3u8;
+
+ match a {
+ 0 => panic!("nope"),
+ 3 if compare(&a, &mut 3) => (),
+ _ => panic!("nope"),
+ }
+
+ match a {
+ 0 => panic!("nope"),
+ 3 if let true = compare(&a, &mut 3) => (),
+ _ => panic!("nope"),
+ }
+}
+
+fn rfcs_issue_1006_1() {
+ let v = vec!["1".to_string(), "2".to_string(), "3".to_string()];
+ match Some(&v) {
+ Some(iv) if iv.iter().any(|x| &x[..]=="2") => true,
+ _ => panic!("nope"),
+ };
+}
+
+fn rfcs_issue_1006_2() {
+ #[inline(always)]
+ fn check<'a, I: Iterator<Item=&'a i32>>(mut i: I) -> bool {
+ i.any(|&x| x == 2)
+ }
+
+ let slice = [1, 2, 3];
+
+ match 42 {
+ _ if slice.iter().any(|&x| x == 2) => { true },
+ _ => { panic!("nope"); }
+ };
+
+ // (This match is just illustrating how easy it was to circumvent
+ // the checking performed for the previous `match`.)
+ match 42 {
+ _ if check(slice.iter()) => { true },
+ _ => { panic!("nope"); }
+ };
+}
diff --git a/tests/ui/nll/issue-27282-move-match-input-into-guard.rs b/tests/ui/nll/issue-27282-move-match-input-into-guard.rs
new file mode 100644
index 000000000..85feda582
--- /dev/null
+++ b/tests/ui/nll/issue-27282-move-match-input-into-guard.rs
@@ -0,0 +1,34 @@
+// Issue 27282: Example 2: This sidesteps the AST checks disallowing
+// mutable borrows in match guards by hiding the mutable borrow in a
+// guard behind a move (of the mutably borrowed match input) within a
+// closure.
+//
+// This example is not rejected by AST borrowck (and then reliably
+// reaches the panic code when executed, despite the compiler warning
+// about that match arm being unreachable.
+
+#![feature(if_let_guard)]
+
+fn main() {
+ let b = &mut true;
+ match b {
+ //~^ ERROR use of moved value: `b` [E0382]
+ &mut false => {},
+ _ if { (|| { let bar = b; *bar = false; })();
+ false } => { },
+ &mut true => { println!("You might think we should get here"); },
+ _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
+ }
+
+ let b = &mut true;
+ match b {
+ //~^ ERROR use of moved value: `b` [E0382]
+ &mut false => {}
+ _ if let Some(()) = {
+ (|| { let bar = b; *bar = false; })();
+ None
+ } => {}
+ &mut true => {}
+ _ => {}
+ }
+}
diff --git a/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr b/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr
new file mode 100644
index 000000000..ae7978004
--- /dev/null
+++ b/tests/ui/nll/issue-27282-move-match-input-into-guard.stderr
@@ -0,0 +1,29 @@
+error[E0382]: use of moved value: `b`
+ --> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
+ |
+LL | let b = &mut true;
+ | - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL | match b {
+ | ^^^^^^^ value used here after move
+...
+LL | _ if { (|| { let bar = b; *bar = false; })();
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+
+error[E0382]: use of moved value: `b`
+ --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
+ |
+LL | let b = &mut true;
+ | - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL | match b {
+ | ^^^^^^^ value used here after move
+...
+LL | (|| { let bar = b; *bar = false; })();
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs
new file mode 100644
index 000000000..833ca8afd
--- /dev/null
+++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs
@@ -0,0 +1,23 @@
+// Issue 27282: Example 1: This sidesteps the AST checks disallowing
+// mutable borrows in match guards by hiding the mutable borrow in a
+// guard behind a move (of the ref mut pattern id) within a closure.
+
+#![feature(if_let_guard)]
+
+fn main() {
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if { (|| { let bar = foo; bar.take() })(); false } => {},
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ Some(s) => std::process::exit(*s),
+ }
+}
diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
new file mode 100644
index 000000000..45119018d
--- /dev/null
+++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
@@ -0,0 +1,23 @@
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
+ |
+LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
+ |
+LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.rs b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.rs
new file mode 100644
index 000000000..d17d6f07f
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.rs
@@ -0,0 +1,31 @@
+// This is testing an attempt to corrupt the discriminant of the match
+// arm in a guard, followed by an attempt to continue matching on that
+// corrupted discriminant in the remaining match arms.
+//
+// Basically this is testing that our new NLL feature of emitting a
+// fake read on each match arm is catching cases like this.
+//
+// This case is interesting because it includes a guard that
+// diverges, and therefore a single final fake-read at the very end
+// after the final match arm would not suffice.
+
+struct ForceFnOnce;
+
+fn main() {
+ let mut x = &mut Some(&2);
+ let force_fn_once = ForceFnOnce;
+ match x {
+ &mut None => panic!("unreachable"),
+ &mut Some(&_) if {
+ // ForceFnOnce needed to exploit #27282
+ (|| { *x = None; drop(force_fn_once); })();
+ //~^ ERROR cannot mutably borrow `x` in match guard [E0510]
+ false
+ } => {}
+ &mut Some(&a) if { // this binds to garbage if we've corrupted discriminant
+ println!("{}", a);
+ panic!()
+ } => {}
+ _ => panic!("unreachable"),
+ }
+}
diff --git a/tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.stderr b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.stderr
new file mode 100644
index 000000000..a1f973e0f
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-1.stderr
@@ -0,0 +1,14 @@
+error[E0510]: cannot mutably borrow `x` in match guard
+ --> $DIR/issue-27282-mutate-before-diverging-arm-1.rs:21:14
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | (|| { *x = None; drop(force_fn_once); })();
+ | ^^ -- borrow occurs due to use of `x` in closure
+ | |
+ | cannot mutably borrow
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0510`.
diff --git a/tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.rs b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.rs
new file mode 100644
index 000000000..9c3e7e997
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.rs
@@ -0,0 +1,40 @@
+// This is testing an attempt to corrupt the discriminant of the match
+// arm in a guard, followed by an attempt to continue matching on that
+// corrupted discriminant in the remaining match arms.
+//
+// Basically this is testing that our new NLL feature of emitting a
+// fake read on each match arm is catching cases like this.
+//
+// This case is interesting because it includes a guard that
+// diverges, and therefore a single final fake-read at the very end
+// after the final match arm would not suffice.
+//
+// It is also interesting because the access to the corrupted data
+// occurs in the pattern-match itself, and not in the guard
+// expression.
+
+struct ForceFnOnce;
+
+fn main() {
+ let mut x = &mut Some(&2);
+ let force_fn_once = ForceFnOnce;
+ match x {
+ &mut None => panic!("unreachable"),
+ &mut Some(&_)
+ if {
+ // ForceFnOnce needed to exploit #27282
+ (|| { *x = None; drop(force_fn_once); })();
+ //~^ ERROR cannot mutably borrow `x` in match guard [E0510]
+ false
+ } => {}
+
+ // this segfaults if we corrupted the discriminant, because
+ // the compiler gets to *assume* that it cannot be the `None`
+ // case, even though that was the effect of the guard.
+ &mut Some(&2)
+ if {
+ panic!()
+ } => {}
+ _ => panic!("unreachable"),
+ }
+}
diff --git a/tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.stderr b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.stderr
new file mode 100644
index 000000000..dd46308d1
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-2.stderr
@@ -0,0 +1,14 @@
+error[E0510]: cannot mutably borrow `x` in match guard
+ --> $DIR/issue-27282-mutate-before-diverging-arm-2.rs:26:18
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | (|| { *x = None; drop(force_fn_once); })();
+ | ^^ -- borrow occurs due to use of `x` in closure
+ | |
+ | cannot mutably borrow
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0510`.
diff --git a/tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.rs b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.rs
new file mode 100644
index 000000000..cff9e963e
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.rs
@@ -0,0 +1,30 @@
+// This is testing an attempt to corrupt the discriminant of the match
+// arm in a guard, followed by an attempt to continue matching on that
+// corrupted discriminant in the remaining match arms.
+//
+// Basically this is testing that our new NLL feature of emitting a
+// fake read on each match arm is catching cases like this.
+//
+// This case is interesting because a borrow of **x is untracked, because **x is
+// immutable. However, for matches we care that **x refers to the same value
+// until we have chosen a match arm.
+
+struct ForceFnOnce;
+fn main() {
+ let mut x = &mut &Some(&2);
+ let force_fn_once = ForceFnOnce;
+ match **x {
+ None => panic!("unreachable"),
+ Some(&_) if {
+ // ForceFnOnce needed to exploit #27282
+ (|| { *x = &None; drop(force_fn_once); })();
+ //~^ ERROR cannot mutably borrow `x` in match guard [E0510]
+ false
+ } => {}
+ Some(&a) if { // this binds to garbage if we've corrupted discriminant
+ println!("{}", a);
+ panic!()
+ } => {}
+ _ => panic!("unreachable"),
+ }
+}
diff --git a/tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.stderr b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.stderr
new file mode 100644
index 000000000..4a4a25790
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutate-before-diverging-arm-3.stderr
@@ -0,0 +1,14 @@
+error[E0510]: cannot mutably borrow `x` in match guard
+ --> $DIR/issue-27282-mutate-before-diverging-arm-3.rs:20:14
+ |
+LL | match **x {
+ | --- value is immutable in match guard
+...
+LL | (|| { *x = &None; drop(force_fn_once); })();
+ | ^^ -- borrow occurs due to use of `x` in closure
+ | |
+ | cannot mutably borrow
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0510`.
diff --git a/tests/ui/nll/issue-27282-mutation-in-guard.rs b/tests/ui/nll/issue-27282-mutation-in-guard.rs
new file mode 100644
index 000000000..4f41fc23f
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutation-in-guard.rs
@@ -0,0 +1,26 @@
+#![feature(if_let_guard)]
+
+fn main() {
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard
+ false
+ } => {},
+ Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
+ _ => println!("Here is some supposedly unreachable code."),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if let Some(()) = {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard
+ None
+ } => {},
+ Some(_) => {},
+ }
+}
diff --git a/tests/ui/nll/issue-27282-mutation-in-guard.stderr b/tests/ui/nll/issue-27282-mutation-in-guard.stderr
new file mode 100644
index 000000000..1ba696593
--- /dev/null
+++ b/tests/ui/nll/issue-27282-mutation-in-guard.stderr
@@ -0,0 +1,23 @@
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-mutation-in-guard.rs:8:18
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-mutation-in-guard.rs:20:18
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs b/tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
new file mode 100644
index 000000000..ac06b2b01
--- /dev/null
+++ b/tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
@@ -0,0 +1,30 @@
+// Issue 27282: This is a variation on issue-27282-move-ref-mut-into-guard.rs
+//
+// It reborrows instead of moving the `ref mut` pattern borrow. This
+// means that our conservative check for mutation in guards will
+// reject it. But I want to make sure that we continue to reject it
+// (under NLL) even when that conservative check goes away.
+
+#![feature(if_let_guard)]
+
+fn main() {
+ let mut b = &mut true;
+ match b {
+ &mut false => {},
+ ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
+ //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ false } => { &mut *r; },
+ &mut true => { println!("You might think we should get here"); },
+ _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
+ }
+
+ let mut b = &mut true;
+ match b {
+ &mut false => {},
+ ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+ //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ None } => { &mut *r; },
+ &mut true => {},
+ _ => {},
+ }
+}
diff --git a/tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr b/tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
new file mode 100644
index 000000000..5eb7a25bf
--- /dev/null
+++ b/tests/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
@@ -0,0 +1,23 @@
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
+ |
+LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
+ | ^^ -- mutable borrow occurs due to use of `r` in closure
+ | |
+ | cannot borrow as mutable
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:24:40
+ |
+LL | ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+ | ^^ -- mutable borrow occurs due to use of `r` in closure
+ | |
+ | cannot borrow as mutable
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/nll/issue-27868.rs b/tests/ui/nll/issue-27868.rs
new file mode 100644
index 000000000..e436b22db
--- /dev/null
+++ b/tests/ui/nll/issue-27868.rs
@@ -0,0 +1,28 @@
+// Regression test for issue #27868
+
+use std::ops::AddAssign;
+
+struct MyVec<T>(Vec<T>);
+
+impl <T> Drop for MyVec<T> {
+ fn drop(&mut self) {
+ println!("Being dropped.");
+ }
+}
+
+impl<T> AddAssign<T> for MyVec<T> {
+ fn add_assign(&mut self, _elem: T) {
+ println!("In add_assign.");
+ }
+}
+
+fn main() {
+ let mut vec = MyVec(vec![0]);
+ let mut vecvec = vec![vec];
+
+ vecvec[0] += {
+ vecvec = vec![];
+ //~^ ERROR cannot assign to `vecvec` because it is borrowed [E0506]
+ 0
+ };
+}
diff --git a/tests/ui/nll/issue-27868.stderr b/tests/ui/nll/issue-27868.stderr
new file mode 100644
index 000000000..e0b3b5494
--- /dev/null
+++ b/tests/ui/nll/issue-27868.stderr
@@ -0,0 +1,18 @@
+error[E0506]: cannot assign to `vecvec` because it is borrowed
+ --> $DIR/issue-27868.rs:24:9
+ |
+LL | vecvec[0] += {
+ | ------
+ | |
+ | _____borrow of `vecvec` occurs here
+ | |
+LL | | vecvec = vec![];
+ | | ^^^^^^ assignment to borrowed `vecvec` occurs here
+LL | |
+LL | | 0
+LL | | };
+ | |_____- 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/nll/issue-30104.rs b/tests/ui/nll/issue-30104.rs
new file mode 100644
index 000000000..38850cd3f
--- /dev/null
+++ b/tests/ui/nll/issue-30104.rs
@@ -0,0 +1,40 @@
+// Regression test for #30104
+
+// check-pass
+
+use std::ops::{Deref, DerefMut};
+
+fn box_two_field(v: &mut Box<(i32, i32)>) {
+ let _a = &mut v.0;
+ let _b = &mut v.1;
+}
+
+fn box_destructure(v: &mut Box<(i32, i32)>) {
+ let (ref mut _head, ref mut _tail) = **v;
+}
+
+struct Wrap<T>(T);
+
+impl<T> Deref for Wrap<T> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<T> DerefMut for Wrap<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ &mut self.0
+ }
+}
+
+fn smart_two_field(v: &mut Wrap<(i32, i32)>) {
+ let _a = &mut v.0;
+ let _b = &mut v.1;
+}
+
+fn smart_destructure(v: &mut Wrap<(i32, i32)>) {
+ let (ref mut _head, ref mut _tail) = **v;
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-31567.rs b/tests/ui/nll/issue-31567.rs
new file mode 100644
index 000000000..623954e6d
--- /dev/null
+++ b/tests/ui/nll/issue-31567.rs
@@ -0,0 +1,25 @@
+// Regression test for #31567: cached results of projections were
+// causing region relations not to be enforced at all the places where
+// they have to be enforced.
+
+struct VecWrapper<'a>(&'a mut S);
+
+struct S(Box<u32>);
+
+fn get_dangling<'a>(v: VecWrapper<'a>) -> &'a u32 {
+ let s_inner: &'a S = &*v.0; //~ ERROR borrow may still be in use when destructor runs [E0713]
+ &s_inner.0
+}
+
+impl<'a> Drop for VecWrapper<'a> {
+ fn drop(&mut self) {
+ *self.0 = S(Box::new(0));
+ }
+}
+
+fn main() {
+ let mut s = S(Box::new(11));
+ let vw = VecWrapper(&mut s);
+ let dangling = get_dangling(vw);
+ println!("{}", dangling);
+}
diff --git a/tests/ui/nll/issue-31567.stderr b/tests/ui/nll/issue-31567.stderr
new file mode 100644
index 000000000..7d43383e8
--- /dev/null
+++ b/tests/ui/nll/issue-31567.stderr
@@ -0,0 +1,16 @@
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-31567.rs:10:26
+ |
+LL | fn get_dangling<'a>(v: VecWrapper<'a>) -> &'a u32 {
+ | -- lifetime `'a` defined here
+LL | let s_inner: &'a S = &*v.0;
+ | ----- ^^^^^
+ | |
+ | type annotation requires that `*v.0` is borrowed for `'a`
+LL | &s_inner.0
+LL | }
+ | - here, drop of `v` needs exclusive access to `*v.0`, because the type `VecWrapper<'_>` 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/nll/issue-32382-index-assoc-type-with-lifetime.rs b/tests/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs
new file mode 100644
index 000000000..a8a8e6930
--- /dev/null
+++ b/tests/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs
@@ -0,0 +1,41 @@
+// check-pass
+
+// rust-lang/rust#32382: Borrow checker used to complain about
+// `foobar_3` in the `impl` below, presumably due to some interaction
+// between the use of a lifetime in the associated type and the use of
+// the overloaded operator[]. This regression test ensures that we do
+// not resume complaining about it in the future.
+
+
+use std::marker::PhantomData;
+use std::ops::Index;
+
+pub trait Context: Clone {
+ type Container: ?Sized;
+ fn foobar_1( container: &Self::Container ) -> &str;
+ fn foobar_2( container: &Self::Container ) -> &str;
+ fn foobar_3( container: &Self::Container ) -> &str;
+}
+
+#[derive(Clone)]
+struct Foobar<'a> {
+ phantom: PhantomData<&'a ()>
+}
+
+impl<'a> Context for Foobar<'a> {
+ type Container = [&'a str];
+
+ fn foobar_1<'r>( container: &'r [&'a str] ) -> &'r str {
+ container[0]
+ }
+
+ fn foobar_2<'r>( container: &'r Self::Container ) -> &'r str {
+ container.index( 0 )
+ }
+
+ fn foobar_3<'r>( container: &'r Self::Container ) -> &'r str {
+ container[0]
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.rs b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.rs
new file mode 100644
index 000000000..0ec0179e8
--- /dev/null
+++ b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.rs
@@ -0,0 +1,11 @@
+// This test illustrates a case where full NLL (enabled by the feature
+// switch below) produces superior diagnostics to the NLL-migrate
+// mode.
+
+fn doit(data: &'static mut ()) {
+ || doit(data);
+ //~^ ERROR lifetime may not live long enough
+ //~| ERROR `data` does not live long enough
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr
new file mode 100644
index 000000000..f7a525ee9
--- /dev/null
+++ b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr
@@ -0,0 +1,26 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-42574-diagnostic-in-nested-closure.rs:6:8
+ |
+LL | || doit(data);
+ | -- ^^^^^^^^^^ argument requires that `'1` must outlive `'static`
+ | |
+ | lifetime `'1` represents this closure's body
+ |
+ = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+
+error[E0597]: `data` does not live long enough
+ --> $DIR/issue-42574-diagnostic-in-nested-closure.rs:6:13
+ |
+LL | || doit(data);
+ | -- -----^^^^-
+ | | | |
+ | | | borrowed value does not live long enough
+ | | argument requires that `data` is borrowed for `'static`
+ | value captured here
+...
+LL | }
+ | - `data` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-43058.rs b/tests/ui/nll/issue-43058.rs
new file mode 100644
index 000000000..227888d17
--- /dev/null
+++ b/tests/ui/nll/issue-43058.rs
@@ -0,0 +1,26 @@
+// check-pass
+
+use std::borrow::Cow;
+
+#[derive(Clone, Debug)]
+struct S<'a> {
+ name: Cow<'a, str>
+}
+
+#[derive(Clone, Debug)]
+struct T<'a> {
+ s: Cow<'a, [S<'a>]>
+}
+
+fn main() {
+ let s1 = [S { name: Cow::Borrowed("Test1") }, S { name: Cow::Borrowed("Test2") }];
+ let b1 = T { s: Cow::Borrowed(&s1) };
+ let s2 = [S { name: Cow::Borrowed("Test3") }, S { name: Cow::Borrowed("Test4") }];
+ let b2 = T { s: Cow::Borrowed(&s2) };
+
+ let mut v = Vec::new();
+ v.push(b1);
+ v.push(b2);
+
+ println!("{:?}", v);
+}
diff --git a/tests/ui/nll/issue-45157.rs b/tests/ui/nll/issue-45157.rs
new file mode 100644
index 000000000..8d2bf22a0
--- /dev/null
+++ b/tests/ui/nll/issue-45157.rs
@@ -0,0 +1,31 @@
+#![allow(unused)]
+
+
+#[derive(Clone, Copy, Default)]
+struct S {
+ a: u8,
+ b: u8,
+}
+#[derive(Clone, Copy, Default)]
+struct Z {
+ c: u8,
+ d: u8,
+}
+
+union U {
+ s: S,
+ z: Z,
+}
+
+fn main() {
+ unsafe {
+ let mut u = U { s: Default::default() };
+
+ let mref = &mut u.s.a;
+ *mref = 22;
+
+ let nref = &u.z.c;
+ //~^ ERROR cannot borrow `u` (via `u.z.c`) as immutable because it is also borrowed as mutable (via `u.s.a`) [E0502]
+ println!("{} {}", mref, nref)
+ }
+}
diff --git a/tests/ui/nll/issue-45157.stderr b/tests/ui/nll/issue-45157.stderr
new file mode 100644
index 000000000..57fd8d49c
--- /dev/null
+++ b/tests/ui/nll/issue-45157.stderr
@@ -0,0 +1,17 @@
+error[E0502]: cannot borrow `u` (via `u.z.c`) as immutable because it is also borrowed as mutable (via `u.s.a`)
+ --> $DIR/issue-45157.rs:27:20
+ |
+LL | let mref = &mut u.s.a;
+ | ---------- mutable borrow occurs here (via `u.s.a`)
+...
+LL | let nref = &u.z.c;
+ | ^^^^^^ immutable borrow of `u.z.c` -- which overlaps with `u.s.a` -- occurs here
+LL |
+LL | println!("{} {}", mref, nref)
+ | ---- mutable borrow later used here
+ |
+ = note: `u.z.c` is a field of the union `U`, so it overlaps the field `u.s.a`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs b/tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs
new file mode 100644
index 000000000..b3f655628
--- /dev/null
+++ b/tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs
@@ -0,0 +1,114 @@
+// rust-lang/rust#45696: This test is checking that we can return
+// mutable borrows owned by boxes even when the boxes are dropped.
+
+// run-pass
+
+// This function shows quite directly what is going on: We have a
+// reborrow of contents within the box.
+fn return_borrow_from_dropped_box_1(x: Box<&mut u32>) -> &mut u32 { &mut **x }
+
+// This function is the way you'll probably see this in practice (the
+// reborrow is now implicit).
+fn return_borrow_from_dropped_box_2(x: Box<&mut u32>) -> &mut u32 { *x }
+
+// For the remaining tests we just add some fields or other
+// indirection to ensure that the compiler isn't just special-casing
+// the above `Box<&mut T>` as the only type that would work.
+
+// Here we add a tuple of indirection between the box and the
+// reference.
+type BoxedTup<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>;
+
+fn return_borrow_of_field_from_dropped_box_1<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ &mut *x.0
+}
+
+fn return_borrow_of_field_from_dropped_box_2<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ x.0
+}
+
+fn return_borrow_from_dropped_tupled_box_1<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ &mut *(x.0).0
+}
+
+fn return_borrow_from_dropped_tupled_box_2<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ (x.0).0
+}
+
+fn basic_tests() {
+ let mut x = 2;
+ let mut y = 3;
+ let mut z = 4;
+ *return_borrow_from_dropped_box_1(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (12, 3, 4));
+ *return_borrow_from_dropped_box_2(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (22, 3, 4));
+ *return_borrow_of_field_from_dropped_box_1(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (32, 3, 4));
+ *return_borrow_of_field_from_dropped_box_2(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (42, 3, 4));
+ *return_borrow_from_dropped_tupled_box_1((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (52, 3, 4));
+ *return_borrow_from_dropped_tupled_box_2((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (62, 3, 4));
+}
+
+// These scribbling tests have been transcribed from
+// issue-45696-scribble-on-boxed-borrow.rs
+//
+// In the context of that file, these tests are meant to show cases
+// that should be *accepted* by the compiler, so here we are actually
+// checking that the code we get when they are compiled matches our
+// expectations.
+
+struct Scribble<'a>(&'a mut u32);
+
+impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
+
+// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has*
+// to strictly outlive `'a`
+fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
+ &mut *s.0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
+ &mut *(*s).0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
+ &mut *(**s).0
+}
+
+fn scribbling_tests() {
+ let mut x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *borrowed_scribble(&mut long_lived) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+}
+
+fn main() {
+ basic_tests();
+ scribbling_tests();
+}
diff --git a/tests/ui/nll/issue-45696-no-variant-box-recur.rs b/tests/ui/nll/issue-45696-no-variant-box-recur.rs
new file mode 100644
index 000000000..39f1607a3
--- /dev/null
+++ b/tests/ui/nll/issue-45696-no-variant-box-recur.rs
@@ -0,0 +1,47 @@
+// rust-lang/rust#45696: This test checks the compiler won't infinite loop when
+// you declare a variable of type `struct A(Box<A>, ...);` (which is impossible
+// to construct but *is* possible to declare; see also issues #4287, #44933,
+// and #52852).
+
+// run-pass
+
+// This test has structs and functions that are by definition unusable
+// all over the place, so just go ahead and allow dead_code
+#![allow(dead_code)]
+
+// direct regular recursion with indirect ownership via box
+struct C { field: Box<C> }
+
+// direct non-regular recursion with indirect ownership via box
+struct D { field: Box<(D, D)> }
+
+// indirect regular recursion with indirect ownership via box.
+struct E { field: F }
+struct F { field: Box<E> }
+
+// indirect non-regular recursion with indirect ownership via box.
+struct G { field: (H, H) }
+struct H { field: Box<G> }
+
+// These enums are cases that are not currently hit by the
+// `visit_terminator_drop` recursion down a type's structural
+// definition.
+//
+// But it seems prudent to include them in this test as variants on
+// the above, in that they are similarly non-constructable data types
+// with destructors that would diverge.
+enum I { One(Box<I>) }
+enum J { One(Box<J>), Two(Box<J>) }
+
+fn impossible_to_call_c(_c: C) { }
+fn impossible_to_call_d(_d: D) { }
+fn impossible_to_call_e(_e: E) { }
+fn impossible_to_call_f(_f: F) { }
+fn impossible_to_call_g(_g: G) { }
+fn impossible_to_call_h(_h: H) { }
+fn impossible_to_call_i(_i: I) { }
+fn impossible_to_call_j(_j: J) { }
+
+fn main() {
+
+}
diff --git a/tests/ui/nll/issue-45696-scribble-on-boxed-borrow.rs b/tests/ui/nll/issue-45696-scribble-on-boxed-borrow.rs
new file mode 100644
index 000000000..637cf278f
--- /dev/null
+++ b/tests/ui/nll/issue-45696-scribble-on-boxed-borrow.rs
@@ -0,0 +1,67 @@
+// rust-lang/rust#45696: This test is checking that we *cannot* return
+// mutable borrows that would be scribbled over by destructors before
+// the return occurs.
+
+// ignore-compare-mode-polonius
+
+struct Scribble<'a>(&'a mut u32);
+
+impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
+
+// this is okay: The `Scribble` here *has* to strictly outlive `'a`
+fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
+ &mut *s.0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
+ &mut *(*s).0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
+ &mut *(**s).0
+}
+
+// this is not okay: in between the time that we take the mutable
+// borrow and the caller receives it as a return value, the drop of
+// `s` will scribble on it, violating our aliasing guarantees.
+//
+// * (Maybe in the future the two-phase borrows system will be
+// extended to support this case. But for now, it is an error in
+// NLL, even with two-phase borrows.)
+fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ &mut *s.0 //~ ERROR borrow may still be in use when destructor runs [E0713]
+}
+
+// This, by analogy to previous case, is *also* not okay.
+fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ &mut *(*s).0 //~ ERROR borrow may still be in use when destructor runs [E0713]
+}
+
+// This, by analogy to previous case, is *also* not okay.
+fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ &mut *(**s).0 //~ ERROR borrow may still be in use when destructor runs [E0713]
+}
+
+fn main() {
+ let mut x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *borrowed_scribble(&mut long_lived) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ *scribbled(Scribble(&mut x)) += 10;
+ *boxed_scribbled(Box::new(Scribble(&mut x))) += 10;
+ *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;
+}
diff --git a/tests/ui/nll/issue-45696-scribble-on-boxed-borrow.stderr b/tests/ui/nll/issue-45696-scribble-on-boxed-borrow.stderr
new file mode 100644
index 000000000..db0a17199
--- /dev/null
+++ b/tests/ui/nll/issue-45696-scribble-on-boxed-borrow.stderr
@@ -0,0 +1,33 @@
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:34:5
+ |
+LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ | -- lifetime `'a` defined here
+LL | &mut *s.0
+ | ^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a`
+LL | }
+ | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait
+
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:39:5
+ |
+LL | fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ | -- lifetime `'a` defined here
+LL | &mut *(*s).0
+ | ^^^^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a`
+LL | }
+ | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait
+
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:44:5
+ |
+LL | fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ | -- lifetime `'a` defined here
+LL | &mut *(**s).0
+ | ^^^^^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a`
+LL | }
+ | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0713`.
diff --git a/tests/ui/nll/issue-46023.rs b/tests/ui/nll/issue-46023.rs
new file mode 100644
index 000000000..a923eb244
--- /dev/null
+++ b/tests/ui/nll/issue-46023.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let x = 0;
+
+ (move || {
+ x = 1;
+ //~^ ERROR cannot assign to `x`, as it is not declared as mutable [E0594]
+ })()
+}
diff --git a/tests/ui/nll/issue-46023.stderr b/tests/ui/nll/issue-46023.stderr
new file mode 100644
index 000000000..ca19c2501
--- /dev/null
+++ b/tests/ui/nll/issue-46023.stderr
@@ -0,0 +1,12 @@
+error[E0594]: cannot assign to `x`, as it is not declared as mutable
+ --> $DIR/issue-46023.rs:5:9
+ |
+LL | let x = 0;
+ | - help: consider changing this to be mutable: `mut x`
+...
+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/nll/issue-46036.rs b/tests/ui/nll/issue-46036.rs
new file mode 100644
index 000000000..18af33c18
--- /dev/null
+++ b/tests/ui/nll/issue-46036.rs
@@ -0,0 +1,12 @@
+// Issue 46036: [NLL] false edges on infinite loops
+// Infinite loops should create false edges to the cleanup block.
+
+struct Foo { x: &'static u32 }
+
+fn foo() {
+ let a = 3;
+ let foo = Foo { x: &a }; //~ ERROR E0597
+ loop { }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-46036.stderr b/tests/ui/nll/issue-46036.stderr
new file mode 100644
index 000000000..e6e95ee61
--- /dev/null
+++ b/tests/ui/nll/issue-46036.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `a` does not live long enough
+ --> $DIR/issue-46036.rs:8:24
+ |
+LL | let foo = Foo { x: &a };
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `a` is borrowed for `'static`
+LL | loop { }
+LL | }
+ | - `a` 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/nll/issue-46589.rs b/tests/ui/nll/issue-46589.rs
new file mode 100644
index 000000000..0a4c20d15
--- /dev/null
+++ b/tests/ui/nll/issue-46589.rs
@@ -0,0 +1,31 @@
+// This tests passes in Polonius mode, so is skipped in the automated compare-mode.
+// We will manually check it passes in Polonius tests, as we can't have a test here
+// which conditionally passes depending on a test revision/compile-flags.
+
+// ignore-compare-mode-polonius
+
+struct Foo;
+
+impl Foo {
+ fn get_self(&mut self) -> Option<&mut Self> {
+ Some(self)
+ }
+
+ fn new_self(&mut self) -> &mut Self {
+ self
+ }
+
+ fn trigger_bug(&mut self) {
+ let other = &mut (&mut *self);
+
+ *other = match (*other).get_self() {
+ Some(s) => s,
+ None => (*other).new_self()
+ //~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499]
+ };
+
+ let c = other;
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-46589.stderr b/tests/ui/nll/issue-46589.stderr
new file mode 100644
index 000000000..60ef3f7b8
--- /dev/null
+++ b/tests/ui/nll/issue-46589.stderr
@@ -0,0 +1,15 @@
+error[E0499]: cannot borrow `**other` as mutable more than once at a time
+ --> $DIR/issue-46589.rs:23:21
+ |
+LL | *other = match (*other).get_self() {
+ | ------------------- first mutable borrow occurs here
+LL | Some(s) => s,
+LL | None => (*other).new_self()
+ | ^^^^^^^^^^^^^^^^^^^
+ | |
+ | second mutable borrow occurs here
+ | 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/nll/issue-47022.rs b/tests/ui/nll/issue-47022.rs
new file mode 100644
index 000000000..521643c66
--- /dev/null
+++ b/tests/ui/nll/issue-47022.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+struct LoadedObject {
+ bodies: Vec<Body>,
+ color: Color,
+}
+
+struct Body;
+
+#[derive(Clone)]
+struct Color;
+
+struct Graphic {
+ color: Color,
+}
+
+fn convert(objects: Vec<LoadedObject>) -> (Vec<Body>, Vec<Graphic>) {
+ objects
+ .into_iter()
+ .flat_map(|LoadedObject { bodies, color, .. }| {
+ bodies.into_iter().map(move |body| {
+ (
+ body,
+ Graphic {
+ color: color.clone(),
+ },
+ )
+ })
+ })
+ .unzip()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-47153-generic-const.rs b/tests/ui/nll/issue-47153-generic-const.rs
new file mode 100644
index 000000000..9f4d57111
--- /dev/null
+++ b/tests/ui/nll/issue-47153-generic-const.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+// Regression test for #47153: constants in a generic context (such as
+// a trait) used to ICE.
+
+#![allow(warnings)]
+
+trait Foo {
+ const B: bool = true;
+}
+
+struct Bar<T> { x: T }
+
+impl<T> Bar<T> {
+ const B: bool = true;
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-47388.rs b/tests/ui/nll/issue-47388.rs
new file mode 100644
index 000000000..207af380e
--- /dev/null
+++ b/tests/ui/nll/issue-47388.rs
@@ -0,0 +1,10 @@
+struct FancyNum {
+ num: u8,
+}
+
+fn main() {
+ let mut fancy = FancyNum{ num: 5 };
+ let fancy_ref = &(&mut fancy);
+ fancy_ref.num = 6; //~ ERROR E0594
+ println!("{}", fancy_ref.num);
+}
diff --git a/tests/ui/nll/issue-47388.stderr b/tests/ui/nll/issue-47388.stderr
new file mode 100644
index 000000000..c780451df
--- /dev/null
+++ b/tests/ui/nll/issue-47388.stderr
@@ -0,0 +1,14 @@
+error[E0594]: cannot assign to `fancy_ref.num`, which is behind a `&` reference
+ --> $DIR/issue-47388.rs:8:5
+ |
+LL | fancy_ref.num = 6;
+ | ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let fancy_ref = &mut (&mut fancy);
+ | ~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/nll/issue-47470.rs b/tests/ui/nll/issue-47470.rs
new file mode 100644
index 000000000..72ee7f886
--- /dev/null
+++ b/tests/ui/nll/issue-47470.rs
@@ -0,0 +1,22 @@
+// Regression test for #47470: cached results of projections were
+// causing region relations not to be enforced at all the places where
+// they have to be enforced.
+
+struct Foo<'a>(&'a ());
+trait Bar {
+ type Assoc;
+ fn get(self) -> Self::Assoc;
+}
+
+impl<'a> Bar for Foo<'a> {
+ type Assoc = &'a u32;
+ fn get(self) -> Self::Assoc {
+ let local = 42;
+ &local //~ ERROR cannot return reference to local variable `local`
+ }
+}
+
+fn main() {
+ let f = Foo(&()).get();
+ println!("{}", f);
+}
diff --git a/tests/ui/nll/issue-47470.stderr b/tests/ui/nll/issue-47470.stderr
new file mode 100644
index 000000000..0b1247d60
--- /dev/null
+++ b/tests/ui/nll/issue-47470.stderr
@@ -0,0 +1,9 @@
+error[E0515]: cannot return reference to local variable `local`
+ --> $DIR/issue-47470.rs:15:9
+ |
+LL | &local
+ | ^^^^^^ 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/nll/issue-47589.rs b/tests/ui/nll/issue-47589.rs
new file mode 100644
index 000000000..280bf0811
--- /dev/null
+++ b/tests/ui/nll/issue-47589.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+pub struct DescriptorSet<'a> {
+ pub slots: Vec<AttachInfo<'a, Resources>>
+}
+
+pub trait ResourcesTrait<'r>: Sized {
+ type DescriptorSet: 'r;
+}
+
+pub struct Resources;
+
+impl<'a> ResourcesTrait<'a> for Resources {
+ type DescriptorSet = DescriptorSet<'a>;
+}
+
+pub enum AttachInfo<'a, R: ResourcesTrait<'a>> {
+ NextDescriptorSet(Box<R::DescriptorSet>)
+}
+
+fn main() {
+ let _x = DescriptorSet {slots: Vec::new()};
+}
diff --git a/tests/ui/nll/issue-48070.rs b/tests/ui/nll/issue-48070.rs
new file mode 100644
index 000000000..a9fe3521d
--- /dev/null
+++ b/tests/ui/nll/issue-48070.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+struct Foo {
+ x: u32
+}
+
+impl Foo {
+ fn twiddle(&mut self) -> &mut Self { self }
+ fn twaddle(&mut self) -> &mut Self { self }
+ fn emit(&mut self) {
+ self.x += 1;
+ }
+}
+
+fn main() {
+ let mut foo = Foo { x: 0 };
+ match 22 {
+ 22 => &mut foo,
+ 44 => foo.twiddle(),
+ _ => foo.twaddle(),
+ }.emit();
+}
diff --git a/tests/ui/nll/issue-48238.rs b/tests/ui/nll/issue-48238.rs
new file mode 100644
index 000000000..d2e9285fa
--- /dev/null
+++ b/tests/ui/nll/issue-48238.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #48238
+
+fn use_val<'a>(val: &'a u8) -> &'a u8 {
+ val
+}
+
+fn main() {
+ let orig: u8 = 5;
+ move || use_val(&orig); //~ ERROR
+}
diff --git a/tests/ui/nll/issue-48238.stderr b/tests/ui/nll/issue-48238.stderr
new file mode 100644
index 000000000..0aa1eedad
--- /dev/null
+++ b/tests/ui/nll/issue-48238.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-48238.rs:9:13
+ |
+LL | move || use_val(&orig);
+ | ------- ^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+ | | |
+ | | return type of closure is &'2 u8
+ | lifetime `'1` represents this closure's body
+ |
+ = note: closure implements `Fn`, so references to captured variables can't escape the closure
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-48623-closure.rs b/tests/ui/nll/issue-48623-closure.rs
new file mode 100644
index 000000000..3f8587eed
--- /dev/null
+++ b/tests/ui/nll/issue-48623-closure.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![allow(path_statements)]
+#![allow(dead_code)]
+
+struct WithDrop;
+
+impl Drop for WithDrop {
+ fn drop(&mut self) {}
+}
+
+fn reborrow_from_closure(r: &mut ()) -> &mut () {
+ let d = WithDrop;
+ (move || { d; &mut *r })()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-48623-generator.rs b/tests/ui/nll/issue-48623-generator.rs
new file mode 100644
index 000000000..08d2584ee
--- /dev/null
+++ b/tests/ui/nll/issue-48623-generator.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![allow(path_statements)]
+#![allow(dead_code)]
+
+#![feature(generators, generator_trait)]
+
+struct WithDrop;
+
+impl Drop for WithDrop {
+ fn drop(&mut self) {}
+}
+
+fn reborrow_from_generator(r: &mut ()) {
+ let d = WithDrop;
+ move || { d; yield; &mut *r }; //~ WARN unused generator that must be used
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-48623-generator.stderr b/tests/ui/nll/issue-48623-generator.stderr
new file mode 100644
index 000000000..bfdfca210
--- /dev/null
+++ b/tests/ui/nll/issue-48623-generator.stderr
@@ -0,0 +1,11 @@
+warning: unused generator that must be used
+ --> $DIR/issue-48623-generator.rs:15:5
+ |
+LL | move || { d; yield; &mut *r };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: generators are lazy and do nothing unless resumed
+ = note: `#[warn(unused_must_use)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/nll/issue-48697.rs b/tests/ui/nll/issue-48697.rs
new file mode 100644
index 000000000..16e29ab2a
--- /dev/null
+++ b/tests/ui/nll/issue-48697.rs
@@ -0,0 +1,10 @@
+// Regression test for #48697
+
+fn foo(x: &i32) -> &i32 {
+ let z = 4;
+ let f = &|y| y;
+ let k = f(&z);
+ f(x) //~ cannot return value referencing local variable
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-48697.stderr b/tests/ui/nll/issue-48697.stderr
new file mode 100644
index 000000000..f0c29b72b
--- /dev/null
+++ b/tests/ui/nll/issue-48697.stderr
@@ -0,0 +1,11 @@
+error[E0515]: cannot return value referencing local variable `z`
+ --> $DIR/issue-48697.rs:7:5
+ |
+LL | let k = f(&z);
+ | -- `z` is borrowed here
+LL | f(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/nll/issue-48803.rs b/tests/ui/nll/issue-48803.rs
new file mode 100644
index 000000000..f7fd04179
--- /dev/null
+++ b/tests/ui/nll/issue-48803.rs
@@ -0,0 +1,13 @@
+fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T {
+ x
+}
+
+fn main() {
+ let mut x = "original";
+ let y = &x;
+ let z = &y;
+ let w = flatten(z);
+ x = "modified";
+ //~^ ERROR cannot assign to `x` because it is borrowed [E0506]
+ println!("{}", w); // prints "modified"
+}
diff --git a/tests/ui/nll/issue-48803.stderr b/tests/ui/nll/issue-48803.stderr
new file mode 100644
index 000000000..2f94039c0
--- /dev/null
+++ b/tests/ui/nll/issue-48803.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/issue-48803.rs:10:5
+ |
+LL | let y = &x;
+ | -- borrow of `x` occurs here
+...
+LL | x = "modified";
+ | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+LL |
+LL | println!("{}", w); // prints "modified"
+ | - 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/nll/issue-50343.rs b/tests/ui/nll/issue-50343.rs
new file mode 100644
index 000000000..dd0afbbdf
--- /dev/null
+++ b/tests/ui/nll/issue-50343.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+#![deny(unused_mut)]
+
+fn main() {
+ vec![42].iter().map(drop).count();
+ vec![(42, 22)].iter().map(|(_x, _y)| ()).count();
+}
diff --git a/tests/ui/nll/issue-50461-used-mut-from-moves.rs b/tests/ui/nll/issue-50461-used-mut-from-moves.rs
new file mode 100644
index 000000000..2458b171e
--- /dev/null
+++ b/tests/ui/nll/issue-50461-used-mut-from-moves.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+#![deny(unused_mut)]
+#![allow(dead_code)]
+
+struct Foo {
+ pub value: i32
+}
+
+fn use_foo_mut(mut foo: Foo) {
+ foo = foo;
+ println!("{}", foo.value);
+}
+
+fn main() {
+ use_foo_mut(Foo { value: 413 });
+}
diff --git a/tests/ui/nll/issue-50716-1.rs b/tests/ui/nll/issue-50716-1.rs
new file mode 100644
index 000000000..9c3e24de4
--- /dev/null
+++ b/tests/ui/nll/issue-50716-1.rs
@@ -0,0 +1,10 @@
+//
+// An additional regression test for the issue #50716 “NLL ignores lifetimes
+// bounds derived from `Sized` requirements” that checks that the fixed compiler
+// accepts this code fragment with both AST and MIR borrow checkers.
+//
+// check-pass
+
+struct Qey<Q: ?Sized>(Q);
+
+fn main() {}
diff --git a/tests/ui/nll/issue-50716.rs b/tests/ui/nll/issue-50716.rs
new file mode 100644
index 000000000..c2fc345fa
--- /dev/null
+++ b/tests/ui/nll/issue-50716.rs
@@ -0,0 +1,17 @@
+//
+// Regression test for the issue #50716: NLL ignores lifetimes bounds
+// derived from `Sized` requirements
+
+trait A {
+ type X: ?Sized;
+}
+
+fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
+where
+ for<'b> &'b T: A,
+ <&'static T as A>::X: Sized
+{
+ let _x = *s; //~ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-50716.stderr b/tests/ui/nll/issue-50716.stderr
new file mode 100644
index 000000000..38dd1b5f6
--- /dev/null
+++ b/tests/ui/nll/issue-50716.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-50716.rs:14:14
+ |
+LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
+ | -- lifetime `'a` defined here
+...
+LL | let _x = *s;
+ | ^^ proving this value is `Sized` requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-51191.rs b/tests/ui/nll/issue-51191.rs
new file mode 100644
index 000000000..836587d93
--- /dev/null
+++ b/tests/ui/nll/issue-51191.rs
@@ -0,0 +1,34 @@
+struct Struct;
+
+impl Struct {
+ fn bar(self: &mut Self) {
+ //~^ WARN function cannot return without recursing
+ //~^^ HELP a `loop` may express intention better if this is on purpose
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ //~^^ HELP try removing `&mut` here
+ }
+
+ fn imm(self) { //~ HELP consider changing this to be mutable
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ }
+
+ fn mtbl(mut self) {
+ (&mut self).bar();
+ }
+
+ fn immref(&self) {
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ //~^^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
+ }
+
+ fn mtblref(&mut self) {
+ (&mut self).bar();
+ //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
+ //~^^ HELP try removing `&mut` here
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-51191.stderr b/tests/ui/nll/issue-51191.stderr
new file mode 100644
index 000000000..27b1f8705
--- /dev/null
+++ b/tests/ui/nll/issue-51191.stderr
@@ -0,0 +1,72 @@
+warning: function cannot return without recursing
+ --> $DIR/issue-51191.rs:4:5
+ |
+LL | fn bar(self: &mut Self) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL | (&mut self).bar();
+ | ----------------- recursive call site
+ |
+ = help: a `loop` may express intention better if this is on purpose
+ = note: `#[warn(unconditional_recursion)]` on by default
+
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:7:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^ cannot borrow as mutable
+ |
+note: the binding is already a mutable borrow
+ --> $DIR/issue-51191.rs:4:18
+ |
+LL | fn bar(self: &mut Self) {
+ | ^^^^^^^^^
+help: try removing `&mut` here
+ --> $DIR/issue-51191.rs:7:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^
+
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:13:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn imm(mut self) {
+ | +++
+
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:22:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/issue-51191.rs:22:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+ --> $DIR/issue-51191.rs:28:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^ cannot borrow as mutable
+ |
+note: the binding is already a mutable borrow
+ --> $DIR/issue-51191.rs:27:16
+ |
+LL | fn mtblref(&mut self) {
+ | ^^^^^^^^^
+help: try removing `&mut` here
+ --> $DIR/issue-51191.rs:28:9
+ |
+LL | (&mut self).bar();
+ | ^^^^^^^^^^^
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/nll/issue-51244.rs b/tests/ui/nll/issue-51244.rs
new file mode 100644
index 000000000..c4cbee675
--- /dev/null
+++ b/tests/ui/nll/issue-51244.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let ref my_ref @ _ = 0;
+ *my_ref = 0;
+ //~^ ERROR cannot assign to `*my_ref`, which is behind a `&` reference [E0594]
+}
diff --git a/tests/ui/nll/issue-51244.stderr b/tests/ui/nll/issue-51244.stderr
new file mode 100644
index 000000000..03d8acc81
--- /dev/null
+++ b/tests/ui/nll/issue-51244.stderr
@@ -0,0 +1,14 @@
+error[E0594]: cannot assign to `*my_ref`, which is behind a `&` reference
+ --> $DIR/issue-51244.rs:3:5
+ |
+LL | *my_ref = 0;
+ | ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let ref mut my_ref @ _ = 0;
+ | ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/nll/issue-51268.rs b/tests/ui/nll/issue-51268.rs
new file mode 100644
index 000000000..dcdedf7d4
--- /dev/null
+++ b/tests/ui/nll/issue-51268.rs
@@ -0,0 +1,21 @@
+struct Bar;
+
+impl Bar {
+ fn bar(&mut self, _: impl Fn()) {}
+}
+
+struct Foo {
+ thing: Bar,
+ number: usize,
+}
+
+impl Foo {
+ fn foo(&mut self) {
+ self.thing.bar(|| {
+ //~^ ERROR cannot borrow `self.thing` as mutable because it is also borrowed as immutable [E0502]
+ &self.number;
+ });
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-51268.stderr b/tests/ui/nll/issue-51268.stderr
new file mode 100644
index 000000000..0483bda63
--- /dev/null
+++ b/tests/ui/nll/issue-51268.stderr
@@ -0,0 +1,17 @@
+error[E0502]: cannot borrow `self.thing` as mutable because it is also borrowed as immutable
+ --> $DIR/issue-51268.rs:14:9
+ |
+LL | self.thing.bar(|| {
+ | ^ --- -- immutable borrow occurs here
+ | | |
+ | _________| immutable borrow later used by call
+ | |
+LL | |
+LL | | &self.number;
+ | | ----------- first borrow occurs due to use of `self` in closure
+LL | | });
+ | |__________^ mutable borrow occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/nll/issue-51345-2.rs b/tests/ui/nll/issue-51345-2.rs
new file mode 100644
index 000000000..52f342a85
--- /dev/null
+++ b/tests/ui/nll/issue-51345-2.rs
@@ -0,0 +1,8 @@
+// run-fail
+// error-pattern: thread 'main' panicked at 'explicit panic'
+// ignore-emscripten no processes
+
+fn main() {
+ let mut vec = vec![];
+ vec.push((vec.len(), panic!()));
+}
diff --git a/tests/ui/nll/issue-51351.rs b/tests/ui/nll/issue-51351.rs
new file mode 100644
index 000000000..591d49584
--- /dev/null
+++ b/tests/ui/nll/issue-51351.rs
@@ -0,0 +1,21 @@
+//
+// Regression test for #51351 and #52133: In the case of #51351,
+// late-bound regions (like 'a) that were unused within the arguments of
+// a function were overlooked and could case an ICE. In the case of #52133,
+// LBR defined on the creator function needed to be added to the free regions
+// of the closure, as they were not present in the closure's generic
+// declarations otherwise.
+//
+// check-pass
+
+fn creash<'a>() {
+ let x: &'a () = &();
+}
+
+fn produce<'a>() {
+ move || {
+ let x: &'a () = &();
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-51512.rs b/tests/ui/nll/issue-51512.rs
new file mode 100644
index 000000000..691760eb9
--- /dev/null
+++ b/tests/ui/nll/issue-51512.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let range = 0..1;
+ let r = range;
+ let x = range.start;
+ //~^ ERROR use of moved value: `range` [E0382]
+}
diff --git a/tests/ui/nll/issue-51512.stderr b/tests/ui/nll/issue-51512.stderr
new file mode 100644
index 000000000..072e96788
--- /dev/null
+++ b/tests/ui/nll/issue-51512.stderr
@@ -0,0 +1,18 @@
+error[E0382]: use of moved value: `range`
+ --> $DIR/issue-51512.rs:4:13
+ |
+LL | let range = 0..1;
+ | ----- move occurs because `range` has type `std::ops::Range<i32>`, which does not implement the `Copy` trait
+LL | let r = range;
+ | ----- value moved here
+LL | let x = range.start;
+ | ^^^^^^^^^^^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | let r = range.clone();
+ | ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/nll/issue-51770.rs b/tests/ui/nll/issue-51770.rs
new file mode 100644
index 000000000..3d6bc82f1
--- /dev/null
+++ b/tests/ui/nll/issue-51770.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![crate_type = "lib"]
+
+// In an older version, when NLL was still a feature, the following previously did not compile
+
+use std::ops::Index;
+
+pub struct Test<T> {
+ a: T,
+}
+
+impl<T> Index<usize> for Test<T> {
+ type Output = T;
+
+ fn index(&self, _index: usize) -> &Self::Output {
+ &self.a
+ }
+}
diff --git a/tests/ui/nll/issue-52057.rs b/tests/ui/nll/issue-52057.rs
new file mode 100644
index 000000000..98f49fe8f
--- /dev/null
+++ b/tests/ui/nll/issue-52057.rs
@@ -0,0 +1,22 @@
+// Regression test for #52057. There is an implied bound
+// that `I: 'a` where `'a` is the lifetime of `self` in `parse_first`;
+// but to observe that, one must normalize first.
+//
+// run-pass
+
+pub trait Parser {
+ type Input;
+
+ fn parse_first(input: &mut Self::Input);
+}
+
+impl<'a, I, P: ?Sized> Parser for &'a mut P
+where
+ P: Parser<Input = I>,
+{
+ type Input = I;
+
+ fn parse_first(_: &mut Self::Input) {}
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs
new file mode 100644
index 000000000..7ea1c445d
--- /dev/null
+++ b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs
@@ -0,0 +1,30 @@
+// rust-lang/rust#52059: Regardless of whether you are moving out of a
+// Drop type or just introducing an inadvertent alias via a borrow of
+// one of its fields, it is useful to be reminded of the significance
+// of the fact that the type implements Drop.
+
+pub struct S<'a> { url: &'a mut String }
+
+impl<'a> Drop for S<'a> { fn drop(&mut self) { } }
+
+fn finish_1(s: S) -> &mut String {
+ s.url
+}
+//~^^ ERROR borrow may still be in use when destructor runs
+
+fn finish_2(s: S) -> &mut String {
+ let p = &mut *s.url; p
+}
+//~^^ ERROR borrow may still be in use when destructor runs
+
+fn finish_3(s: S) -> &mut String {
+ let p: &mut _ = s.url; p
+}
+//~^^ ERROR borrow may still be in use when destructor runs
+
+fn finish_4(s: S) -> &mut String {
+ let p = s.url; p
+}
+//~^^ ERROR cannot move out of type `S<'_>`, which implements the `Drop` trait
+
+fn main() {}
diff --git a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
new file mode 100644
index 000000000..7f9cbc3c3
--- /dev/null
+++ b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
@@ -0,0 +1,48 @@
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:11:5
+ |
+LL | fn finish_1(s: S) -> &mut String {
+ | - has type `S<'1>`
+LL | s.url
+ | ^^^^^ returning this value requires that `*s.url` is borrowed for `'1`
+LL | }
+ | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait
+
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:16:13
+ |
+LL | fn finish_2(s: S) -> &mut String {
+ | - has type `S<'1>`
+LL | let p = &mut *s.url; p
+ | ^^^^^^^^^^^ - returning this value requires that `*s.url` is borrowed for `'1`
+LL | }
+ | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait
+
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:21:21
+ |
+LL | fn finish_3(s: S) -> &mut String {
+ | - has type `S<'1>`
+LL | let p: &mut _ = s.url; p
+ | ^^^^^ - returning this value requires that `*s.url` is borrowed for `'1`
+LL | }
+ | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait
+
+error[E0509]: cannot move out of type `S<'_>`, which implements the `Drop` trait
+ --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:26:13
+ |
+LL | let p = s.url; p
+ | ^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `s.url` has type `&mut String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let p = &s.url; p
+ | +
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0509, E0713.
+For more information about an error, try `rustc --explain E0509`.
diff --git a/tests/ui/nll/issue-52078.rs b/tests/ui/nll/issue-52078.rs
new file mode 100644
index 000000000..a2bcb91ac
--- /dev/null
+++ b/tests/ui/nll/issue-52078.rs
@@ -0,0 +1,24 @@
+// Regression test for #52078: we were failing to infer a relationship
+// between `'a` and `'b` below due to inference variables introduced
+// during the normalization process.
+//
+// check-pass
+
+struct Drain<'a, T: 'a> {
+ _marker: ::std::marker::PhantomData<&'a T>,
+}
+
+trait Join {
+ type Value;
+ fn get(value: &mut Self::Value);
+}
+
+impl<'a, T> Join for Drain<'a, T> {
+ type Value = &'a mut Option<T>;
+
+ fn get<'b>(value: &'b mut Self::Value) {
+ }
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/issue-52086.rs b/tests/ui/nll/issue-52086.rs
new file mode 100644
index 000000000..0414428e4
--- /dev/null
+++ b/tests/ui/nll/issue-52086.rs
@@ -0,0 +1,14 @@
+use std::rc::Rc;
+use std::sync::Arc;
+
+struct Bar { field: Vec<i32> }
+
+fn main() {
+ let x = Rc::new(Bar { field: vec![] });
+ drop(x.field);
+//~^ ERROR cannot move out of an `Rc`
+
+ let y = Arc::new(Bar { field: vec![] });
+ drop(y.field);
+//~^ ERROR cannot move out of an `Arc`
+}
diff --git a/tests/ui/nll/issue-52086.stderr b/tests/ui/nll/issue-52086.stderr
new file mode 100644
index 000000000..3b2dae9b7
--- /dev/null
+++ b/tests/ui/nll/issue-52086.stderr
@@ -0,0 +1,15 @@
+error[E0507]: cannot move out of an `Rc`
+ --> $DIR/issue-52086.rs:8:10
+ |
+LL | drop(x.field);
+ | ^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+
+error[E0507]: cannot move out of an `Arc`
+ --> $DIR/issue-52086.rs:12:10
+ |
+LL | drop(y.field);
+ | ^^^^^^^ move occurs because value has type `Vec<i32>`, 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/nll/issue-52113.rs b/tests/ui/nll/issue-52113.rs
new file mode 100644
index 000000000..ffaef272a
--- /dev/null
+++ b/tests/ui/nll/issue-52113.rs
@@ -0,0 +1,35 @@
+trait Bazinga {}
+impl<F> Bazinga for F {}
+
+fn produce1<'a>(data: &'a u32) -> impl Bazinga + 'a {
+ let x = move || {
+ let _data: &'a u32 = data;
+ };
+ x
+}
+
+fn produce2<'a>(data: &'a mut Vec<&'a u32>, value: &'a u32) -> impl Bazinga + 'a {
+ let x = move || {
+ let value: &'a u32 = value;
+ data.push(value);
+ };
+ x
+}
+
+fn produce3<'a, 'b: 'a>(data: &'a mut Vec<&'a u32>, value: &'b u32) -> impl Bazinga + 'a {
+ let x = move || {
+ let value: &'a u32 = value;
+ data.push(value);
+ };
+ x
+}
+
+fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
+ let x = move || {
+ let value: &'a u32 = value;
+ data.push(value); //~ ERROR lifetime may not live long enough
+ };
+ x
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-52113.stderr b/tests/ui/nll/issue-52113.stderr
new file mode 100644
index 000000000..84d4eb266
--- /dev/null
+++ b/tests/ui/nll/issue-52113.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-52113.rs:30:9
+ |
+LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | data.push(value);
+ | ^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-52213.rs b/tests/ui/nll/issue-52213.rs
new file mode 100644
index 000000000..a016924a8
--- /dev/null
+++ b/tests/ui/nll/issue-52213.rs
@@ -0,0 +1,15 @@
+fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+ match (&t,) {
+ ((u,),) => u,
+ //~^ ERROR lifetime may not live long enough
+ }
+}
+
+fn main() {
+ let x = {
+ let y = Box::new((42,));
+ transmute_lifetime(&y)
+ };
+
+ println!("{}", x);
+}
diff --git a/tests/ui/nll/issue-52213.stderr b/tests/ui/nll/issue-52213.stderr
new file mode 100644
index 000000000..da31bcd54
--- /dev/null
+++ b/tests/ui/nll/issue-52213.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-52213.rs:3:20
+ |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | match (&t,) {
+LL | ((u,),) => u,
+ | ^ 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/nll/issue-52533-1.rs b/tests/ui/nll/issue-52533-1.rs
new file mode 100644
index 000000000..d15daeddc
--- /dev/null
+++ b/tests/ui/nll/issue-52533-1.rs
@@ -0,0 +1,11 @@
+#![allow(warnings)]
+
+struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T }
+
+fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>,
+ &'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { }
+
+fn main() {
+ gimme(|x, y| y)
+ //~^ ERROR lifetime may not live long enough
+}
diff --git a/tests/ui/nll/issue-52533-1.stderr b/tests/ui/nll/issue-52533-1.stderr
new file mode 100644
index 000000000..20f19b259
--- /dev/null
+++ b/tests/ui/nll/issue-52533-1.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-52533-1.rs:9:18
+ |
+LL | gimme(|x, y| y)
+ | - - ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ | | |
+ | | has type `&Foo<'_, '1, u32>`
+ | has type `&Foo<'_, '2, u32>`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-52534-1.rs b/tests/ui/nll/issue-52534-1.rs
new file mode 100644
index 000000000..d9ea3ae42
--- /dev/null
+++ b/tests/ui/nll/issue-52534-1.rs
@@ -0,0 +1,48 @@
+struct Test;
+
+impl Test {
+ fn bar(&self, x: &u32) -> &u32 {
+ let x = 22;
+ &x
+//~^ ERROR cannot return reference to local variable
+ }
+}
+
+fn foo(x: &u32) -> &u32 {
+ let x = 22;
+ &x
+//~^ ERROR cannot return reference to local variable
+}
+
+fn baz(x: &u32) -> &&u32 {
+ let x = 22;
+ &&x
+//~^ ERROR cannot return value referencing local variable
+//~| ERROR cannot return reference to temporary value
+}
+
+fn foobazbar<'a>(x: u32, y: &'a u32) -> &'a u32 {
+ let x = 22;
+ &x
+//~^ ERROR cannot return reference to local variable
+}
+
+fn foobar<'a>(x: &'a u32) -> &'a u32 {
+ let x = 22;
+ &x
+//~^ ERROR cannot return reference to local variable
+}
+
+fn foobaz<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ let x = 22;
+ &x
+//~^ ERROR cannot return reference to local variable
+}
+
+fn foobarbaz<'a, 'b>(x: &'a u32, y: &'b u32, z: &'a u32) -> &'a u32 {
+ let x = 22;
+ &x
+//~^ ERROR cannot return reference to local variable
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-52534-1.stderr b/tests/ui/nll/issue-52534-1.stderr
new file mode 100644
index 000000000..743179f05
--- /dev/null
+++ b/tests/ui/nll/issue-52534-1.stderr
@@ -0,0 +1,57 @@
+error[E0515]: cannot return reference to local variable `x`
+ --> $DIR/issue-52534-1.rs:6:9
+ |
+LL | &x
+ | ^^ returns a reference to data owned by the current function
+
+error[E0515]: cannot return reference to local variable `x`
+ --> $DIR/issue-52534-1.rs:13:5
+ |
+LL | &x
+ | ^^ returns a reference to data owned by the current function
+
+error[E0515]: cannot return value referencing local variable `x`
+ --> $DIR/issue-52534-1.rs:19:5
+ |
+LL | &&x
+ | ^--
+ | ||
+ | |`x` is borrowed here
+ | returns a value referencing data owned by the current function
+
+error[E0515]: cannot return reference to temporary value
+ --> $DIR/issue-52534-1.rs:19:5
+ |
+LL | &&x
+ | ^--
+ | ||
+ | |temporary value created here
+ | returns a reference to data owned by the current function
+
+error[E0515]: cannot return reference to local variable `x`
+ --> $DIR/issue-52534-1.rs:26:5
+ |
+LL | &x
+ | ^^ returns a reference to data owned by the current function
+
+error[E0515]: cannot return reference to local variable `x`
+ --> $DIR/issue-52534-1.rs:32:5
+ |
+LL | &x
+ | ^^ returns a reference to data owned by the current function
+
+error[E0515]: cannot return reference to local variable `x`
+ --> $DIR/issue-52534-1.rs:38:5
+ |
+LL | &x
+ | ^^ returns a reference to data owned by the current function
+
+error[E0515]: cannot return reference to local variable `x`
+ --> $DIR/issue-52534-1.rs:44:5
+ |
+LL | &x
+ | ^^ returns a reference to data owned by the current function
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/nll/issue-52534-2.rs b/tests/ui/nll/issue-52534-2.rs
new file mode 100644
index 000000000..e416264ed
--- /dev/null
+++ b/tests/ui/nll/issue-52534-2.rs
@@ -0,0 +1,14 @@
+fn foo(x: &u32) -> &u32 {
+ let y;
+
+ {
+ let x = 32;
+ y = &x
+//~^ ERROR does not live long enough
+ }
+
+ println!("{}", y);
+ x
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-52534-2.stderr b/tests/ui/nll/issue-52534-2.stderr
new file mode 100644
index 000000000..ac385e056
--- /dev/null
+++ b/tests/ui/nll/issue-52534-2.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/issue-52534-2.rs:6:13
+ |
+LL | y = &x
+ | ^^ borrowed value does not live long enough
+LL |
+LL | }
+ | - `x` dropped here while still borrowed
+LL |
+LL | println!("{}", y);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-52534.rs b/tests/ui/nll/issue-52534.rs
new file mode 100644
index 000000000..559d4c859
--- /dev/null
+++ b/tests/ui/nll/issue-52534.rs
@@ -0,0 +1,19 @@
+fn foo(_: impl FnOnce(&u32) -> &u32) {
+}
+
+fn baz(_: impl FnOnce(&u32, u32) -> &u32) {
+}
+
+fn bar() {
+ let x = 22;
+ foo(|a| &x)
+//~^ ERROR does not live long enough
+}
+
+fn foobar() {
+ let y = 22;
+ baz(|first, second| &y)
+//~^ ERROR does not live long enough
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-52534.stderr b/tests/ui/nll/issue-52534.stderr
new file mode 100644
index 000000000..b2b727fd4
--- /dev/null
+++ b/tests/ui/nll/issue-52534.stderr
@@ -0,0 +1,31 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/issue-52534.rs:9:14
+ |
+LL | foo(|a| &x)
+ | - ^ `x` would have to be valid for `'0`...
+ | |
+ | has type `&'0 u32`
+LL |
+LL | }
+ | - ...but `x` will be dropped here, when the function `bar` returns
+ |
+ = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#dangling-references>
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/issue-52534.rs:15:26
+ |
+LL | baz(|first, second| &y)
+ | ----- ^ `y` would have to be valid for `'0`...
+ | |
+ | has type `&'0 u32`
+LL |
+LL | }
+ | - ...but `y` will be dropped here, when the function `foobar` returns
+ |
+ = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#dangling-references>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-52663-span-decl-captured-variable.rs b/tests/ui/nll/issue-52663-span-decl-captured-variable.rs
new file mode 100644
index 000000000..cd1f457a1
--- /dev/null
+++ b/tests/ui/nll/issue-52663-span-decl-captured-variable.rs
@@ -0,0 +1,11 @@
+fn expect_fn<F>(f: F) where F : Fn() {
+ f();
+}
+
+fn main() {
+ {
+ let x = (vec![22], vec![44]);
+ expect_fn(|| drop(x.0));
+ //~^ ERROR cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure [E0507]
+ }
+}
diff --git a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
new file mode 100644
index 000000000..fb61b30f0
--- /dev/null
+++ b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
@@ -0,0 +1,13 @@
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+ --> $DIR/issue-52663-span-decl-captured-variable.rs:8:26
+ |
+LL | let x = (vec![22], vec![44]);
+ | - captured outer variable
+LL | expect_fn(|| drop(x.0));
+ | -- ^^^ move occurs because `x.0` has type `Vec<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/nll/issue-52663-trait-object.rs b/tests/ui/nll/issue-52663-trait-object.rs
new file mode 100644
index 000000000..f6bbb2d14
--- /dev/null
+++ b/tests/ui/nll/issue-52663-trait-object.rs
@@ -0,0 +1,16 @@
+trait Foo { fn get(&self); }
+
+impl<A> Foo for A {
+ fn get(&self) { }
+}
+
+
+
+fn main() {
+ let _ = {
+ let tmp0 = 3;
+ let tmp1 = &tmp0;
+ Box::new(tmp1) as Box<dyn Foo + '_>
+ };
+ //~^^^ ERROR `tmp0` does not live long enough
+}
diff --git a/tests/ui/nll/issue-52663-trait-object.stderr b/tests/ui/nll/issue-52663-trait-object.stderr
new file mode 100644
index 000000000..5cedea6e6
--- /dev/null
+++ b/tests/ui/nll/issue-52663-trait-object.stderr
@@ -0,0 +1,13 @@
+error[E0597]: `tmp0` does not live long enough
+ --> $DIR/issue-52663-trait-object.rs:12:20
+ |
+LL | let tmp1 = &tmp0;
+ | ^^^^^ borrowed value does not live long enough
+LL | Box::new(tmp1) as Box<dyn Foo + '_>
+ | ----------------------------------- borrow later captured here by trait object
+LL | };
+ | - `tmp0` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-52669.rs b/tests/ui/nll/issue-52669.rs
new file mode 100644
index 000000000..e33528ac5
--- /dev/null
+++ b/tests/ui/nll/issue-52669.rs
@@ -0,0 +1,17 @@
+struct A {
+ b: B,
+}
+
+#[derive(Clone)]
+struct B;
+
+fn foo(_: A) {}
+
+fn bar(mut a: A) -> B {
+ a.b = B;
+ foo(a);
+ a.b.clone()
+//~^ ERROR borrow of moved value
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-52669.stderr b/tests/ui/nll/issue-52669.stderr
new file mode 100644
index 000000000..807b95f7e
--- /dev/null
+++ b/tests/ui/nll/issue-52669.stderr
@@ -0,0 +1,14 @@
+error[E0382]: borrow of moved value: `a.b`
+ --> $DIR/issue-52669.rs:13:5
+ |
+LL | fn bar(mut a: A) -> B {
+ | ----- move occurs because `a` has type `A`, which does not implement the `Copy` trait
+LL | a.b = B;
+LL | foo(a);
+ | - value moved here
+LL | a.b.clone()
+ | ^^^^^^^^^^^ value borrowed here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/nll/issue-52742.rs b/tests/ui/nll/issue-52742.rs
new file mode 100644
index 000000000..d3e201b8a
--- /dev/null
+++ b/tests/ui/nll/issue-52742.rs
@@ -0,0 +1,17 @@
+struct Foo<'a, 'b> {
+ x: &'a u32,
+ y: &'b u32,
+}
+
+struct Bar<'b> {
+ z: &'b u32,
+}
+
+impl Foo<'_, '_> {
+ fn take_bar(&mut self, b: Bar<'_>) {
+ self.y = b.z
+ //~^ ERROR
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-52742.stderr b/tests/ui/nll/issue-52742.stderr
new file mode 100644
index 000000000..a79738296
--- /dev/null
+++ b/tests/ui/nll/issue-52742.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-52742.rs:12:9
+ |
+LL | fn take_bar(&mut self, b: Bar<'_>) {
+ | --------- - has type `Bar<'1>`
+ | |
+ | has type `&mut Foo<'_, '2>`
+LL | self.y = b.z
+ | ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-52992.rs b/tests/ui/nll/issue-52992.rs
new file mode 100644
index 000000000..530d1a61b
--- /dev/null
+++ b/tests/ui/nll/issue-52992.rs
@@ -0,0 +1,25 @@
+// Regression test for an NLL-related ICE (#52992) -- computing
+// implied bounds was causing outlives relations that were not
+// properly handled.
+//
+// check-pass
+
+fn main() {}
+
+fn fail<'a>() -> Struct<'a, Generic<()>> {
+ Struct(&Generic(()))
+}
+
+struct Struct<'a, T>(&'a T) where
+ T: Trait + 'a,
+ T::AT: 'a; // only fails with this bound
+
+struct Generic<T>(T);
+
+trait Trait {
+ type AT;
+}
+
+impl<T> Trait for Generic<T> {
+ type AT = T; // only fails with a generic AT
+}
diff --git a/tests/ui/nll/issue-53040.rs b/tests/ui/nll/issue-53040.rs
new file mode 100644
index 000000000..e4ee6e913
--- /dev/null
+++ b/tests/ui/nll/issue-53040.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let mut v: Vec<()> = Vec::new();
+ || &mut v;
+//~^ ERROR captured variable cannot escape `FnMut` closure body
+}
diff --git a/tests/ui/nll/issue-53040.stderr b/tests/ui/nll/issue-53040.stderr
new file mode 100644
index 000000000..87ffe9b1a
--- /dev/null
+++ b/tests/ui/nll/issue-53040.stderr
@@ -0,0 +1,17 @@
+error: captured variable cannot escape `FnMut` closure body
+ --> $DIR/issue-53040.rs:3:8
+ |
+LL | let mut v: Vec<()> = Vec::new();
+ | ----- variable defined here
+LL | || &mut v;
+ | - ^^^^^-
+ | | | |
+ | | | variable captured here
+ | | returns a reference to a captured variable which escapes the closure body
+ | inferred to be a `FnMut` closure
+ |
+ = note: `FnMut` closures only have access to their captured variables while they are executing...
+ = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-53119.rs b/tests/ui/nll/issue-53119.rs
new file mode 100644
index 000000000..03c9c071c
--- /dev/null
+++ b/tests/ui/nll/issue-53119.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+use std::ops::Deref;
+
+pub struct TypeFieldIterator<'a, T: 'a> {
+ _t: &'a T,
+}
+
+pub struct Type<Id, T> {
+ _types: Vec<(Id, T)>,
+}
+
+impl<'a, Id: 'a, T> Iterator for TypeFieldIterator<'a, T>
+where T: Deref<Target = Type<Id, T>> {
+ type Item = &'a (Id, T);
+
+ fn next(&mut self) -> Option<&'a (Id, T)> {
+ || self.next();
+ None
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-53123-raw-pointer-cast.rs b/tests/ui/nll/issue-53123-raw-pointer-cast.rs
new file mode 100644
index 000000000..941c9eeb4
--- /dev/null
+++ b/tests/ui/nll/issue-53123-raw-pointer-cast.rs
@@ -0,0 +1,26 @@
+// run-pass
+
+#![allow(unused_variables)]
+
+pub trait TryTransform {
+ fn try_transform<F>(self, f: F)
+ where
+ Self: Sized,
+ F: FnOnce(Self);
+}
+
+impl<'a, T> TryTransform for &'a mut T {
+ fn try_transform<F>(self, f: F)
+ where
+ // The bug was that `Self: Sized` caused the lifetime of `this` to "extend" for all
+ // of 'a instead of only lasting as long as the binding is used (for just that line).
+ Self: Sized,
+ F: FnOnce(Self),
+ {
+ let this: *mut T = self as *mut T;
+ f(self);
+ }
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/issue-53570.rs b/tests/ui/nll/issue-53570.rs
new file mode 100644
index 000000000..35860ba9c
--- /dev/null
+++ b/tests/ui/nll/issue-53570.rs
@@ -0,0 +1,32 @@
+// Regression test for #53570. Here, we need to propagate that `T: 'a`
+// but in some versions of NLL we were propagating a stronger
+// requirement that `T: 'static`. This arose because we actually had
+// to propagate both that `T: 'a` but also `T: 'b` where `'b` is the
+// higher-ranked lifetime that appears in the type of the closure
+// parameter `x` -- since `'b` cannot be expressed in the caller's
+// space, that got promoted th `'static`.
+//
+// check-pass
+
+use std::cell::{RefCell, Ref};
+
+trait AnyVec<'a> {
+}
+
+trait GenericVec<T> {
+ fn unwrap<'a, 'b>(vec: &'b dyn AnyVec<'a>) -> &'b [T] where T: 'a;
+}
+
+struct Scratchpad<'a> {
+ buffers: RefCell<Box<dyn AnyVec<'a>>>,
+}
+
+impl<'a> Scratchpad<'a> {
+ fn get<T: GenericVec<T>>(&self) -> Ref<[T]>
+ where T: 'a
+ {
+ Ref::map(self.buffers.borrow(), |x| T::unwrap(x.as_ref()))
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-53773.rs b/tests/ui/nll/issue-53773.rs
new file mode 100644
index 000000000..ed971b6ce
--- /dev/null
+++ b/tests/ui/nll/issue-53773.rs
@@ -0,0 +1,47 @@
+struct Archive;
+struct ArchiveIterator<'a> {
+ x: &'a Archive,
+}
+struct ArchiveChild<'a> {
+ x: &'a Archive,
+}
+
+struct A {
+ raw: &'static mut Archive,
+}
+struct Iter<'a> {
+ raw: &'a mut ArchiveIterator<'a>,
+}
+struct C<'a> {
+ raw: &'a mut ArchiveChild<'a>,
+}
+
+impl A {
+ pub fn iter(&self) -> Iter<'_> {
+ panic!()
+ }
+}
+impl Drop for A {
+ fn drop(&mut self) {}
+}
+impl<'a> Drop for C<'a> {
+ fn drop(&mut self) {}
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = C<'a>;
+ fn next(&mut self) -> Option<C<'a>> {
+ panic!()
+ }
+}
+
+fn error(archive: &A) {
+ let mut members: Vec<&mut ArchiveChild<'_>> = vec![];
+ for child in archive.iter() {
+ members.push(child.raw);
+ //~^ ERROR borrow may still be in use when destructor runs [E0713]
+ }
+ members.len();
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-53773.stderr b/tests/ui/nll/issue-53773.stderr
new file mode 100644
index 000000000..90cba2a14
--- /dev/null
+++ b/tests/ui/nll/issue-53773.stderr
@@ -0,0 +1,14 @@
+error[E0713]: borrow may still be in use when destructor runs
+ --> $DIR/issue-53773.rs:41:22
+ |
+LL | members.push(child.raw);
+ | -------------^^^^^^^^^- borrow later used here
+LL |
+LL | }
+ | - here, drop of `child` needs exclusive access to `*child.raw`, because the type `C<'_>` implements the `Drop` trait
+ |
+ = note: consider using a `let` binding to create a longer lived value
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0713`.
diff --git a/tests/ui/nll/issue-53807.rs b/tests/ui/nll/issue-53807.rs
new file mode 100644
index 000000000..d494f7e15
--- /dev/null
+++ b/tests/ui/nll/issue-53807.rs
@@ -0,0 +1,8 @@
+pub fn main(){
+ let maybe = Some(vec![true, true]);
+ loop {
+ if let Some(thing) = maybe {
+//~^ ERROR use of moved value
+ }
+ }
+}
diff --git a/tests/ui/nll/issue-53807.stderr b/tests/ui/nll/issue-53807.stderr
new file mode 100644
index 000000000..d8f58b591
--- /dev/null
+++ b/tests/ui/nll/issue-53807.stderr
@@ -0,0 +1,15 @@
+error[E0382]: use of moved value
+ --> $DIR/issue-53807.rs:4: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/nll/issue-54189.rs b/tests/ui/nll/issue-54189.rs
new file mode 100644
index 000000000..70aecc384
--- /dev/null
+++ b/tests/ui/nll/issue-54189.rs
@@ -0,0 +1,6 @@
+fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
+//~^ ERROR binding for associated type `Output` references lifetime `'r`
+
+fn main() {
+ let f = bug();
+}
diff --git a/tests/ui/nll/issue-54189.stderr b/tests/ui/nll/issue-54189.stderr
new file mode 100644
index 000000000..4787abd49
--- /dev/null
+++ b/tests/ui/nll/issue-54189.stderr
@@ -0,0 +1,9 @@
+error[E0582]: binding for associated type `Output` references lifetime `'r`, which does not appear in the trait input types
+ --> $DIR/issue-54189.rs:1:35
+ |
+LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0582`.
diff --git a/tests/ui/nll/issue-54382-use-span-of-tail-of-block.rs b/tests/ui/nll/issue-54382-use-span-of-tail-of-block.rs
new file mode 100644
index 000000000..312e6dce8
--- /dev/null
+++ b/tests/ui/nll/issue-54382-use-span-of-tail-of-block.rs
@@ -0,0 +1,29 @@
+fn main() {
+ {
+ let mut _thing1 = D(Box::new("thing1"));
+ {
+ let _thing2 = D("thing2");
+ side_effects();
+ D("other").next(&_thing1)
+//~^ ERROR does not live long enough
+ }
+ }
+
+ ;
+}
+
+#[derive(Debug)]
+struct D<T: std::fmt::Debug>(T);
+
+impl<T: std::fmt::Debug> Drop for D<T> {
+ fn drop(&mut self) {
+ println!("dropping {:?})", self);
+ }
+}
+
+impl<T: std::fmt::Debug> D<T> {
+ fn next<U: std::fmt::Debug>(&self, _other: U) -> D<U> { D(_other) }
+ fn end(&self) { }
+}
+
+fn side_effects() { }
diff --git a/tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr b/tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr
new file mode 100644
index 000000000..d8f43cbc9
--- /dev/null
+++ b/tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr
@@ -0,0 +1,23 @@
+error[E0597]: `_thing1` does not live long enough
+ --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29
+ |
+LL | D("other").next(&_thing1)
+ | ----------------^^^^^^^^-
+ | | |
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+...
+LL | }
+ | - `_thing1` dropped here while still borrowed
+LL |
+LL | ;
+ | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | D("other").next(&_thing1);
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-54556-niconii.rs b/tests/ui/nll/issue-54556-niconii.rs
new file mode 100644
index 000000000..cae389e8c
--- /dev/null
+++ b/tests/ui/nll/issue-54556-niconii.rs
@@ -0,0 +1,31 @@
+// This is a reduction of a concrete test illustrating a case that was
+// annoying to Rust developer niconii (see comment thread on #21114).
+//
+// With resolving issue #54556, pnkfelix hopes that the new diagnostic
+// output produced by NLL helps to *explain* the semantic significance
+// of temp drop order, and thus why inserting a semi-colon after the
+// `if let` expression in `main` works.
+
+struct Mutex;
+struct MutexGuard<'a>(&'a Mutex);
+
+impl Drop for Mutex { fn drop(&mut self) { println!("Mutex::drop"); } }
+impl<'a> Drop for MutexGuard<'a> { fn drop(&mut self) { println!("MutexGuard::drop"); } }
+
+impl Mutex {
+ fn lock(&self) -> Result<MutexGuard, ()> { Ok(MutexGuard(self)) }
+}
+
+fn main() {
+ let counter = Mutex;
+
+ if let Ok(_) = counter.lock() { } //~ ERROR does not live long enough
+
+ // With this code as written, the dynamic semantics here implies
+ // that `Mutex::drop` for `counter` runs *before*
+ // `MutexGuard::drop`, which would be unsound since `MutexGuard`
+ // still has a reference to `counter`.
+ //
+ // The goal of #54556 is to explain that within a compiler
+ // diagnostic.
+}
diff --git a/tests/ui/nll/issue-54556-niconii.stderr b/tests/ui/nll/issue-54556-niconii.stderr
new file mode 100644
index 000000000..a8e1edc54
--- /dev/null
+++ b/tests/ui/nll/issue-54556-niconii.stderr
@@ -0,0 +1,23 @@
+error[E0597]: `counter` does not live long enough
+ --> $DIR/issue-54556-niconii.rs:22:20
+ |
+LL | if let Ok(_) = counter.lock() { }
+ | ^^^^^^^^^^^^^^
+ | |
+ | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+...
+LL | }
+ | -
+ | |
+ | `counter` dropped here while still borrowed
+ | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Result<MutexGuard<'_>, ()>`
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | if let Ok(_) = counter.lock() { };
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-54556-stephaneyfx.rs b/tests/ui/nll/issue-54556-stephaneyfx.rs
new file mode 100644
index 000000000..b758228e4
--- /dev/null
+++ b/tests/ui/nll/issue-54556-stephaneyfx.rs
@@ -0,0 +1,35 @@
+// This is a reduction of a concrete test illustrating a case that was
+// annoying to Rust developer stephaneyfx (see issue #46413).
+//
+// With resolving issue #54556, pnkfelix hopes that the new diagnostic
+// output produced by NLL helps to *explain* the semantic significance
+// of temp drop order, and thus why storing the result in `x` and then
+// returning `x` works.
+
+pub struct Statement;
+
+pub struct Rows<'stmt>(&'stmt Statement);
+
+impl<'stmt> Drop for Rows<'stmt> {
+ fn drop(&mut self) {}
+}
+
+impl<'stmt> Iterator for Rows<'stmt> {
+ type Item = String;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+fn get_names() -> Option<String> {
+ let stmt = Statement;
+ let rows = Rows(&stmt); //~ ERROR does not live long enough
+ rows.map(|row| row).next()
+ // let x = rows.map(|row| row).next();
+ // x
+ //
+ // Removing the map works too as does removing the Drop impl.
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-54556-stephaneyfx.stderr b/tests/ui/nll/issue-54556-stephaneyfx.stderr
new file mode 100644
index 000000000..036a7a0ab
--- /dev/null
+++ b/tests/ui/nll/issue-54556-stephaneyfx.stderr
@@ -0,0 +1,24 @@
+error[E0597]: `stmt` does not live long enough
+ --> $DIR/issue-54556-stephaneyfx.rs:27:21
+ |
+LL | let rows = Rows(&stmt);
+ | ^^^^^ borrowed value does not live long enough
+LL | rows.map(|row| row).next()
+ | ------------------- a temporary with access to the borrow is created here ...
+...
+LL | }
+ | -
+ | |
+ | `stmt` dropped here while still borrowed
+ | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Map<Rows<'_>, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:19]>`
+ |
+ = note: the temporary is part of an expression at the end of a block;
+ consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
+help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
+ |
+LL | let x = rows.map(|row| row).next(); x
+ | +++++++ +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.rs b/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.rs
new file mode 100644
index 000000000..2935caaf2
--- /dev/null
+++ b/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.rs
@@ -0,0 +1,23 @@
+fn main() {
+ {
+ let mut _thing1 = D(Box::new("thing1"));
+ // D("other").next(&_thing1).end()
+ D(&_thing1).end() //~ ERROR does not live long enough
+ }
+
+ ;
+}
+
+#[derive(Debug)]
+struct D<T: std::fmt::Debug>(T);
+
+impl<T: std::fmt::Debug> Drop for D<T> {
+ fn drop(&mut self) {
+ println!("dropping {:?})", self);
+ }
+}
+
+impl<T: std::fmt::Debug> D<T> {
+ fn next<U: std::fmt::Debug>(&self, _other: U) -> D<U> { D(_other) }
+ fn end(&self) { }
+}
diff --git a/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr b/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr
new file mode 100644
index 000000000..92f5ffdf3
--- /dev/null
+++ b/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr
@@ -0,0 +1,22 @@
+error[E0597]: `_thing1` does not live long enough
+ --> $DIR/issue-54556-temps-in-tail-diagnostic.rs:5:11
+ |
+LL | D(&_thing1).end()
+ | --^^^^^^^^-
+ | | |
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+LL | }
+ | - `_thing1` dropped here while still borrowed
+LL |
+LL | ;
+ | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | D(&_thing1).end();
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-54556-used-vs-unused-tails.rs b/tests/ui/nll/issue-54556-used-vs-unused-tails.rs
new file mode 100644
index 000000000..a111acca6
--- /dev/null
+++ b/tests/ui/nll/issue-54556-used-vs-unused-tails.rs
@@ -0,0 +1,56 @@
+// This test case is exploring the space of how blocks with tail
+// expressions and statements can be composed, trying to keep each
+// case on one line so that we can compare them via a vertical scan
+// with the human eye.
+
+// Each comment on the right side of the line is summarizing the
+// expected suggestion from the diagnostic for issue #54556.
+
+fn main() {
+ { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;`
+//~^ ERROR does not live long enough
+
+ { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } } ; // suggest `;`
+//~^ ERROR does not live long enough
+
+ { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() }; } // suggest `;`
+//~^ ERROR does not live long enough
+
+ let _ = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;`
+//~^ ERROR does not live long enough
+
+ let _u = { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } ; // suggest `;`
+//~^ ERROR does not live long enough
+
+ let _x = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x`
+//~^ ERROR does not live long enough
+ let _x = { let mut _t1 = D(Box::new("t1")); let x = D(&_t1).end(); x } ; // no error
+
+ let mut _y;
+ _y = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x`
+//~^ ERROR does not live long enough
+ _y = { let mut _t1 = D(Box::new("t1")); let x = D(&_t1).end(); x } ; // no error
+}
+
+fn f_param_ref(_t1: D<Box<&'static str>>) { D(&_t1).unit() } // no error
+
+fn f_local_ref() { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } // suggest `;`
+//~^ ERROR does not live long enough
+
+fn f() -> String { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } // `let x = ...; x`
+//~^ ERROR does not live long enough
+
+#[derive(Debug)]
+struct D<T: std::fmt::Debug>(T);
+
+impl<T: std::fmt::Debug> Drop for D<T> {
+ fn drop(&mut self) {
+ println!("dropping {:?})", self);
+ }
+}
+
+impl<T: std::fmt::Debug> D<T> {
+ fn next<U: std::fmt::Debug>(&self, _other: U) -> D<U> { D(_other) }
+ fn end(&self) -> String { format!("End({:?})", self.0) }
+ fn unit(&self) { }
+}
diff --git a/tests/ui/nll/issue-54556-used-vs-unused-tails.stderr b/tests/ui/nll/issue-54556-used-vs-unused-tails.stderr
new file mode 100644
index 000000000..25226e296
--- /dev/null
+++ b/tests/ui/nll/issue-54556-used-vs-unused-tails.stderr
@@ -0,0 +1,146 @@
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:10:55
+ |
+LL | { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;`
+ | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | { let mut _t1 = D(Box::new("t1")); D(&_t1).end(); } ; // suggest `;`
+ | +
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:13:55
+ |
+LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } } ; // suggest `;`
+ | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end(); } } ; // suggest `;`
+ | +
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:16:55
+ |
+LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() }; } // suggest `;`
+ | --^^^^- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end(); }; } // suggest `;`
+ | +
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:19:55
+ |
+LL | let _ = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;`
+ | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | let _ = { let mut _t1 = D(Box::new("t1")); D(&_t1).end(); } ; // suggest `;`
+ | +
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:22:55
+ |
+LL | let _u = { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } ; // suggest `;`
+ | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | let _u = { let mut _t1 = D(Box::new("t1")); D(&_t1).unit(); } ; // suggest `;`
+ | +
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:25:55
+ |
+LL | let _x = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x`
+ | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+ = note: the temporary is part of an expression at the end of a block;
+ consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
+help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
+ |
+LL | let _x = { let mut _t1 = D(Box::new("t1")); let x = D(&_t1).end(); x } ; // `let x = ...; x`
+ | +++++++ +++
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:30:55
+ |
+LL | _y = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x`
+ | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+ = note: the temporary is part of an expression at the end of a block;
+ consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
+help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
+ |
+LL | _y = { let mut _t1 = D(Box::new("t1")); let x = D(&_t1).end(); x } ; // `let x = ...; x`
+ | +++++++ +++
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:37:55
+ |
+LL | fn f_local_ref() { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } // suggest `;`
+ | --^^^^- -
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
+ |
+LL | fn f_local_ref() { let mut _t1 = D(Box::new("t1")); D(&_t1).unit(); } // suggest `;`
+ | +
+
+error[E0597]: `_t1` does not live long enough
+ --> $DIR/issue-54556-used-vs-unused-tails.rs:40:55
+ |
+LL | fn f() -> String { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } // `let x = ...; x`
+ | --^^^^- -
+ | | | |
+ | | | `_t1` dropped here while still borrowed
+ | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
+ |
+ = note: the temporary is part of an expression at the end of a block;
+ consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
+help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
+ |
+LL | fn f() -> String { let mut _t1 = D(Box::new("t1")); let x = D(&_t1).end(); x } // `let x = ...; x`
+ | +++++++ +++
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-54556-wrap-it-up.rs b/tests/ui/nll/issue-54556-wrap-it-up.rs
new file mode 100644
index 000000000..11dbef0d8
--- /dev/null
+++ b/tests/ui/nll/issue-54556-wrap-it-up.rs
@@ -0,0 +1,28 @@
+// This is testing how the diagnostic from issue #54556 behaves when
+// the destructor code is attached to a place held in a field of the
+// temporary being dropped.
+//
+// Eventually it would be nice if the diagnostic would actually report
+// that specific place and its type that implements the `Drop` trait.
+// But for the short term, it is acceptable to just print out the
+// whole type of the temporary.
+
+#![allow(warnings)]
+
+struct Wrap<'p> { p: &'p mut i32 }
+
+impl<'p> Drop for Wrap<'p> {
+ fn drop(&mut self) {
+ *self.p += 1;
+ }
+}
+
+struct Foo<'p> { a: String, b: Wrap<'p> }
+
+fn main() {
+ let mut x = 0;
+ let wrap = Wrap { p: &mut x };
+ let s = String::from("str");
+ let foo = Foo { a: s, b: wrap };
+ x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
+}
diff --git a/tests/ui/nll/issue-54556-wrap-it-up.stderr b/tests/ui/nll/issue-54556-wrap-it-up.stderr
new file mode 100644
index 000000000..9f27fac15
--- /dev/null
+++ b/tests/ui/nll/issue-54556-wrap-it-up.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/issue-54556-wrap-it-up.rs:27:5
+ |
+LL | let wrap = Wrap { p: &mut x };
+ | ------ borrow of `x` occurs here
+...
+LL | x = 1;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | }
+ | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.rs b/tests/ui/nll/issue-54779-anon-static-lifetime.rs
new file mode 100644
index 000000000..260b6b109
--- /dev/null
+++ b/tests/ui/nll/issue-54779-anon-static-lifetime.rs
@@ -0,0 +1,49 @@
+// Regression test for #54779, checks if the diagnostics are confusing.
+
+trait DebugWith<Cx: ?Sized> {
+ fn debug_with<'me>(&'me self, cx: &'me Cx) -> DebugCxPair<'me, Self, Cx> {
+ DebugCxPair { value: self, cx }
+ }
+
+ fn fmt_with(&self, cx: &Cx, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
+}
+
+struct DebugCxPair<'me, Value: ?Sized, Cx: ?Sized>
+where
+ Value: DebugWith<Cx>,
+{
+ value: &'me Value,
+ cx: &'me Cx,
+}
+
+trait DebugContext {}
+
+struct Foo {
+ bar: Bar,
+}
+
+impl DebugWith<dyn DebugContext> for Foo {
+ fn fmt_with(
+ &self,
+ cx: &dyn DebugContext,
+ fmt: &mut std::fmt::Formatter<'_>,
+ ) -> std::fmt::Result {
+ let Foo { bar } = self;
+ bar.debug_with(cx); //~ ERROR: lifetime may not live long enough
+ Ok(())
+ }
+}
+
+struct Bar {}
+
+impl DebugWith<dyn DebugContext> for Bar {
+ fn fmt_with(
+ &self,
+ cx: &dyn DebugContext,
+ fmt: &mut std::fmt::Formatter<'_>,
+ ) -> std::fmt::Result {
+ Ok(())
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
new file mode 100644
index 000000000..64ad7a21a
--- /dev/null
+++ b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-54779-anon-static-lifetime.rs:32:24
+ |
+LL | cx: &dyn DebugContext,
+ | - let's call the lifetime of this reference `'1`
+...
+LL | bar.debug_with(cx);
+ | ^^ cast requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-54943-3.rs b/tests/ui/nll/issue-54943-3.rs
new file mode 100644
index 000000000..077eb1563
--- /dev/null
+++ b/tests/ui/nll/issue-54943-3.rs
@@ -0,0 +1,19 @@
+// check-pass
+// FIXME(#54943) This test targets the scenario where proving the WF requirements requires
+// knowing the value of the `_` type present in the user type annotation - unfortunately, figuring
+// out the value of that `_` requires type-checking the surrounding code, but that code is dead,
+// so our NLL region checker doesn't have access to it. This test should actually fail to compile.
+
+#![allow(warnings)]
+
+use std::fmt::Debug;
+
+fn foo<T: 'static + Debug>(_: T) { }
+
+fn bar<'a>() {
+ return;
+
+ let _x = foo::<Vec<_>>(Vec::<&'a u32>::new());
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-54943.rs b/tests/ui/nll/issue-54943.rs
new file mode 100644
index 000000000..85722300b
--- /dev/null
+++ b/tests/ui/nll/issue-54943.rs
@@ -0,0 +1,10 @@
+fn foo<T: 'static>() { }
+
+fn boo<'a>() {
+ return;
+
+ let x = foo::<&'a u32>();
+ //~^ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-54943.stderr b/tests/ui/nll/issue-54943.stderr
new file mode 100644
index 000000000..59be0f983
--- /dev/null
+++ b/tests/ui/nll/issue-54943.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-54943.rs:6:13
+ |
+LL | fn boo<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | let x = foo::<&'a u32>();
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-55288.rs b/tests/ui/nll/issue-55288.rs
new file mode 100644
index 000000000..aab2dc267
--- /dev/null
+++ b/tests/ui/nll/issue-55288.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+struct Slice(&'static [&'static [u8]]);
+
+static MAP: Slice = Slice(&[
+ b"CloseEvent" as &'static [u8],
+]);
+
+fn main() {}
diff --git a/tests/ui/nll/issue-55344.rs b/tests/ui/nll/issue-55344.rs
new file mode 100644
index 000000000..20f18dc46
--- /dev/null
+++ b/tests/ui/nll/issue-55344.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+#![deny(unused_mut)]
+
+pub fn foo() {
+ return;
+
+ let mut v = 0;
+ assert_eq!(v, 0);
+ v = 1;
+ assert_eq!(v, 1);
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-55394.rs b/tests/ui/nll/issue-55394.rs
new file mode 100644
index 000000000..f813d1c91
--- /dev/null
+++ b/tests/ui/nll/issue-55394.rs
@@ -0,0 +1,13 @@
+struct Bar;
+
+struct Foo<'s> {
+ bar: &'s mut Bar,
+}
+
+impl Foo<'_> {
+ fn new(bar: &mut Bar) -> Self {
+ Foo { bar } //~ERROR
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/issue-55394.stderr b/tests/ui/nll/issue-55394.stderr
new file mode 100644
index 000000000..24b8c84b4
--- /dev/null
+++ b/tests/ui/nll/issue-55394.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-55394.rs:9:9
+ |
+LL | fn new(bar: &mut Bar) -> Self {
+ | - ---- return type is Foo<'2>
+ | |
+ | let's call the lifetime of this reference `'1`
+LL | Foo { bar }
+ | ^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-55401.rs b/tests/ui/nll/issue-55401.rs
new file mode 100644
index 000000000..fc45824e9
--- /dev/null
+++ b/tests/ui/nll/issue-55401.rs
@@ -0,0 +1,6 @@
+fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+ let (ref y, _z): (&'a u32, u32) = (&22, 44);
+ *y //~ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-55401.stderr b/tests/ui/nll/issue-55401.stderr
new file mode 100644
index 000000000..4f797f26a
--- /dev/null
+++ b/tests/ui/nll/issue-55401.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-55401.rs:3:5
+ |
+LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | let (ref y, _z): (&'a u32, u32) = (&22, 44);
+LL | *y
+ | ^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-55511.rs b/tests/ui/nll/issue-55511.rs
new file mode 100644
index 000000000..7dfa9c7bc
--- /dev/null
+++ b/tests/ui/nll/issue-55511.rs
@@ -0,0 +1,19 @@
+#![warn(indirect_structural_match)]
+use std::cell::Cell;
+trait Foo<'a> {
+ const C: Option<Cell<&'a u32>>;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: Option<Cell<&'a u32>> = None;
+}
+
+fn main() {
+ let a = 22;
+ let b = Some(Cell::new(&a));
+ //~^ ERROR `a` does not live long enough [E0597]
+ match b {
+ <() as Foo<'static>>::C => { }
+ _ => { }
+ }
+}
diff --git a/tests/ui/nll/issue-55511.stderr b/tests/ui/nll/issue-55511.stderr
new file mode 100644
index 000000000..bf3e58e8c
--- /dev/null
+++ b/tests/ui/nll/issue-55511.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `a` does not live long enough
+ --> $DIR/issue-55511.rs:13:28
+ |
+LL | let b = Some(Cell::new(&a));
+ | ^^ borrowed value does not live long enough
+...
+LL | <() as Foo<'static>>::C => { }
+ | ----------------------- type annotation requires that `a` is borrowed for `'static`
+...
+LL | }
+ | - `a` 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/nll/issue-55651.rs b/tests/ui/nll/issue-55651.rs
new file mode 100644
index 000000000..75ba48271
--- /dev/null
+++ b/tests/ui/nll/issue-55651.rs
@@ -0,0 +1,28 @@
+// check-pass
+
+use std::mem::ManuallyDrop;
+
+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;
+ 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/nll/issue-55825-const-fn.rs b/tests/ui/nll/issue-55825-const-fn.rs
new file mode 100644
index 000000000..8aaa19813
--- /dev/null
+++ b/tests/ui/nll/issue-55825-const-fn.rs
@@ -0,0 +1,8 @@
+// Regression test for issue #55825
+// Tests that we don't emit a spurious warning in NLL mode
+
+// check-pass
+
+const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+
+fn main() { }
diff --git a/tests/ui/nll/issue-55850.rs b/tests/ui/nll/issue-55850.rs
new file mode 100644
index 000000000..e6279bd02
--- /dev/null
+++ b/tests/ui/nll/issue-55850.rs
@@ -0,0 +1,35 @@
+#![allow(unused_mut)]
+#![feature(generators, generator_trait)]
+
+use std::marker::Unpin;
+use std::ops::Generator;
+use std::ops::GeneratorState::Yielded;
+use std::pin::Pin;
+
+pub struct GenIter<G>(G);
+
+impl <G> Iterator for GenIter<G>
+where
+ G: Generator + Unpin,
+{
+ type Item = G::Yield;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match Pin::new(&mut self.0).resume(()) {
+ Yielded(y) => Some(y),
+ _ => None
+ }
+ }
+}
+
+fn bug<'a>() -> impl Iterator<Item = &'a str> {
+ GenIter(move || {
+ let mut s = String::new();
+ yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515]
+ //~| ERROR borrow may still be in use when generator yields
+ })
+}
+
+fn main() {
+ bug();
+}
diff --git a/tests/ui/nll/issue-55850.stderr b/tests/ui/nll/issue-55850.stderr
new file mode 100644
index 000000000..86a8cdc42
--- /dev/null
+++ b/tests/ui/nll/issue-55850.stderr
@@ -0,0 +1,19 @@
+error[E0515]: cannot yield value referencing local variable `s`
+ --> $DIR/issue-55850.rs:28:9
+ |
+LL | yield &s[..]
+ | ^^^^^^^-^^^^
+ | | |
+ | | `s` is borrowed here
+ | yields a value referencing data owned by the current function
+
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/issue-55850.rs:28:16
+ |
+LL | yield &s[..]
+ | -------^---- possible yield occurs here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0515, E0626.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/tests/ui/nll/issue-57100.rs b/tests/ui/nll/issue-57100.rs
new file mode 100644
index 000000000..f15929334
--- /dev/null
+++ b/tests/ui/nll/issue-57100.rs
@@ -0,0 +1,67 @@
+#![allow(unused)]
+
+
+// This tests the error messages for borrows of union fields when the unions are embedded in other
+// structs or unions.
+
+#[derive(Clone, Copy, Default)]
+struct Leaf {
+ l1_u8: u8,
+ l2_u8: u8,
+}
+
+#[derive(Clone, Copy)]
+union First {
+ f1_leaf: Leaf,
+ f2_leaf: Leaf,
+ f3_union: Second,
+}
+
+#[derive(Clone, Copy)]
+union Second {
+ s1_leaf: Leaf,
+ s2_leaf: Leaf,
+}
+
+struct Root {
+ r1_u8: u8,
+ r2_union: First,
+}
+
+// Borrow a different field of the nested union.
+fn nested_union() {
+ unsafe {
+ let mut r = Root {
+ r1_u8: 3,
+ r2_union: First { f3_union: Second { s2_leaf: Leaf { l1_u8: 8, l2_u8: 4 } } }
+ };
+
+ let mref = &mut r.r2_union.f3_union.s1_leaf.l1_u8;
+ // ^^^^^^^
+ *mref = 22;
+ let nref = &r.r2_union.f3_union.s2_leaf.l1_u8;
+ // ^^^^^^^
+ //~^^ ERROR cannot borrow `r.r2_union.f3_union` (via `r.r2_union.f3_union.s2_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f3_union.s1_leaf.l1_u8`) [E0502]
+ println!("{} {}", mref, nref)
+ }
+}
+
+// Borrow a different field of the first union.
+fn first_union() {
+ unsafe {
+ let mut r = Root {
+ r1_u8: 3,
+ r2_union: First { f3_union: Second { s2_leaf: Leaf { l1_u8: 8, l2_u8: 4 } } }
+ };
+
+ let mref = &mut r.r2_union.f2_leaf.l1_u8;
+ // ^^^^^^^
+ *mref = 22;
+ let nref = &r.r2_union.f1_leaf.l1_u8;
+ // ^^^^^^^
+ //~^^ ERROR cannot borrow `r.r2_union` (via `r.r2_union.f1_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f2_leaf.l1_u8`) [E0502]
+ println!("{} {}", mref, nref)
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-57100.stderr b/tests/ui/nll/issue-57100.stderr
new file mode 100644
index 000000000..523c3e8d0
--- /dev/null
+++ b/tests/ui/nll/issue-57100.stderr
@@ -0,0 +1,31 @@
+error[E0502]: cannot borrow `r.r2_union.f3_union` (via `r.r2_union.f3_union.s2_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f3_union.s1_leaf.l1_u8`)
+ --> $DIR/issue-57100.rs:42:20
+ |
+LL | let mref = &mut r.r2_union.f3_union.s1_leaf.l1_u8;
+ | -------------------------------------- mutable borrow occurs here (via `r.r2_union.f3_union.s1_leaf.l1_u8`)
+...
+LL | let nref = &r.r2_union.f3_union.s2_leaf.l1_u8;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow of `r.r2_union.f3_union.s2_leaf.l1_u8` -- which overlaps with `r.r2_union.f3_union.s1_leaf.l1_u8` -- occurs here
+...
+LL | println!("{} {}", mref, nref)
+ | ---- mutable borrow later used here
+ |
+ = note: `r.r2_union.f3_union.s2_leaf.l1_u8` is a field of the union `Second`, so it overlaps the field `r.r2_union.f3_union.s1_leaf.l1_u8`
+
+error[E0502]: cannot borrow `r.r2_union` (via `r.r2_union.f1_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f2_leaf.l1_u8`)
+ --> $DIR/issue-57100.rs:60:20
+ |
+LL | let mref = &mut r.r2_union.f2_leaf.l1_u8;
+ | ----------------------------- mutable borrow occurs here (via `r.r2_union.f2_leaf.l1_u8`)
+...
+LL | let nref = &r.r2_union.f1_leaf.l1_u8;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow of `r.r2_union.f1_leaf.l1_u8` -- which overlaps with `r.r2_union.f2_leaf.l1_u8` -- occurs here
+...
+LL | println!("{} {}", mref, nref)
+ | ---- mutable borrow later used here
+ |
+ = note: `r.r2_union.f1_leaf.l1_u8` is a field of the union `First`, so it overlaps the field `r.r2_union.f2_leaf.l1_u8`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/nll/issue-57265-return-type-wf-check.rs b/tests/ui/nll/issue-57265-return-type-wf-check.rs
new file mode 100644
index 000000000..8fb8351ce
--- /dev/null
+++ b/tests/ui/nll/issue-57265-return-type-wf-check.rs
@@ -0,0 +1,24 @@
+use std::any::Any;
+
+#[derive(Debug, Clone)]
+struct S<T: 'static>(T);
+
+// S<&'a T> is in the return type, so we get an implied bound
+// &'a T: 'static
+fn foo<'a, T>(x: &'a T) -> (S<&'a T>, Box<dyn Any + 'static>) {
+ let y = S(x);
+
+ let z = Box::new(y.clone()) as Box<dyn Any + 'static>;
+ (y, z)
+}
+
+fn main() {
+ let x = 5;
+
+ // Check that we require that the argument is of type `&'static String`,
+ // so that the return type is well-formed.
+ let (_, z) = foo(&"hello".to_string());
+ //~^ ERROR temporary value dropped while borrowed
+
+ println!("{:?}", z.downcast_ref::<S<&'static String>>());
+}
diff --git a/tests/ui/nll/issue-57265-return-type-wf-check.stderr b/tests/ui/nll/issue-57265-return-type-wf-check.stderr
new file mode 100644
index 000000000..bb45575fa
--- /dev/null
+++ b/tests/ui/nll/issue-57265-return-type-wf-check.stderr
@@ -0,0 +1,12 @@
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/issue-57265-return-type-wf-check.rs:20:23
+ |
+LL | let (_, z) = foo(&"hello".to_string());
+ | -----^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary value which is freed while still in use
+ | argument requires that borrow lasts for `'static`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/nll/issue-57280-1-flipped.rs b/tests/ui/nll/issue-57280-1-flipped.rs
new file mode 100644
index 000000000..ad4b8dcfd
--- /dev/null
+++ b/tests/ui/nll/issue-57280-1-flipped.rs
@@ -0,0 +1,23 @@
+// This test should compile, as the lifetimes
+// in matches don't really matter.
+//
+// We currently use contravariance when checking the
+// type of match arms.
+
+trait Foo<'a> {
+ const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: &'a u32 = &22;
+}
+
+fn foo<'a>(x: &'static u32) {
+ match x {
+ <() as Foo<'a>>::C => { }
+ //~^ ERROR lifetime may not live long enough
+ &_ => { }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-57280-1-flipped.stderr b/tests/ui/nll/issue-57280-1-flipped.stderr
new file mode 100644
index 000000000..7a2135a2a
--- /dev/null
+++ b/tests/ui/nll/issue-57280-1-flipped.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-57280-1-flipped.rs:17:9
+ |
+LL | fn foo<'a>(x: &'static u32) {
+ | -- lifetime `'a` defined here
+LL | match x {
+LL | <() as Foo<'a>>::C => { }
+ | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-57280-1.rs b/tests/ui/nll/issue-57280-1.rs
new file mode 100644
index 000000000..b8979624e
--- /dev/null
+++ b/tests/ui/nll/issue-57280-1.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+trait Foo<'a> {
+ const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: &'a u32 = &22;
+}
+
+fn foo() {
+ let a = 22;
+ match &a {
+ <() as Foo<'static>>::C => { }
+ &_ => { }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-57280.rs b/tests/ui/nll/issue-57280.rs
new file mode 100644
index 000000000..b9d336ec3
--- /dev/null
+++ b/tests/ui/nll/issue-57280.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+trait Foo {
+ const BLAH: &'static str;
+}
+
+struct Placeholder;
+
+impl Foo for Placeholder {
+ const BLAH: &'static str = "hi";
+}
+
+fn foo(x: &str) {
+ match x {
+ <Placeholder as Foo>::BLAH => { }
+ _ => { }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.rs b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs
new file mode 100644
index 000000000..eba859cde
--- /dev/null
+++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs
@@ -0,0 +1,38 @@
+// Regression test for issue #57642
+// Tests that we reject a bad higher-ranked subtype
+
+trait X {
+ type G;
+ fn make_g() -> Self::G;
+}
+
+impl<'a> X for fn(&'a ()) {
+ type G = &'a ();
+
+ fn make_g() -> Self::G {
+ &()
+ }
+}
+
+trait Y {
+ type F;
+ fn make_f() -> Self::F;
+}
+
+impl<T> Y for fn(T) {
+ type F = fn(T);
+
+ fn make_f() -> Self::F {
+ |_| {}
+ }
+}
+
+fn higher_ranked_region_has_lost_its_binder() {
+ let x = <fn (&())>::make_g(); //~ ERROR the function
+}
+
+fn magical() {
+ let x = <fn (&())>::make_f(); //~ ERROR no function
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr
new file mode 100644
index 000000000..6e96f40c0
--- /dev/null
+++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr
@@ -0,0 +1,31 @@
+error[E0599]: the function or associated item `make_g` exists for fn pointer `for<'a> fn(&'a ())`, but its trait bounds were not satisfied
+ --> $DIR/issue-57642-higher-ranked-subtype.rs:31:25
+ |
+LL | let x = <fn (&())>::make_g();
+ | ^^^^^^ function or associated item cannot be called on `for<'a> fn(&'a ())` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `for<'a> fn(&'a ()): X`
+ = help: items from traits can only be used if the trait is implemented and in scope
+note: `X` defines an item `make_g`, perhaps you need to implement it
+ --> $DIR/issue-57642-higher-ranked-subtype.rs:4:1
+ |
+LL | trait X {
+ | ^^^^^^^
+
+error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope
+ --> $DIR/issue-57642-higher-ranked-subtype.rs:35:25
+ |
+LL | let x = <fn (&())>::make_f();
+ | ^^^^^^ function or associated item not found in `for<'a> fn(&'a ())`
+ |
+ = help: items from traits can only be used if the trait is implemented and in scope
+note: `Y` defines an item `make_f`, perhaps you need to implement it
+ --> $DIR/issue-57642-higher-ranked-subtype.rs:17:1
+ |
+LL | trait Y {
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/nll/issue-57843.rs b/tests/ui/nll/issue-57843.rs
new file mode 100644
index 000000000..11629690e
--- /dev/null
+++ b/tests/ui/nll/issue-57843.rs
@@ -0,0 +1,26 @@
+// Regression test for an ICE that occurred with the universes code:
+//
+// The signature of the closure `|_|` was being inferred to
+// `exists<'r> fn(&'r u8)`. This should result in a type error since
+// the signature `for<'r> fn(&'r u8)` is required. However, due to a
+// bug in the type variable generalization code, the placeholder for
+// `'r` was leaking out into the writeback phase, causing an ICE.
+
+trait ClonableFn<T> {
+ fn clone(&self) -> Box<dyn Fn(T)>;
+}
+
+impl<T, F: 'static> ClonableFn<T> for F
+where
+ F: Fn(T) + Clone,
+{
+ fn clone(&self) -> Box<dyn Fn(T)> {
+ Box::new(self.clone())
+ }
+}
+
+struct Foo(Box<dyn for<'a> ClonableFn<&'a bool>>);
+
+fn main() {
+ Foo(Box::new(|_| ())); //~ ERROR implementation of `FnOnce` is not general enough
+}
diff --git a/tests/ui/nll/issue-57843.stderr b/tests/ui/nll/issue-57843.stderr
new file mode 100644
index 000000000..2ab49ec61
--- /dev/null
+++ b/tests/ui/nll/issue-57843.stderr
@@ -0,0 +1,11 @@
+error: implementation of `FnOnce` is not general enough
+ --> $DIR/issue-57843.rs:25:9
+ |
+LL | Foo(Box::new(|_| ()));
+ | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+ |
+ = note: closure with signature `fn(&'2 bool)` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-57960.rs b/tests/ui/nll/issue-57960.rs
new file mode 100644
index 000000000..32e45184a
--- /dev/null
+++ b/tests/ui/nll/issue-57960.rs
@@ -0,0 +1,38 @@
+// run-pass
+
+#![allow(dead_code)]
+
+trait Range {
+ const FIRST: u8;
+ const LAST: u8;
+}
+
+struct OneDigit;
+impl Range for OneDigit {
+ const FIRST: u8 = 0;
+ const LAST: u8 = 9;
+}
+
+struct TwoDigits;
+impl Range for TwoDigits {
+ const FIRST: u8 = 10;
+ const LAST: u8 = 99;
+}
+
+struct ThreeDigits;
+impl Range for ThreeDigits {
+ const FIRST: u8 = 100;
+ const LAST: u8 = 255;
+}
+
+fn digits(x: u8) -> u32 {
+ match x {
+ OneDigit::FIRST..=OneDigit::LAST => 1,
+ TwoDigits::FIRST..=TwoDigits::LAST => 2,
+ ThreeDigits::FIRST..=ThreeDigits::LAST => 3,
+ }
+}
+
+fn main() {
+ assert_eq!(digits(100), 3);
+}
diff --git a/tests/ui/nll/issue-57989.rs b/tests/ui/nll/issue-57989.rs
new file mode 100644
index 000000000..8f3dec454
--- /dev/null
+++ b/tests/ui/nll/issue-57989.rs
@@ -0,0 +1,10 @@
+// Test for ICE from issue 57989
+
+fn f(x: &i32) {
+ let g = &x;
+ *x = 0; //~ ERROR cannot assign to `*x`, which is behind a `&` reference
+ //~| ERROR cannot assign to `*x` because it is borrowed
+ g;
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-57989.stderr b/tests/ui/nll/issue-57989.stderr
new file mode 100644
index 000000000..31f40d825
--- /dev/null
+++ b/tests/ui/nll/issue-57989.stderr
@@ -0,0 +1,26 @@
+error[E0594]: cannot assign to `*x`, which is behind a `&` reference
+ --> $DIR/issue-57989.rs:5:5
+ |
+LL | *x = 0;
+ | ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | fn f(x: &mut i32) {
+ | ~~~~~~~~
+
+error[E0506]: cannot assign to `*x` because it is borrowed
+ --> $DIR/issue-57989.rs:5:5
+ |
+LL | let g = &x;
+ | -- borrow of `*x` occurs here
+LL | *x = 0;
+ | ^^^^^^ assignment to borrowed `*x` occurs here
+LL |
+LL | g;
+ | - borrow later used here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0506, E0594.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/issue-58053.rs b/tests/ui/nll/issue-58053.rs
new file mode 100644
index 000000000..d5a2fa1a3
--- /dev/null
+++ b/tests/ui/nll/issue-58053.rs
@@ -0,0 +1,11 @@
+fn main() {
+ let i = &3;
+
+ let f = |x: &i32| -> &i32 { x };
+ //~^ ERROR lifetime may not live long enough
+ let j = f(i);
+
+ let g = |x: &i32| { x };
+ //~^ ERROR lifetime may not live long enough
+ let k = g(i);
+}
diff --git a/tests/ui/nll/issue-58053.stderr b/tests/ui/nll/issue-58053.stderr
new file mode 100644
index 000000000..bf7416e1a
--- /dev/null
+++ b/tests/ui/nll/issue-58053.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-58053.rs:4:33
+ |
+LL | let f = |x: &i32| -> &i32 { x };
+ | - - ^ returning this value requires that `'1` must outlive `'2`
+ | | |
+ | | let's call the lifetime of this reference `'2`
+ | let's call the lifetime of this reference `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-58053.rs:8:25
+ |
+LL | let g = |x: &i32| { x };
+ | - - ^ returning this value requires that `'1` must outlive `'2`
+ | | |
+ | | return type of closure is &'2 i32
+ | let's call the lifetime of this reference `'1`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/issue-58299.rs b/tests/ui/nll/issue-58299.rs
new file mode 100644
index 000000000..0587fe8b4
--- /dev/null
+++ b/tests/ui/nll/issue-58299.rs
@@ -0,0 +1,27 @@
+struct A<'a>(&'a ());
+
+trait Y {
+ const X: i32;
+}
+
+impl Y for A<'static> {
+ const X: i32 = 10;
+}
+
+fn foo<'a>(x: i32) {
+ match x {
+ // This uses <A<'a> as Y>::X, but `A<'a>` does not implement `Y`.
+ A::<'a>::X..=A::<'static>::X => (), //~ ERROR lifetime may not live long enough
+ _ => (),
+ }
+}
+
+fn bar<'a>(x: i32) {
+ match x {
+ // This uses <A<'a> as Y>::X, but `A<'a>` does not implement `Y`.
+ A::<'static>::X..=A::<'a>::X => (), //~ ERROR lifetime may not live long enough
+ _ => (),
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-58299.stderr b/tests/ui/nll/issue-58299.stderr
new file mode 100644
index 000000000..509ba67bd
--- /dev/null
+++ b/tests/ui/nll/issue-58299.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-58299.rs:14:9
+ |
+LL | fn foo<'a>(x: i32) {
+ | -- lifetime `'a` defined here
+...
+LL | A::<'a>::X..=A::<'static>::X => (),
+ | ^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-58299.rs:22:27
+ |
+LL | fn bar<'a>(x: i32) {
+ | -- lifetime `'a` defined here
+...
+LL | A::<'static>::X..=A::<'a>::X => (),
+ | ^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/issue-61311-normalize.rs b/tests/ui/nll/issue-61311-normalize.rs
new file mode 100644
index 000000000..77d67b07a
--- /dev/null
+++ b/tests/ui/nll/issue-61311-normalize.rs
@@ -0,0 +1,34 @@
+// Regression test for #61311
+// We would ICE after failing to normalize `Self::Proj` in the `impl` below.
+
+// check-pass
+
+pub struct Unit;
+trait Obj {}
+
+trait Bound {}
+impl Bound for Unit {}
+
+pub trait HasProj {
+ type Proj;
+}
+
+impl<T> HasProj for T {
+ type Proj = Unit;
+}
+
+trait HasProjFn {
+ type Proj;
+ fn the_fn(_: Self::Proj);
+}
+
+impl HasProjFn for Unit
+where
+ Box<dyn Obj + 'static>: HasProj,
+ <Box<dyn Obj + 'static> as HasProj>::Proj: Bound,
+{
+ type Proj = Unit;
+ fn the_fn(_: Self::Proj) {}
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-61320-normalize.rs b/tests/ui/nll/issue-61320-normalize.rs
new file mode 100644
index 000000000..095bef03f
--- /dev/null
+++ b/tests/ui/nll/issue-61320-normalize.rs
@@ -0,0 +1,160 @@
+// Regression test for #61320
+// This is the same issue as #61311, just a larger test case.
+
+// check-pass
+
+pub struct AndThen<A, B, F>
+where
+ A: Future,
+ B: IntoFuture,
+{
+ state: (A, B::Future, F),
+}
+
+pub struct FutureResult<T, E> {
+ inner: Option<Result<T, E>>,
+}
+
+impl<T, E> Future for FutureResult<T, E> {
+ type Item = T;
+ type Error = E;
+
+ fn poll(&mut self) -> Poll<T, E> {
+ unimplemented!()
+ }
+}
+
+pub type Poll<T, E> = Result<T, E>;
+
+impl<A, B, F> Future for AndThen<A, B, F>
+where
+ A: Future,
+ B: IntoFuture<Error = A::Error>,
+ F: FnOnce(A::Item) -> B,
+{
+ type Item = B::Item;
+ type Error = B::Error;
+
+ fn poll(&mut self) -> Poll<B::Item, B::Error> {
+ unimplemented!()
+ }
+}
+
+pub trait Future {
+ type Item;
+
+ type Error;
+
+ fn poll(&mut self) -> Poll<Self::Item, Self::Error>;
+
+ fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
+ where
+ F: FnOnce(Self::Item) -> B,
+ B: IntoFuture<Error = Self::Error>,
+ Self: Sized,
+ {
+ unimplemented!()
+ }
+}
+
+pub trait IntoFuture {
+ /// The future that this type can be converted into.
+ type Future: Future<Item = Self::Item, Error = Self::Error>;
+
+ /// The item that the future may resolve with.
+ type Item;
+ /// The error that the future may resolve with.
+ type Error;
+
+ /// Consumes this object and produces a future.
+ fn into_future(self) -> Self::Future;
+}
+
+impl<F: Future> IntoFuture for F {
+ type Future = F;
+ type Item = F::Item;
+ type Error = F::Error;
+
+ fn into_future(self) -> F {
+ self
+ }
+}
+
+impl<F: ?Sized + Future> Future for ::std::boxed::Box<F> {
+ type Item = F::Item;
+ type Error = F::Error;
+
+ fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
+ (**self).poll()
+ }
+}
+
+impl<T, E> IntoFuture for Result<T, E> {
+ type Future = FutureResult<T, E>;
+ type Item = T;
+ type Error = E;
+
+ fn into_future(self) -> FutureResult<T, E> {
+ unimplemented!()
+ }
+}
+
+struct Request<T>(T);
+
+trait RequestContext {}
+impl<T> RequestContext for T {}
+struct NoContext;
+impl AsRef<NoContext> for NoContext {
+ fn as_ref(&self) -> &Self {
+ &NoContext
+ }
+}
+
+type BoxedError = Box<dyn std::error::Error + Send + Sync>;
+type DefaultFuture<T, E> = Box<dyn Future<Item = T, Error = E> + Send>;
+
+trait Guard: Sized {
+ type Result: IntoFuture<Item = Self, Error = BoxedError>;
+ fn from_request(request: &Request<()>) -> Self::Result;
+}
+
+trait FromRequest: Sized {
+ type Context;
+ type Future: Future<Item = Self, Error = BoxedError> + Send;
+ fn from_request(request: Request<()>) -> Self::Future;
+}
+
+struct MyGuard;
+impl Guard for MyGuard {
+ type Result = Result<Self, BoxedError>;
+ fn from_request(_request: &Request<()>) -> Self::Result {
+ Ok(MyGuard)
+ }
+}
+
+struct Generic<I> {
+ _inner: I,
+}
+
+impl<I> FromRequest for Generic<I>
+where
+ MyGuard: Guard,
+ <MyGuard as Guard>::Result: IntoFuture<Item = MyGuard, Error = BoxedError>,
+ <<MyGuard as Guard>::Result as IntoFuture>::Future: Send,
+ I: FromRequest<Context = NoContext>,
+{
+ type Future = DefaultFuture<Self, BoxedError>;
+ type Context = NoContext;
+ fn from_request(headers: Request<()>) -> DefaultFuture<Self, BoxedError> {
+ let _future = <MyGuard as Guard>::from_request(&headers)
+ .into_future()
+ .and_then(move |_| {
+ <I as FromRequest>::from_request(headers)
+ .into_future()
+ .and_then(move |fld_inner| Ok(Generic { _inner: fld_inner }).into_future())
+ });
+ panic!();
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-61424.fixed b/tests/ui/nll/issue-61424.fixed
new file mode 100644
index 000000000..63e00c172
--- /dev/null
+++ b/tests/ui/nll/issue-61424.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#![deny(unused_mut)]
+
+fn main() {
+ let x; //~ ERROR: variable does not need to be mutable
+ x = String::new();
+ dbg!(x);
+}
diff --git a/tests/ui/nll/issue-61424.rs b/tests/ui/nll/issue-61424.rs
new file mode 100644
index 000000000..3b64996c2
--- /dev/null
+++ b/tests/ui/nll/issue-61424.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#![deny(unused_mut)]
+
+fn main() {
+ let mut x; //~ ERROR: variable does not need to be mutable
+ x = String::new();
+ dbg!(x);
+}
diff --git a/tests/ui/nll/issue-61424.stderr b/tests/ui/nll/issue-61424.stderr
new file mode 100644
index 000000000..6de6b7f3a
--- /dev/null
+++ b/tests/ui/nll/issue-61424.stderr
@@ -0,0 +1,16 @@
+error: variable does not need to be mutable
+ --> $DIR/issue-61424.rs:6:9
+ |
+LL | let mut x;
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+note: the lint level is defined here
+ --> $DIR/issue-61424.rs:3:9
+ |
+LL | #![deny(unused_mut)]
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-62007-assign-const-index.rs b/tests/ui/nll/issue-62007-assign-const-index.rs
new file mode 100644
index 000000000..3ea5d3a7a
--- /dev/null
+++ b/tests/ui/nll/issue-62007-assign-const-index.rs
@@ -0,0 +1,32 @@
+// Issue #62007: assigning over a const-index projection of an array
+// (in this case, `list[I] = n;`) should in theory be able to kill all borrows
+// of `list[0]`, so that `list[0]` could be borrowed on the next
+// iteration through the loop.
+//
+// Currently the compiler does not allow this. We may want to consider
+// loosening that restriction in the future. (However, doing so would
+// at *least* require T-lang team approval, and probably an RFC; e.g.
+// such loosening might make complicate the user's mental mode; it
+// also would make code more brittle in the face of refactorings that
+// replace constants with variables.
+
+#![allow(dead_code)]
+
+struct List<T> {
+ value: T,
+ next: Option<Box<List<T>>>,
+}
+
+fn to_refs<T>(mut list: [&mut List<T>; 2]) -> Vec<&mut T> {
+ let mut result = vec![];
+ loop {
+ result.push(&mut list[0].value); //~ ERROR cannot borrow `list[_].value` as mutable
+ if let Some(n) = list[0].next.as_mut() { //~ ERROR cannot borrow `list[_].next` as mutable
+ list[0] = n;
+ } else {
+ return result;
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-62007-assign-const-index.stderr b/tests/ui/nll/issue-62007-assign-const-index.stderr
new file mode 100644
index 000000000..12e28aa3f
--- /dev/null
+++ b/tests/ui/nll/issue-62007-assign-const-index.stderr
@@ -0,0 +1,27 @@
+error[E0499]: cannot borrow `list[_].value` as mutable more than once at a time
+ --> $DIR/issue-62007-assign-const-index.rs:23:21
+ |
+LL | fn to_refs<T>(mut list: [&mut List<T>; 2]) -> Vec<&mut T> {
+ | - let's call the lifetime of this reference `'1`
+...
+LL | result.push(&mut list[0].value);
+ | ^^^^^^^^^^^^^^^^^^ `list[_].value` was mutably borrowed here in the previous iteration of the loop
+...
+LL | return result;
+ | ------ returning this value requires that `list[_].value` is borrowed for `'1`
+
+error[E0499]: cannot borrow `list[_].next` as mutable more than once at a time
+ --> $DIR/issue-62007-assign-const-index.rs:24:26
+ |
+LL | fn to_refs<T>(mut list: [&mut List<T>; 2]) -> Vec<&mut T> {
+ | - let's call the lifetime of this reference `'1`
+...
+LL | if let Some(n) = list[0].next.as_mut() {
+ | ^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `list[_].next` was mutably borrowed here in the previous iteration of the loop
+ | argument requires that `list[_].next` is borrowed for `'1`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/nll/issue-62007-assign-differing-fields.rs b/tests/ui/nll/issue-62007-assign-differing-fields.rs
new file mode 100644
index 000000000..29d92b7b8
--- /dev/null
+++ b/tests/ui/nll/issue-62007-assign-differing-fields.rs
@@ -0,0 +1,25 @@
+// Double-check we didn't go too far with our resolution to issue
+// #62007: assigning over a field projection (`list.1 = n;` in this
+// case) should kill only borrows of `list.1`; `list.0` can *not*
+// necessarily 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<'a, T>(mut list: (&'a mut List<T>, &'a mut List<T>)) -> Vec<&'a mut T> {
+ let mut result = vec![];
+ loop {
+ result.push(&mut (list.0).value); //~ ERROR cannot borrow `list.0.value` as mutable
+ if let Some(n) = (list.0).next.as_mut() { //~ ERROR cannot borrow `list.0.next` as mutable
+ list.1 = n;
+ } else {
+ return result;
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-62007-assign-differing-fields.stderr b/tests/ui/nll/issue-62007-assign-differing-fields.stderr
new file mode 100644
index 000000000..4488431fc
--- /dev/null
+++ b/tests/ui/nll/issue-62007-assign-differing-fields.stderr
@@ -0,0 +1,27 @@
+error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time
+ --> $DIR/issue-62007-assign-differing-fields.rs:16:21
+ |
+LL | fn to_refs<'a, T>(mut list: (&'a mut List<T>, &'a mut List<T>)) -> Vec<&'a mut T> {
+ | -- lifetime `'a` defined here
+...
+LL | result.push(&mut (list.0).value);
+ | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop
+...
+LL | return result;
+ | ------ returning this value requires that `list.0.value` is borrowed for `'a`
+
+error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time
+ --> $DIR/issue-62007-assign-differing-fields.rs:17:26
+ |
+LL | fn to_refs<'a, T>(mut list: (&'a mut List<T>, &'a mut List<T>)) -> Vec<&'a mut T> {
+ | -- lifetime `'a` defined here
+...
+LL | if let Some(n) = (list.0).next.as_mut() {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `list.0.next` was mutably borrowed here in the previous iteration of the loop
+ | argument requires that `list.0.next` is borrowed for `'a`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/nll/issue-63154-normalize.rs b/tests/ui/nll/issue-63154-normalize.rs
new file mode 100644
index 000000000..484c12879
--- /dev/null
+++ b/tests/ui/nll/issue-63154-normalize.rs
@@ -0,0 +1,34 @@
+// Regression test for rust-lang/rust#63154
+//
+// Before, we would ICE after failing to normalize the destination type
+// when checking call destinations and also when checking MIR
+// assignment statements.
+
+// check-pass
+
+trait HasAssocType {
+ type Inner;
+}
+
+impl HasAssocType for () {
+ type Inner = ();
+}
+
+trait Tr<I, T>: Fn(I) -> Option<T> {}
+impl<I, T, Q: Fn(I) -> Option<T>> Tr<I, T> for Q {}
+
+fn f<T: HasAssocType>() -> impl Tr<T, T::Inner> {
+ |_| None
+}
+
+fn g<T, Y>(f: impl Tr<T, Y>) -> impl Tr<T, Y> {
+ f
+}
+
+fn h() {
+ g(f())(());
+}
+
+fn main() {
+ h();
+}
diff --git a/tests/ui/nll/issue-67007-escaping-data.rs b/tests/ui/nll/issue-67007-escaping-data.rs
new file mode 100644
index 000000000..49ea2e596
--- /dev/null
+++ b/tests/ui/nll/issue-67007-escaping-data.rs
@@ -0,0 +1,24 @@
+// Regression test for issue #67007
+// Ensures that we show information about the specific regions involved
+
+// Covariant over 'a, invariant over 'tcx
+struct FnCtxt<'a, 'tcx: 'a>(&'a (), *mut &'tcx ());
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ fn use_it(&self, _: &'tcx ()) {}
+}
+
+struct Consumer<'tcx>(&'tcx ());
+
+impl<'tcx> Consumer<'tcx> {
+ fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
+ let other = self.use_fcx(fcx); //~ ERROR lifetime may not live long enough
+ fcx.use_it(other);
+ }
+
+ fn use_fcx<'a>(&self, _: &FnCtxt<'a, 'tcx>) -> &'a () {
+ &()
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-67007-escaping-data.stderr b/tests/ui/nll/issue-67007-escaping-data.stderr
new file mode 100644
index 000000000..ac9c59bf7
--- /dev/null
+++ b/tests/ui/nll/issue-67007-escaping-data.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-67007-escaping-data.rs:15:21
+ |
+LL | impl<'tcx> Consumer<'tcx> {
+ | ---- lifetime `'tcx` defined here
+LL | fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
+ | -- lifetime `'a` defined here
+LL | let other = self.use_fcx(fcx);
+ | ^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'tcx`
+ |
+ = help: consider adding the following bound: `'a: 'tcx`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-68550.rs b/tests/ui/nll/issue-68550.rs
new file mode 100644
index 000000000..6bfd18de1
--- /dev/null
+++ b/tests/ui/nll/issue-68550.rs
@@ -0,0 +1,15 @@
+// Regression test for issue #68550.
+//
+// The `&'static A:` where clause was triggering
+// ICEs because it wound up being compiled to reference
+// the `'empty(U0)` region.
+
+fn run<'a, A>(x: A)
+where
+ A: 'static,
+ &'static A: ,
+{
+ let _: &'a A = &x; //~ ERROR `x` does not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-68550.stderr b/tests/ui/nll/issue-68550.stderr
new file mode 100644
index 000000000..e234ebb04
--- /dev/null
+++ b/tests/ui/nll/issue-68550.stderr
@@ -0,0 +1,16 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/issue-68550.rs:12:20
+ |
+LL | fn run<'a, A>(x: A)
+ | -- lifetime `'a` defined here
+...
+LL | let _: &'a A = &x;
+ | ----- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `x` is borrowed for `'a`
+LL | }
+ | - `x` 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/nll/issue-69114-static-mut-ty.rs b/tests/ui/nll/issue-69114-static-mut-ty.rs
new file mode 100644
index 000000000..ce37da053
--- /dev/null
+++ b/tests/ui/nll/issue-69114-static-mut-ty.rs
@@ -0,0 +1,30 @@
+// Check that borrowck ensures that `static mut` items have the expected type.
+
+static FOO: u8 = 42;
+static mut BAR: &'static u8 = &FOO;
+static mut BAR_ELIDED: &u8 = &FOO;
+
+fn main() {
+ unsafe {
+ println!("{} {}", BAR, BAR_ELIDED);
+ set_bar();
+ set_bar_elided();
+ println!("{} {}", BAR, BAR_ELIDED);
+ }
+}
+
+fn set_bar() {
+ let n = 42;
+ unsafe {
+ BAR = &n;
+ //~^ ERROR does not live long enough
+ }
+}
+
+fn set_bar_elided() {
+ let n = 42;
+ unsafe {
+ BAR_ELIDED = &n;
+ //~^ ERROR does not live long enough
+ }
+}
diff --git a/tests/ui/nll/issue-69114-static-mut-ty.stderr b/tests/ui/nll/issue-69114-static-mut-ty.stderr
new file mode 100644
index 000000000..5e55cb502
--- /dev/null
+++ b/tests/ui/nll/issue-69114-static-mut-ty.stderr
@@ -0,0 +1,27 @@
+error[E0597]: `n` does not live long enough
+ --> $DIR/issue-69114-static-mut-ty.rs:19:15
+ |
+LL | BAR = &n;
+ | ------^^
+ | | |
+ | | borrowed value does not live long enough
+ | assignment requires that `n` is borrowed for `'static`
+...
+LL | }
+ | - `n` dropped here while still borrowed
+
+error[E0597]: `n` does not live long enough
+ --> $DIR/issue-69114-static-mut-ty.rs:27:22
+ |
+LL | BAR_ELIDED = &n;
+ | -------------^^
+ | | |
+ | | borrowed value does not live long enough
+ | assignment requires that `n` is borrowed for `'static`
+...
+LL | }
+ | - `n` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/issue-69114-static-ty.rs b/tests/ui/nll/issue-69114-static-ty.rs
new file mode 100644
index 000000000..3318433a1
--- /dev/null
+++ b/tests/ui/nll/issue-69114-static-ty.rs
@@ -0,0 +1,9 @@
+// Check that borrowck ensures that `static` items have the expected type.
+
+static FOO: &'static (dyn Fn(&'static u8) + Send + Sync) = &drop;
+
+fn main() {
+ let n = 42;
+ FOO(&n);
+ //~^ ERROR does not live long enough
+}
diff --git a/tests/ui/nll/issue-69114-static-ty.stderr b/tests/ui/nll/issue-69114-static-ty.stderr
new file mode 100644
index 000000000..0815e74b5
--- /dev/null
+++ b/tests/ui/nll/issue-69114-static-ty.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `n` does not live long enough
+ --> $DIR/issue-69114-static-ty.rs:7:9
+ |
+LL | FOO(&n);
+ | ----^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `n` is borrowed for `'static`
+LL |
+LL | }
+ | - `n` 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/nll/issue-73159-rpit-static.rs b/tests/ui/nll/issue-73159-rpit-static.rs
new file mode 100644
index 000000000..3002408b0
--- /dev/null
+++ b/tests/ui/nll/issue-73159-rpit-static.rs
@@ -0,0 +1,13 @@
+// Regression test for issue #73159
+// Tests thar we don't suggest replacing 'a with 'static'
+
+struct Foo<'a>(&'a [u8]);
+
+impl<'a> Foo<'a> {
+ fn make_it(&self) -> impl Iterator<Item = u8> {
+ self.0.iter().copied()
+ //~^ ERROR: captures lifetime that does not appear in bounds
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-73159-rpit-static.stderr b/tests/ui/nll/issue-73159-rpit-static.stderr
new file mode 100644
index 000000000..260b9b597
--- /dev/null
+++ b/tests/ui/nll/issue-73159-rpit-static.stderr
@@ -0,0 +1,12 @@
+error[E0700]: hidden type for `impl Iterator<Item = u8>` captures lifetime that does not appear in bounds
+ --> $DIR/issue-73159-rpit-static.rs:8:9
+ |
+LL | impl<'a> Foo<'a> {
+ | -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here
+LL | fn make_it(&self) -> impl Iterator<Item = u8> {
+LL | self.0.iter().copied()
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/nll/issue-78561.rs b/tests/ui/nll/issue-78561.rs
new file mode 100644
index 000000000..55147fcd1
--- /dev/null
+++ b/tests/ui/nll/issue-78561.rs
@@ -0,0 +1,23 @@
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+pub trait Trait {
+ type A;
+
+ fn f() -> Self::A;
+}
+
+pub trait Tr2<'a, 'b> {}
+
+pub struct A<T>(T);
+pub trait Tr {
+ type B;
+}
+
+impl<'a, 'b, T: Tr<B = dyn Tr2<'a, 'b>>> Trait for A<T> {
+ type A = impl core::fmt::Debug;
+
+ fn f() -> Self::A {}
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-95272.rs b/tests/ui/nll/issue-95272.rs
new file mode 100644
index 000000000..958cbde37
--- /dev/null
+++ b/tests/ui/nll/issue-95272.rs
@@ -0,0 +1,15 @@
+use std::cell::Cell;
+
+fn check<'a, 'b>(x: Cell<&'a ()>, y: Cell<&'b ()>)
+where
+ 'a: 'b,
+{
+}
+
+fn test<'a, 'b>(x: Cell<&'a ()>, y: Cell<&'b ()>) {
+ let f = check;
+ //~^ ERROR lifetime may not live long enough
+ f(x, y);
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-95272.stderr b/tests/ui/nll/issue-95272.stderr
new file mode 100644
index 000000000..03edbc3a6
--- /dev/null
+++ b/tests/ui/nll/issue-95272.stderr
@@ -0,0 +1,17 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-95272.rs:10:13
+ |
+LL | fn test<'a, 'b>(x: Cell<&'a ()>, y: Cell<&'b ()>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | let f = check;
+ | ^^^^^ assignment requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a function pointer to `check`
+ = note: the function `check` is invariant over the parameter `'a`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/issue-97997.rs b/tests/ui/nll/issue-97997.rs
new file mode 100644
index 000000000..c64e720b1
--- /dev/null
+++ b/tests/ui/nll/issue-97997.rs
@@ -0,0 +1,16 @@
+trait Foo {
+ const ASSOC: bool = true;
+}
+impl<T> Foo for fn(T) {}
+
+fn foo(_x: i32) {}
+
+fn impls_foo<T: Foo>(_x: T) {}
+
+fn main() {
+ impls_foo(foo as fn(i32));
+
+ <fn(&u8) as Foo>::ASSOC;
+ //~^ ERROR implementation of `Foo` is not general enough
+ //~| ERROR implementation of `Foo` is not general enough
+}
diff --git a/tests/ui/nll/issue-97997.stderr b/tests/ui/nll/issue-97997.stderr
new file mode 100644
index 000000000..46440c021
--- /dev/null
+++ b/tests/ui/nll/issue-97997.stderr
@@ -0,0 +1,20 @@
+error: implementation of `Foo` is not general enough
+ --> $DIR/issue-97997.rs:13:5
+ |
+LL | <fn(&u8) as Foo>::ASSOC;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a u8)`
+ = note: ...but `Foo` is actually implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
+
+error: implementation of `Foo` is not general enough
+ --> $DIR/issue-97997.rs:13:5
+ |
+LL | <fn(&u8) as Foo>::ASSOC;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a u8)`
+ = note: ...but `Foo` is actually implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/issue-98170.rs b/tests/ui/nll/issue-98170.rs
new file mode 100644
index 000000000..6bb12f52d
--- /dev/null
+++ b/tests/ui/nll/issue-98170.rs
@@ -0,0 +1,25 @@
+pub struct MyStruct<'a> {
+ field: &'a [u32],
+}
+
+impl MyStruct<'_> {
+ pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
+ Self { field }
+ //~^ ERROR lifetime may not live long enough
+ //~| ERROR lifetime may not live long enough
+ }
+}
+
+trait Trait<'a> {
+ fn new(field: &'a [u32]) -> MyStruct<'a>;
+}
+
+impl<'a> Trait<'a> for MyStruct<'_> {
+ fn new(field: &'a [u32]) -> MyStruct<'a> {
+ Self { field }
+ //~^ ERROR lifetime may not live long enough
+ //~| ERROR lifetime may not live long enough
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-98170.stderr b/tests/ui/nll/issue-98170.stderr
new file mode 100644
index 000000000..0d17365e7
--- /dev/null
+++ b/tests/ui/nll/issue-98170.stderr
@@ -0,0 +1,44 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-98170.rs:7:9
+ |
+LL | impl MyStruct<'_> {
+ | -- lifetime `'1` appears in the `impl`'s self type
+LL | pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
+ | -- lifetime `'a` defined here
+LL | Self { field }
+ | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-98170.rs:7:16
+ |
+LL | impl MyStruct<'_> {
+ | -- lifetime `'1` appears in the `impl`'s self type
+LL | pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
+ | -- lifetime `'a` defined here
+LL | Self { field }
+ | ^^^^^ this usage requires that `'a` must outlive `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-98170.rs:19:9
+ |
+LL | impl<'a> Trait<'a> for MyStruct<'_> {
+ | -- -- lifetime `'1` appears in the `impl`'s self type
+ | |
+ | lifetime `'a` defined here
+LL | fn new(field: &'a [u32]) -> MyStruct<'a> {
+LL | Self { field }
+ | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-98170.rs:19:16
+ |
+LL | impl<'a> Trait<'a> for MyStruct<'_> {
+ | -- -- lifetime `'1` appears in the `impl`'s self type
+ | |
+ | lifetime `'a` defined here
+LL | fn new(field: &'a [u32]) -> MyStruct<'a> {
+LL | Self { field }
+ | ^^^^^ this usage requires that `'a` must outlive `'1`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/nll/issue-98589-closures-relate-named-regions.rs b/tests/ui/nll/issue-98589-closures-relate-named-regions.rs
new file mode 100644
index 000000000..6cc4340bb
--- /dev/null
+++ b/tests/ui/nll/issue-98589-closures-relate-named-regions.rs
@@ -0,0 +1,36 @@
+// Regression test for #98589.
+// Previously, named lifetime `'a` that appears in the closure was unrelated to `'a`
+// that appears in the parent function iff `'a` is early-bound.
+// This made the following tests pass borrowck.
+
+// check-fail
+
+// The bound `'a: 'a` ensures that `'a` is early-bound.
+fn test_early_early<'a: 'a, 'b: 'b>() {
+ || { None::<&'a &'b ()>; };
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_late<'a: 'a, 'b>() {
+ || { None::<&'a &'b ()>; };
+ //~^ ERROR lifetime may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_late<'a, 'b>() {
+ || { None::<&'a &'b ()>; };
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_type<'a: 'a, T>() {
+ || { None::<&'a T>; };
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_type<'a, T>() {
+ || { None::<&'a T>; };
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
new file mode 100644
index 000000000..d8b26f0b0
--- /dev/null
+++ b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr
@@ -0,0 +1,61 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:10:5
+ |
+LL | fn test_early_early<'a: 'a, 'b: 'b>() {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | || { None::<&'a &'b ()>; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:15:10
+ |
+LL | fn test_early_late<'a: 'a, 'b>() {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | || { None::<&'a &'b ()>; };
+ | ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:21:10
+ |
+LL | fn test_late_late<'a, 'b>() {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | || { None::<&'a &'b ()>; };
+ | ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:26:10
+ |
+LL | || { None::<&'a T>; };
+ | ^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test_early_type<'a: 'a, T: 'a>() {
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:32:10
+ |
+LL | || { None::<&'a T>; };
+ | ^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test_late_type<'a, T: 'a>() {
+ | ++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/issue-98693.rs b/tests/ui/nll/issue-98693.rs
new file mode 100644
index 000000000..7a325e2e9
--- /dev/null
+++ b/tests/ui/nll/issue-98693.rs
@@ -0,0 +1,21 @@
+// Regression test for #98693.
+//
+// The closure encounters an obligation that `T` must outlive `!U1`,
+// a placeholder from universe U1. We were ignoring this placeholder
+// when promoting the constraint to the enclosing function, and
+// thus incorrectly judging the closure to be safe.
+
+fn assert_static<T>()
+where
+ for<'a> T: 'a,
+{
+}
+
+fn test<T>() {
+ || {
+ assert_static::<T>();
+ //~^ ERROR the parameter type `T` may not live long enough
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/issue-98693.stderr b/tests/ui/nll/issue-98693.stderr
new file mode 100644
index 000000000..15ca38aa2
--- /dev/null
+++ b/tests/ui/nll/issue-98693.stderr
@@ -0,0 +1,14 @@
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/issue-98693.rs:16:9
+ |
+LL | assert_static::<T>();
+ | ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test<T: 'static>() {
+ | +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/nll/lint-no-err.rs b/tests/ui/nll/lint-no-err.rs
new file mode 100644
index 000000000..2d1d5cb26
--- /dev/null
+++ b/tests/ui/nll/lint-no-err.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+// mir borrowck previously incorrectly set `tainted_by_errors`
+// when buffering lints, which resulted in ICE later on,
+// see #94502.
+
+struct Repro;
+impl Repro {
+ fn get(&self) -> &i32 {
+ &3
+ }
+
+ fn insert(&mut self, _: i32) {}
+}
+
+fn main() {
+ let x = &0;
+ let mut conflict = Repro;
+ let prev = conflict.get();
+ conflict.insert(*prev + *x);
+}
diff --git a/tests/ui/nll/loan_ends_mid_block_pair.rs b/tests/ui/nll/loan_ends_mid_block_pair.rs
new file mode 100644
index 000000000..acd6ec706
--- /dev/null
+++ b/tests/ui/nll/loan_ends_mid_block_pair.rs
@@ -0,0 +1,29 @@
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+
+fn main() {
+}
+
+fn nll_fail() {
+ let mut data = ('a', 'b', 'c');
+ let c = &mut data.0;
+ capitalize(c);
+ data.0 = 'e';
+ //~^ ERROR [E0506]
+ data.0 = 'f';
+ data.0 = 'g';
+ capitalize(c);
+}
+
+fn nll_ok() {
+ let mut data = ('a', 'b', 'c');
+ let c = &mut data.0;
+ capitalize(c);
+ data.0 = 'e';
+ data.0 = 'f';
+ data.0 = 'g';
+}
+
+fn capitalize(_: &mut char) {
+}
diff --git a/tests/ui/nll/loan_ends_mid_block_pair.stderr b/tests/ui/nll/loan_ends_mid_block_pair.stderr
new file mode 100644
index 000000000..eb8442b31
--- /dev/null
+++ b/tests/ui/nll/loan_ends_mid_block_pair.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `data.0` because it is borrowed
+ --> $DIR/loan_ends_mid_block_pair.rs:12:5
+ |
+LL | let c = &mut data.0;
+ | ----------- borrow of `data.0` occurs here
+LL | capitalize(c);
+LL | data.0 = 'e';
+ | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+...
+LL | capitalize(c);
+ | - 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/nll/loan_ends_mid_block_vec.rs b/tests/ui/nll/loan_ends_mid_block_vec.rs
new file mode 100644
index 000000000..2edcdef0a
--- /dev/null
+++ b/tests/ui/nll/loan_ends_mid_block_vec.rs
@@ -0,0 +1,30 @@
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+fn main() {
+}
+
+fn nll_fail() {
+ let mut data = vec!['a', 'b', 'c'];
+ let slice = &mut data;
+ capitalize(slice);
+ data.push('d');
+ //~^ ERROR [E0499]
+ data.push('e');
+ //~^ ERROR [E0499]
+ data.push('f');
+ //~^ ERROR [E0499]
+ capitalize(slice);
+}
+
+fn nll_ok() {
+ let mut data = vec!['a', 'b', 'c'];
+ let slice = &mut data;
+ capitalize(slice);
+ data.push('d');
+ data.push('e');
+ data.push('f');
+}
+
+fn capitalize(_: &mut [char]) {
+}
diff --git a/tests/ui/nll/loan_ends_mid_block_vec.stderr b/tests/ui/nll/loan_ends_mid_block_vec.stderr
new file mode 100644
index 000000000..22c72af61
--- /dev/null
+++ b/tests/ui/nll/loan_ends_mid_block_vec.stderr
@@ -0,0 +1,39 @@
+error[E0499]: cannot borrow `data` as mutable more than once at a time
+ --> $DIR/loan_ends_mid_block_vec.rs:11:5
+ |
+LL | let slice = &mut data;
+ | --------- first mutable borrow occurs here
+LL | capitalize(slice);
+LL | data.push('d');
+ | ^^^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL | capitalize(slice);
+ | ----- first borrow later used here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time
+ --> $DIR/loan_ends_mid_block_vec.rs:13:5
+ |
+LL | let slice = &mut data;
+ | --------- first mutable borrow occurs here
+...
+LL | data.push('e');
+ | ^^^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL | capitalize(slice);
+ | ----- first borrow later used here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time
+ --> $DIR/loan_ends_mid_block_vec.rs:15:5
+ |
+LL | let slice = &mut data;
+ | --------- first mutable borrow occurs here
+...
+LL | data.push('f');
+ | ^^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |
+LL | capitalize(slice);
+ | ----- first borrow later used here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.rs b/tests/ui/nll/local-outlives-static-via-hrtb.rs
new file mode 100644
index 000000000..5f1f9b3a7
--- /dev/null
+++ b/tests/ui/nll/local-outlives-static-via-hrtb.rs
@@ -0,0 +1,26 @@
+// Test that we handle the case when a local variable is borrowed for `'static`
+// due to an outlives constraint involving a region in an incompatible universe
+
+pub trait Outlives<'this> {}
+
+impl<'this, T> Outlives<'this> for T where T: 'this {}
+trait Reference {
+ type AssociatedType;
+}
+
+impl<'a, T: 'a> Reference for &'a T {
+ type AssociatedType = &'a ();
+}
+
+fn assert_static_via_hrtb<G>(_: G) where for<'a> G: Outlives<'a> {}
+
+fn assert_static_via_hrtb_with_assoc_type<T>(_: &'_ T)
+where
+ for<'a> &'a T: Reference<AssociatedType = &'a ()>,
+{}
+
+fn main() {
+ let local = 0;
+ assert_static_via_hrtb(&local); //~ ERROR `local` does not live long enough
+ assert_static_via_hrtb_with_assoc_type(&&local); //~ ERROR `local` does not live long enough
+}
diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr
new file mode 100644
index 000000000..f5c10f3dd
--- /dev/null
+++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr
@@ -0,0 +1,38 @@
+error[E0597]: `local` does not live long enough
+ --> $DIR/local-outlives-static-via-hrtb.rs:24:28
+ |
+LL | assert_static_via_hrtb(&local);
+ | -----------------------^^^^^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `local` is borrowed for `'static`
+LL | assert_static_via_hrtb_with_assoc_type(&&local);
+LL | }
+ | - `local` dropped here while still borrowed
+ |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+ --> $DIR/local-outlives-static-via-hrtb.rs:15:53
+ |
+LL | fn assert_static_via_hrtb<G>(_: G) where for<'a> G: Outlives<'a> {}
+ | ^^^^^^^^^^^^
+
+error[E0597]: `local` does not live long enough
+ --> $DIR/local-outlives-static-via-hrtb.rs:25:45
+ |
+LL | assert_static_via_hrtb_with_assoc_type(&&local);
+ | ----------------------------------------^^^^^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `local` is borrowed for `'static`
+LL | }
+ | - `local` dropped here while still borrowed
+ |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+ --> $DIR/local-outlives-static-via-hrtb.rs:19:20
+ |
+LL | for<'a> &'a T: Reference<AssociatedType = &'a ()>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/lub-if.rs b/tests/ui/nll/lub-if.rs
new file mode 100644
index 000000000..50225a783
--- /dev/null
+++ b/tests/ui/nll/lub-if.rs
@@ -0,0 +1,44 @@
+// Test that we correctly consider the type of `match` to be the LUB
+// of the various arms, particularly in the case where regions are
+// involved.
+
+pub fn opt_str0<'a>(maybestr: &'a Option<String>) -> &'a str {
+ if maybestr.is_none() {
+ "(none)"
+ } else {
+ let s: &'a str = maybestr.as_ref().unwrap();
+ s
+ }
+}
+
+pub fn opt_str1<'a>(maybestr: &'a Option<String>) -> &'a str {
+ if maybestr.is_some() {
+ let s: &'a str = maybestr.as_ref().unwrap();
+ s
+ } else {
+ "(none)"
+ }
+}
+
+pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
+ if maybestr.is_none() {
+ "(none)"
+ } else {
+ let s: &'a str = maybestr.as_ref().unwrap();
+ s
+ //~^ ERROR lifetime may not live long enough
+ }
+}
+
+pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
+ if maybestr.is_some() {
+ let s: &'a str = maybestr.as_ref().unwrap();
+ s
+ //~^ ERROR lifetime may not live long enough
+ } else {
+ "(none)"
+ }
+}
+
+
+fn main() {}
diff --git a/tests/ui/nll/lub-if.stderr b/tests/ui/nll/lub-if.stderr
new file mode 100644
index 000000000..03f7f9204
--- /dev/null
+++ b/tests/ui/nll/lub-if.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+ --> $DIR/lub-if.rs:28:9
+ |
+LL | pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
+ | -- lifetime `'a` defined here
+...
+LL | s
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/lub-if.rs:36:9
+ |
+LL | pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
+ | -- lifetime `'a` defined here
+...
+LL | s
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/lub-match.rs b/tests/ui/nll/lub-match.rs
new file mode 100644
index 000000000..454dd1fc6
--- /dev/null
+++ b/tests/ui/nll/lub-match.rs
@@ -0,0 +1,47 @@
+// Test that we correctly consider the type of `match` to be the LUB
+// of the various arms, particularly in the case where regions are
+// involved.
+
+pub fn opt_str0<'a>(maybestr: &'a Option<String>) -> &'a str {
+ match *maybestr {
+ Some(ref s) => {
+ let s: &'a str = s;
+ s
+ }
+ None => "(none)",
+ }
+}
+
+pub fn opt_str1<'a>(maybestr: &'a Option<String>) -> &'a str {
+ match *maybestr {
+ None => "(none)",
+ Some(ref s) => {
+ let s: &'a str = s;
+ s
+ }
+ }
+}
+
+pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
+ match *maybestr {
+ None => "(none)",
+ Some(ref s) => {
+ let s: &'a str = s;
+ s
+ //~^ ERROR lifetime may not live long enough
+ }
+ }
+}
+
+pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
+ match *maybestr {
+ Some(ref s) => {
+ let s: &'a str = s;
+ s
+ //~^ ERROR lifetime may not live long enough
+ }
+ None => "(none)",
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/lub-match.stderr b/tests/ui/nll/lub-match.stderr
new file mode 100644
index 000000000..208ec07a1
--- /dev/null
+++ b/tests/ui/nll/lub-match.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+ --> $DIR/lub-match.rs:30:13
+ |
+LL | pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
+ | -- lifetime `'a` defined here
+...
+LL | s
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/lub-match.rs:40:13
+ |
+LL | pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
+ | -- lifetime `'a` defined here
+...
+LL | s
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/match-cfg-fake-edges.rs b/tests/ui/nll/match-cfg-fake-edges.rs
new file mode 100644
index 000000000..1afc7931a
--- /dev/null
+++ b/tests/ui/nll/match-cfg-fake-edges.rs
@@ -0,0 +1,70 @@
+// Test that we have enough false edges to avoid exposing the exact matching
+// algorithm in borrow checking.
+
+#![feature(if_let_guard)]
+
+fn guard_always_precedes_arm(y: i32) {
+ let mut x;
+ // x should always be initialized, as the only way to reach the arm is
+ // through the guard.
+ match y {
+ 0 | 2 if { x = 2; true } => x,
+ _ => 2,
+ };
+
+ let mut x;
+ match y {
+ 0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
+ _ => 2,
+ };
+}
+
+fn guard_may_be_skipped(y: i32) {
+ let x;
+ // Even though x *is* always initialized, we don't want to have borrowck
+ // results be based on whether patterns are exhaustive.
+ match y {
+ _ if { x = 2; true } => 1,
+ _ if {
+ x; //~ ERROR E0381
+ false
+ } => 2,
+ _ => 3,
+ };
+
+ let x;
+ match y {
+ _ if let Some(()) = { x = 2; Some(()) } => 1,
+ _ if let Some(()) = {
+ x; //~ ERROR E0381
+ None
+ } => 2,
+ _ => 3,
+ };
+}
+
+fn guard_may_be_taken(y: bool) {
+ let x = String::new();
+ // Even though x *is* never moved before the use, we don't want to have
+ // borrowck results be based on whether patterns are disjoint.
+ match y {
+ false if { drop(x); true } => 1,
+ true => {
+ x; //~ ERROR use of moved value: `x`
+ 2
+ }
+ false => 3,
+ };
+
+ let x = String::new();
+ match y {
+ false if let Some(()) = { drop(x); Some(()) } => 1,
+ true => {
+ x; //~ ERROR use of moved value: `x`
+ 2
+ }
+ false => 3,
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr
new file mode 100644
index 000000000..a6261345c
--- /dev/null
+++ b/tests/ui/nll/match-cfg-fake-edges.stderr
@@ -0,0 +1,72 @@
+error[E0381]: used binding `x` isn't initialized
+ --> $DIR/match-cfg-fake-edges.rs:29:13
+ |
+LL | let x;
+ | - binding declared here but left uninitialized
+...
+LL | _ if { x = 2; true } => 1,
+ | ----- binding initialized here in some conditions
+LL | _ if {
+LL | x;
+ | ^ `x` used here but it isn't initialized
+ |
+help: consider assigning a value
+ |
+LL | let x = 0;
+ | +++
+
+error[E0381]: used binding `x` isn't initialized
+ --> $DIR/match-cfg-fake-edges.rs:39:13
+ |
+LL | let x;
+ | - binding declared here but left uninitialized
+LL | match y {
+LL | _ if let Some(()) = { x = 2; Some(()) } => 1,
+ | ----- binding initialized here in some conditions
+LL | _ if let Some(()) = {
+LL | x;
+ | ^ `x` used here but it isn't initialized
+ |
+help: consider assigning a value
+ |
+LL | let x = 0;
+ | +++
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/match-cfg-fake-edges.rs:53:13
+ |
+LL | let x = String::new();
+ | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL | false if { drop(x); true } => 1,
+ | - value moved here
+LL | true => {
+LL | x;
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | false if { drop(x.clone()); true } => 1,
+ | ++++++++
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/match-cfg-fake-edges.rs:63:13
+ |
+LL | let x = String::new();
+ | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | match y {
+LL | false if let Some(()) = { drop(x); Some(()) } => 1,
+ | - value moved here
+LL | true => {
+LL | x;
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+ | ++++++++
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0381, E0382.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/nll/match-cfg-fake-edges2.rs b/tests/ui/nll/match-cfg-fake-edges2.rs
new file mode 100644
index 000000000..48f95e03b
--- /dev/null
+++ b/tests/ui/nll/match-cfg-fake-edges2.rs
@@ -0,0 +1,18 @@
+// Test that we have enough false edges to avoid exposing the exact matching
+// algorithm in borrow checking.
+
+fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
+ let r = &mut y.1;
+ // We don't actually test y.1 to select the second arm, but we don't want
+ // borrowck results to be based on the order we match patterns.
+ match y { //~ ERROR cannot use `y.1` because it was mutably borrowed
+ (false, true) => 1,
+ (true, _) => {
+ r;
+ 2
+ }
+ (false, _) => 3,
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/match-cfg-fake-edges2.stderr b/tests/ui/nll/match-cfg-fake-edges2.stderr
new file mode 100644
index 000000000..c6d15a936
--- /dev/null
+++ b/tests/ui/nll/match-cfg-fake-edges2.stderr
@@ -0,0 +1,15 @@
+error[E0503]: cannot use `y.1` because it was mutably borrowed
+ --> $DIR/match-cfg-fake-edges2.rs:8:5
+ |
+LL | let r = &mut y.1;
+ | -------- borrow of `y.1` occurs here
+...
+LL | match y {
+ | ^^^^^^^ use of borrowed `y.1`
+...
+LL | r;
+ | - 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/nll/match-guards-always-borrow.rs b/tests/ui/nll/match-guards-always-borrow.rs
new file mode 100644
index 000000000..ff63cc092
--- /dev/null
+++ b/tests/ui/nll/match-guards-always-borrow.rs
@@ -0,0 +1,64 @@
+#![feature(if_let_guard)]
+
+// Here is arielb1's basic example from rust-lang/rust#27282
+// that AST borrowck is flummoxed by:
+
+fn should_reject_destructive_mutate_in_guard() {
+ match Some(&4) {
+ None => {},
+ ref mut foo if {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ false } => { },
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(()) = {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ None } => { },
+ Some(s) => std::process::exit(*s),
+ }
+}
+
+// Here below is a case that needs to keep working: we only use the
+// binding via immutable-borrow in the guard, and we mutate in the arm
+// body.
+fn allow_mutate_in_arm_body() {
+ match Some(&4) {
+ None => {},
+ ref mut foo if foo.is_some() => { foo.take(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(_) = foo => { foo.take(); () }
+ Some(s) => std::process::exit(*s),
+ }
+}
+
+// Here below is a case that needs to keep working: we only use the
+// binding via immutable-borrow in the guard, and we move into the arm
+// body.
+fn allow_move_into_arm_body() {
+ match Some(&4) {
+ None => {},
+ mut foo if foo.is_some() => { foo.unwrap(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ mut foo if let Some(_) = foo => { foo.unwrap(); () }
+ Some(s) => std::process::exit(*s),
+ }
+}
+
+fn main() {
+ should_reject_destructive_mutate_in_guard();
+ allow_mutate_in_arm_body();
+ allow_move_into_arm_body();
+}
diff --git a/tests/ui/nll/match-guards-always-borrow.stderr b/tests/ui/nll/match-guards-always-borrow.stderr
new file mode 100644
index 000000000..fa01d3a6f
--- /dev/null
+++ b/tests/ui/nll/match-guards-always-borrow.stderr
@@ -0,0 +1,23 @@
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/match-guards-always-borrow.rs:10:14
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/match-guards-always-borrow.rs:19:14
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/nll/match-guards-partially-borrow.rs b/tests/ui/nll/match-guards-partially-borrow.rs
new file mode 100644
index 000000000..3a9e1654b
--- /dev/null
+++ b/tests/ui/nll/match-guards-partially-borrow.rs
@@ -0,0 +1,332 @@
+// Test that a (partially) mutably borrowed place can be matched on, so long as
+// we don't have to read any values that are mutably borrowed to determine
+// which arm to take.
+//
+// Test that we don't allow mutating the value being matched on in a way that
+// changes which patterns it matches, until we have chosen an arm.
+
+#![feature(if_let_guard)]
+
+fn ok_mutation_in_if_guard(mut q: i32) {
+ match q {
+ // OK, mutation doesn't change which patterns g matches
+ _ if { q = 1; false } => (),
+ _ => (),
+ }
+}
+
+fn ok_mutation_in_if_let_guard(mut q: i32) {
+ match q {
+ // OK, mutation doesn't change which patterns g matches
+ _ if let Some(()) = { q = 1; None } => (),
+ _ => (),
+ }
+}
+
+fn ok_mutation_in_if_guard2(mut u: bool) {
+ // OK value of u is unused before modification
+ match u {
+ _ => (),
+ _ if {
+ u = true;
+ false
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_mutation_in_if_let_guard2(mut u: bool) {
+ // OK value of u is unused before modification
+ match u {
+ _ => (),
+ _ if let Some(()) = {
+ u = true;
+ None
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_mutation_in_if_guard4(mut w: (&mut bool,)) {
+ // OK value of u is unused before modification
+ match w {
+ _ => (),
+ _ if {
+ *w.0 = true;
+ false
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_mutation_in_if_let_guard4(mut w: (&mut bool,)) {
+ // OK value of u is unused before modification
+ match w {
+ _ => (),
+ _ if let Some(()) = {
+ *w.0 = true;
+ None
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_indirect_mutation_in_if_guard(mut p: &bool) {
+ match *p {
+ // OK, mutation doesn't change which patterns s matches
+ _ if {
+ p = &true;
+ false
+ } => (),
+ _ => (),
+ }
+}
+
+fn ok_indirect_mutation_in_if_let_guard(mut p: &bool) {
+ match *p {
+ // OK, mutation doesn't change which patterns s matches
+ _ if let Some(()) = {
+ p = &true;
+ None
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_pattern_in_if_guard(mut q: bool) {
+ match q {
+ // q doesn't match the pattern with the guard by the end of the guard.
+ false if {
+ q = true; //~ ERROR
+ true
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_pattern_in_if_let_guard(mut q: bool) {
+ match q {
+ // q doesn't match the pattern with the guard by the end of the guard.
+ false if let Some(()) = {
+ q = true; //~ ERROR
+ Some(())
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_guard(mut r: bool) {
+ match r {
+ // r matches a previous pattern by the end of the guard.
+ true => (),
+ _ if {
+ r = true; //~ ERROR
+ true
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_let_guard(mut r: bool) {
+ match r {
+ // r matches a previous pattern by the end of the guard.
+ true => (),
+ _ if let Some(()) = {
+ r = true; //~ ERROR
+ Some(())
+ } => (),
+ _ => (),
+ }
+}
+
+fn match_on_borrowed_early_end_if_guard(mut s: bool) {
+ let h = &mut s;
+ // OK value of s is unused before modification.
+ match s {
+ _ if {
+ *h = !*h;
+ false
+ } => (),
+ true => (),
+ false => (),
+ }
+}
+
+fn match_on_borrowed_early_end_if_let_guard(mut s: bool) {
+ let h = &mut s;
+ // OK value of s is unused before modification.
+ match s {
+ _ if let Some(()) = {
+ *h = !*h;
+ None
+ } => (),
+ true => (),
+ false => (),
+ }
+}
+
+fn bad_mutation_in_if_guard(mut t: bool) {
+ match t {
+ true => (),
+ false if {
+ t = true; //~ ERROR
+ false
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_mutation_in_if_let_guard(mut t: bool) {
+ match t {
+ true => (),
+ false if let Some(()) = {
+ t = true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_mutation_in_if_guard2(mut x: Option<Option<&i32>>) {
+ // Check that nested patterns are checked.
+ match x {
+ None => (),
+ Some(None) => (),
+ _ if {
+ match x {
+ Some(ref mut r) => *r = None, //~ ERROR
+ _ => return,
+ };
+ false
+ } => (),
+ Some(Some(r)) => println!("{}", r),
+ }
+}
+
+fn bad_mutation_in_if_let_guard2(mut x: Option<Option<&i32>>) {
+ // Check that nested patterns are checked.
+ match x {
+ None => (),
+ Some(None) => (),
+ _ if let Some(()) = {
+ match x {
+ Some(ref mut r) => *r = None, //~ ERROR
+ _ => return,
+ };
+ None
+ } => (),
+ Some(Some(r)) => println!("{}", r),
+ }
+}
+
+fn bad_mutation_in_if_guard3(mut t: bool) {
+ match t {
+ s if {
+ t = !t; //~ ERROR
+ false
+ } => (), // What value should `s` have in the arm?
+ _ => (),
+ }
+}
+
+fn bad_mutation_in_if_let_guard3(mut t: bool) {
+ match t {
+ s if let Some(()) = {
+ t = !t; //~ ERROR
+ None
+ } => (), // What value should `s` have in the arm?
+ _ => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard(mut y: &bool) {
+ match *y {
+ true => (),
+ false if {
+ y = &true; //~ ERROR
+ false
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_let_guard(mut y: &bool) {
+ match *y {
+ true => (),
+ false if let Some(()) = {
+ y = &true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard2(mut z: &bool) {
+ match z {
+ &true => (),
+ &false if {
+ z = &true; //~ ERROR
+ false
+ } => (),
+ &false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_let_guard2(mut z: &bool) {
+ match z {
+ &true => (),
+ &false if let Some(()) = {
+ z = &true; //~ ERROR
+ None
+ } => (),
+ &false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard3(mut a: &bool) {
+ // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+ match a {
+ true => (),
+ false if {
+ a = &true; //~ ERROR
+ false
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_let_guard3(mut a: &bool) {
+ // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+ match a {
+ true => (),
+ false if let Some(()) = {
+ a = &true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard4(mut b: &bool) {
+ match b {
+ &_ => (),
+ &_ if {
+ b = &true; //~ ERROR
+ false
+ } => (),
+ &b => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_let_guard4(mut b: &bool) {
+ match b {
+ &_ => (),
+ &_ if let Some(()) = {
+ b = &true; //~ ERROR
+ None
+ } => (),
+ &b => (),
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/match-guards-partially-borrow.stderr b/tests/ui/nll/match-guards-partially-borrow.stderr
new file mode 100644
index 000000000..60b8dee71
--- /dev/null
+++ b/tests/ui/nll/match-guards-partially-borrow.stderr
@@ -0,0 +1,170 @@
+error[E0510]: cannot assign `q` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:100:13
+ |
+LL | match q {
+ | - value is immutable in match guard
+...
+LL | q = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `q` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:111:13
+ |
+LL | match q {
+ | - value is immutable in match guard
+...
+LL | q = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:123:13
+ |
+LL | match r {
+ | - value is immutable in match guard
+...
+LL | r = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:135:13
+ |
+LL | match r {
+ | - value is immutable in match guard
+...
+LL | r = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:172:13
+ |
+LL | match t {
+ | - value is immutable in match guard
+...
+LL | t = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:183:13
+ |
+LL | match t {
+ | - value is immutable in match guard
+...
+LL | t = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:197:22
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | Some(ref mut r) => *r = None,
+ | ^^^^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:213:22
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | Some(ref mut r) => *r = None,
+ | ^^^^^^^^^ cannot mutably borrow
+
+error[E0506]: cannot assign to `t` because it is borrowed
+ --> $DIR/match-guards-partially-borrow.rs:225:13
+ |
+LL | s if {
+ | - borrow of `t` occurs here
+LL | t = !t;
+ | ^^^^^^ assignment to borrowed `t` occurs here
+LL | false
+LL | } => (), // What value should `s` have in the arm?
+ | - borrow later used here
+
+error[E0506]: cannot assign to `t` because it is borrowed
+ --> $DIR/match-guards-partially-borrow.rs:235:13
+ |
+LL | s if let Some(()) = {
+ | - borrow of `t` occurs here
+LL | t = !t;
+ | ^^^^^^ assignment to borrowed `t` occurs here
+LL | None
+LL | } => (), // What value should `s` have in the arm?
+ | - borrow later used here
+
+error[E0510]: cannot assign `y` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:246:13
+ |
+LL | match *y {
+ | -- value is immutable in match guard
+...
+LL | y = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `y` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:257:13
+ |
+LL | match *y {
+ | -- value is immutable in match guard
+...
+LL | y = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:268:13
+ |
+LL | match z {
+ | - value is immutable in match guard
+...
+LL | z = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:279:13
+ |
+LL | match z {
+ | - value is immutable in match guard
+...
+LL | z = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:291:13
+ |
+LL | match a {
+ | - value is immutable in match guard
+...
+LL | a = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:303:13
+ |
+LL | match a {
+ | - value is immutable in match guard
+...
+LL | a = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:314:13
+ |
+LL | match b {
+ | - value is immutable in match guard
+...
+LL | b = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:325:13
+ |
+LL | match b {
+ | - value is immutable in match guard
+...
+LL | b = &true;
+ | ^^^^^^^^^ cannot assign
+
+error: aborting due to 18 previous errors
+
+Some errors have detailed explanations: E0506, E0510.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/match-on-borrowed.rs b/tests/ui/nll/match-on-borrowed.rs
new file mode 100644
index 000000000..447dabeb4
--- /dev/null
+++ b/tests/ui/nll/match-on-borrowed.rs
@@ -0,0 +1,96 @@
+// Test that a (partially) mutably borrowed place can be matched on, so long as
+// we don't have to read any values that are mutably borrowed to determine
+// which arm to take.
+//
+// Test that we don't allow mutating the value being matched on in a way that
+// changes which patterns it matches, until we have chosen an arm.
+
+struct A(i32, i32);
+
+fn struct_example(mut a: A) {
+ let x = &mut a.0;
+ match a { // OK, no access of borrowed data
+ _ if false => (),
+ A(_, r) => (),
+ }
+ x;
+}
+
+fn indirect_struct_example(mut b: &mut A) {
+ let x = &mut b.0;
+ match *b { // OK, no access of borrowed data
+ _ if false => (),
+ A(_, r) => (),
+ }
+ x;
+}
+
+fn underscore_example(mut c: i32) {
+ let r = &mut c;
+ match c { // OK, no access of borrowed data (or any data at all)
+ _ if false => (),
+ _ => (),
+ }
+ r;
+}
+
+enum E {
+ V(i32, i32),
+ W,
+}
+
+fn enum_example(mut e: E) {
+ let x = match e {
+ E::V(ref mut x, _) => x,
+ E::W => panic!(),
+ };
+ match e { // Don't know that E uses a tag for its discriminant
+ //~^ ERROR
+ _ if false => (),
+ E::V(_, r) => (),
+ E::W => (),
+ }
+ x;
+}
+
+fn indirect_enum_example(mut f: &mut E) {
+ let x = match *f {
+ E::V(ref mut x, _) => x,
+ E::W => panic!(),
+ };
+ match f { // Don't know that E uses a tag for its discriminant
+ //~^ ERROR
+ _ if false => (),
+ E::V(_, r) => (),
+ E::W => (),
+ }
+ x;
+}
+
+fn match_on_muatbly_borrowed_ref(mut p: &bool) {
+ let r = &mut p;
+ match *p { // OK, no access at all
+ _ if false => (),
+ _ => (),
+ }
+ r;
+}
+
+fn match_on_borrowed(mut t: bool) {
+ let x = &mut t;
+ match t {
+ //~^ ERROR
+ true => (),
+ false => (),
+ }
+ x;
+}
+
+enum Never {}
+
+fn never_init() {
+ let n: Never;
+ match n {} //~ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/match-on-borrowed.stderr b/tests/ui/nll/match-on-borrowed.stderr
new file mode 100644
index 000000000..32666529f
--- /dev/null
+++ b/tests/ui/nll/match-on-borrowed.stderr
@@ -0,0 +1,52 @@
+error[E0503]: cannot use `e` because it was mutably borrowed
+ --> $DIR/match-on-borrowed.rs:47:11
+ |
+LL | E::V(ref mut x, _) => x,
+ | --------- borrow of `e.0` occurs here
+...
+LL | match e { // Don't know that E uses a tag for its discriminant
+ | ^ use of borrowed `e.0`
+...
+LL | x;
+ | - borrow later used here
+
+error[E0503]: cannot use `*f` because it was mutably borrowed
+ --> $DIR/match-on-borrowed.rs:61:11
+ |
+LL | E::V(ref mut x, _) => x,
+ | --------- borrow of `f.0` occurs here
+...
+LL | match f { // Don't know that E uses a tag for its discriminant
+ | ^ use of borrowed `f.0`
+...
+LL | x;
+ | - borrow later used here
+
+error[E0503]: cannot use `t` because it was mutably borrowed
+ --> $DIR/match-on-borrowed.rs:81:5
+ |
+LL | let x = &mut t;
+ | ------ borrow of `t` occurs here
+LL | match t {
+ | ^^^^^^^ use of borrowed `t`
+...
+LL | x;
+ | - borrow later used here
+
+error[E0381]: used binding `n` isn't initialized
+ --> $DIR/match-on-borrowed.rs:93:11
+ |
+LL | let n: Never;
+ | - binding declared here but left uninitialized
+LL | match n {}
+ | ^ `n` used here but it isn't initialized
+ |
+help: consider assigning a value
+ |
+LL | let n: Never = todo!();
+ | +++++++++
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0381, E0503.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs b/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
new file mode 100644
index 000000000..1de32ddf5
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
@@ -0,0 +1,19 @@
+struct Wrap<'p> { p: &'p mut i32 }
+
+impl<'p> Drop for Wrap<'p> {
+ fn drop(&mut self) {
+ *self.p += 1;
+ }
+}
+
+struct Foo<'p> { a: String, b: Wrap<'p> }
+
+fn main() {
+ let mut x = 0;
+ let wrap = Wrap { p: &mut x };
+ let s = String::from("str");
+ let foo = Foo { a: s, b: wrap };
+ std::mem::drop(foo.b);
+ x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
+ // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
+}
diff --git a/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr b/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
new file mode 100644
index 000000000..80e297807
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:17:5
+ |
+LL | let wrap = Wrap { p: &mut x };
+ | ------ borrow of `x` occurs here
+...
+LL | x = 1;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
+LL | }
+ | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/maybe-initialized-drop-uninitialized.rs b/tests/ui/nll/maybe-initialized-drop-uninitialized.rs
new file mode 100644
index 000000000..32e07cd14
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop-uninitialized.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![allow(warnings)]
+
+struct Wrap<'p> { p: &'p mut i32 }
+
+impl<'p> Drop for Wrap<'p> {
+ fn drop(&mut self) {
+ *self.p += 1;
+ }
+}
+
+fn main() {
+ let mut x = 0;
+ let wrap = Wrap { p: &mut x };
+ std::mem::drop(wrap);
+ x = 1; // OK, drop is inert
+}
diff --git a/tests/ui/nll/maybe-initialized-drop-with-fragment.rs b/tests/ui/nll/maybe-initialized-drop-with-fragment.rs
new file mode 100644
index 000000000..778212918
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop-with-fragment.rs
@@ -0,0 +1,20 @@
+#![allow(warnings)]
+
+struct Wrap<'p> { p: &'p mut i32 }
+
+impl<'p> Drop for Wrap<'p> {
+ fn drop(&mut self) {
+ *self.p += 1;
+ }
+}
+
+struct Foo<'p> { a: String, b: Wrap<'p> }
+
+fn main() {
+ let mut x = 0;
+ let wrap = Wrap { p: &mut x };
+ let s = String::from("str");
+ let foo = Foo { a: s, b: wrap };
+ std::mem::drop(foo.a);
+ x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
+}
diff --git a/tests/ui/nll/maybe-initialized-drop-with-fragment.stderr b/tests/ui/nll/maybe-initialized-drop-with-fragment.stderr
new file mode 100644
index 000000000..14074472e
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop-with-fragment.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/maybe-initialized-drop-with-fragment.rs:19:5
+ |
+LL | let wrap = Wrap { p: &mut x };
+ | ------ borrow of `x` occurs here
+...
+LL | x = 1;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | }
+ | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs b/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs
new file mode 100644
index 000000000..b0d6e27a3
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs
@@ -0,0 +1,22 @@
+#![allow(warnings)]
+
+struct Wrap<'p> { p: &'p mut i32 }
+
+impl<'p> Drop for Wrap<'p> {
+ fn drop(&mut self) {
+ *self.p += 1;
+ }
+}
+
+struct Foo<'p> { a: String, b: Wrap<'p> }
+
+fn main() {
+ let mut x = 0;
+ let wrap = Wrap { p: &mut x };
+ let s = String::from("str");
+ let foo = Foo { a: s, b: wrap };
+ std::mem::drop(foo.a);
+ std::mem::drop(foo.b);
+ x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
+ // FIXME ^ This currently errors and it should not.
+}
diff --git a/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr b/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr
new file mode 100644
index 000000000..91c0afc1d
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/maybe-initialized-drop-with-uninitialized-fragments.rs:20:5
+ |
+LL | let wrap = Wrap { p: &mut x };
+ | ------ borrow of `x` occurs here
+...
+LL | x = 1;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | // FIXME ^ This currently errors and it should not.
+LL | }
+ | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/maybe-initialized-drop.rs b/tests/ui/nll/maybe-initialized-drop.rs
new file mode 100644
index 000000000..44a7ede78
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop.rs
@@ -0,0 +1,15 @@
+#![allow(warnings)]
+
+struct Wrap<'p> { p: &'p mut i32 }
+
+impl<'p> Drop for Wrap<'p> {
+ fn drop(&mut self) {
+ *self.p += 1;
+ }
+}
+
+fn main() {
+ let mut x = 0;
+ let wrap = Wrap { p: &mut x };
+ x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
+}
diff --git a/tests/ui/nll/maybe-initialized-drop.stderr b/tests/ui/nll/maybe-initialized-drop.stderr
new file mode 100644
index 000000000..9825ba461
--- /dev/null
+++ b/tests/ui/nll/maybe-initialized-drop.stderr
@@ -0,0 +1,13 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/maybe-initialized-drop.rs:14:5
+ |
+LL | let wrap = Wrap { p: &mut x };
+ | ------ borrow of `x` occurs here
+LL | x = 1;
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | }
+ | - borrow might be used here, when `wrap` is dropped and runs the `Drop` code for type `Wrap`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/nll/mir_check_cast_closure.rs b/tests/ui/nll/mir_check_cast_closure.rs
new file mode 100644
index 000000000..4aebcfdb4
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_closure.rs
@@ -0,0 +1,9 @@
+#![allow(dead_code)]
+
+fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 {
+ let g: fn(_, _) -> _ = |_x, y| y;
+ g
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/mir_check_cast_closure.stderr b/tests/ui/nll/mir_check_cast_closure.stderr
new file mode 100644
index 000000000..72d99aad9
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_closure.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/mir_check_cast_closure.rs:5:5
+ |
+LL | fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | let g: fn(_, _) -> _ = |_x, y| y;
+LL | g
+ | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/mir_check_cast_reify.rs b/tests/ui/nll/mir_check_cast_reify.rs
new file mode 100644
index 000000000..951459911
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_reify.rs
@@ -0,0 +1,39 @@
+#![allow(dead_code)]
+
+// Test that we relate the type of the fn type to the type of the fn
+// ptr when doing a `ReifyFnPointer` cast.
+//
+// This test is a bit tortured, let me explain:
+//
+
+// The `where 'a: 'a` clause here ensures that `'a` is early bound,
+// which is needed below to ensure that this test hits the path we are
+// concerned with.
+fn foo<'a>(x: &'a u32) -> &'a u32
+where
+ 'a: 'a,
+{
+ panic!()
+}
+
+fn bar<'a>(x: &'a u32) -> &'static u32 {
+ // Here, the type of `foo` is `typeof(foo::<'x>)` for some fresh variable `'x`.
+ // During NLL region analysis, this will get renumbered to `typeof(foo::<'?0>)`
+ // where `'?0` is a new region variable.
+ //
+ // (Note that if `'a` on `foo` were late-bound, the type would be
+ // `typeof(foo)`, which would interact differently with because
+ // the renumbering later.)
+ //
+ // This type is then coerced to a fn type `fn(&'?1 u32) -> &'?2
+ // u32`. Here, the `'?1` and `'?2` will have been created during
+ // the NLL region renumbering.
+ //
+ // The MIR type checker must therefore relate `'?0` to `'?1` and `'?2`
+ // as part of checking the `ReifyFnPointer`.
+ let f: fn(_) -> _ = foo;
+ f(x)
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/mir_check_cast_reify.stderr b/tests/ui/nll/mir_check_cast_reify.stderr
new file mode 100644
index 000000000..9be2670fe
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_reify.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/mir_check_cast_reify.rs:35:5
+ |
+LL | fn bar<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+...
+LL | f(x)
+ | ^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/mir_check_cast_unsafe_fn.rs b/tests/ui/nll/mir_check_cast_unsafe_fn.rs
new file mode 100644
index 000000000..8f55bedfb
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_unsafe_fn.rs
@@ -0,0 +1,11 @@
+#![allow(dead_code)]
+
+fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 {
+ // Here the NLL checker must relate the types in `f` to the types
+ // in `g`. These are related via the `UnsafeFnPointer` cast.
+ let g: unsafe fn(_) -> _ = f;
+ unsafe { g(input) }
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/mir_check_cast_unsafe_fn.stderr b/tests/ui/nll/mir_check_cast_unsafe_fn.stderr
new file mode 100644
index 000000000..321d17ba6
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_unsafe_fn.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/mir_check_cast_unsafe_fn.rs:7:14
+ |
+LL | fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+...
+LL | unsafe { g(input) }
+ | ^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/mir_check_cast_unsize.rs b/tests/ui/nll/mir_check_cast_unsize.rs
new file mode 100644
index 000000000..f6c100ab6
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_unsize.rs
@@ -0,0 +1,10 @@
+#![allow(dead_code)]
+
+use std::fmt::Debug;
+
+fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
+ x
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/mir_check_cast_unsize.stderr b/tests/ui/nll/mir_check_cast_unsize.stderr
new file mode 100644
index 000000000..1cd2579e4
--- /dev/null
+++ b/tests/ui/nll/mir_check_cast_unsize.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/mir_check_cast_unsize.rs:6:5
+ |
+LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
+ | -- lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'static`
+ |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug + 'a {
+ | ++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/move-errors.rs b/tests/ui/nll/move-errors.rs
new file mode 100644
index 000000000..e0fcd6250
--- /dev/null
+++ b/tests/ui/nll/move-errors.rs
@@ -0,0 +1,117 @@
+struct A(String);
+struct C(D);
+
+fn suggest_remove_deref() {
+ let a = &A("".to_string());
+ let b = *a;
+ //~^ ERROR
+}
+
+fn suggest_borrow() {
+ let a = [A("".to_string())];
+ let b = a[0];
+ //~^ ERROR
+}
+
+fn suggest_borrow2() {
+ let mut a = A("".to_string());
+ let r = &&mut a;
+ let s = **r;
+ //~^ ERROR
+}
+
+fn suggest_borrow3() {
+ use std::rc::Rc;
+ let mut a = A("".to_string());
+ let r = Rc::new(a);
+ let s = *r;
+ //~^ ERROR
+}
+
+fn suggest_borrow4() {
+ let a = [A("".to_string())][0];
+ //~^ ERROR
+}
+
+fn suggest_borrow5() {
+ let a = &A("".to_string());
+ let A(s) = *a;
+ //~^ ERROR
+}
+
+fn suggest_ref() {
+ let c = C(D(String::new()));
+ let C(D(s)) = c;
+ //~^ ERROR
+}
+
+fn suggest_nothing() {
+ let a = &A("".to_string());
+ let b;
+ b = *a;
+ //~^ ERROR
+}
+
+enum B {
+ V(String),
+ U(D),
+}
+
+struct D(String);
+
+impl Drop for D {
+ fn drop(&mut self) {}
+}
+
+struct F(String, String);
+
+impl Drop for F {
+ fn drop(&mut self) {}
+}
+
+fn probably_suggest_borrow() {
+ let x = [B::V(String::new())];
+ match x[0] {
+ //~^ ERROR
+ B::U(d) => (),
+ B::V(s) => (),
+ }
+}
+
+fn have_to_suggest_ref() {
+ let x = B::V(String::new());
+ match x {
+ //~^ ERROR
+ B::V(s) => drop(s),
+ B::U(D(s)) => (),
+ };
+}
+
+fn two_separate_errors() {
+ let x = (D(String::new()), &String::new());
+ match x {
+ //~^ ERROR
+ //~^^ ERROR
+ (D(s), &t) => (),
+ _ => (),
+ }
+}
+
+fn have_to_suggest_double_ref() {
+ let x = F(String::new(), String::new());
+ match x {
+ //~^ ERROR
+ F(s, mut t) => (),
+ _ => (),
+ }
+}
+
+fn double_binding(x: &Result<String, String>) {
+ match *x {
+ //~^ ERROR
+ Ok(s) | Err(s) => (),
+ }
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr
new file mode 100644
index 000000000..58b8aa31d
--- /dev/null
+++ b/tests/ui/nll/move-errors.stderr
@@ -0,0 +1,210 @@
+error[E0507]: cannot move out of `*a` which is behind a shared reference
+ --> $DIR/move-errors.rs:6:13
+ |
+LL | let b = *a;
+ | ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let b = *a;
+LL + let b = a;
+ |
+
+error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
+ --> $DIR/move-errors.rs:12:13
+ |
+LL | let b = a[0];
+ | ^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `a[_]` has type `A`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let b = &a[0];
+ | +
+
+error[E0507]: cannot move out of `**r` which is behind a shared reference
+ --> $DIR/move-errors.rs:19:13
+ |
+LL | let s = **r;
+ | ^^^ move occurs because `**r` has type `A`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let s = **r;
+LL + let s = *r;
+ |
+
+error[E0507]: cannot move out of an `Rc`
+ --> $DIR/move-errors.rs:27:13
+ |
+LL | let s = *r;
+ | ^^ move occurs because value has type `A`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let s = *r;
+LL + let s = r;
+ |
+
+error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
+ --> $DIR/move-errors.rs:32:13
+ |
+LL | let a = [A("".to_string())][0];
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because value has type `A`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let a = &[A("".to_string())][0];
+ | +
+
+error[E0507]: cannot move out of `a` which is behind a shared reference
+ --> $DIR/move-errors.rs:38:16
+ |
+LL | let A(s) = *a;
+ | - ^^
+ | |
+ | data moved here
+ | move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let A(s) = *a;
+LL + let A(s) = a;
+ |
+
+error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
+ --> $DIR/move-errors.rs:44:19
+ |
+LL | let C(D(s)) = c;
+ | - ^ 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 C(D(ref s)) = c;
+ | +++
+
+error[E0507]: cannot move out of `*a` which is behind a shared reference
+ --> $DIR/move-errors.rs:51:9
+ |
+LL | b = *a;
+ | ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait
+
+error[E0508]: cannot move out of type `[B; 1]`, a non-copy array
+ --> $DIR/move-errors.rs:74:11
+ |
+LL | match x[0] {
+ | ^^^^ cannot move out of here
+LL |
+LL | B::U(d) => (),
+ | - data moved here
+LL | B::V(s) => (),
+ | - ...and here
+ |
+ = note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing here
+ |
+LL | match &x[0] {
+ | +
+
+error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
+ --> $DIR/move-errors.rs:83:11
+ |
+LL | match x {
+ | ^ cannot move out of here
+...
+LL | B::U(D(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 | B::U(D(ref s)) => (),
+ | +++
+
+error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
+ --> $DIR/move-errors.rs:92:11
+ |
+LL | match x {
+ | ^ cannot move out of here
+...
+LL | (D(s), &t) => (),
+ | -
+ | |
+ | data moved here
+ | move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | (D(ref s), &t) => (),
+ | +++
+
+error[E0507]: cannot move out of `*x.1` which is behind a shared reference
+ --> $DIR/move-errors.rs:92:11
+ |
+LL | match x {
+ | ^
+...
+LL | (D(s), &t) => (),
+ | -
+ | |
+ | data moved here
+ | move occurs because `t` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | (D(s), &ref t) => (),
+ | +++
+
+error[E0509]: cannot move out of type `F`, which implements the `Drop` trait
+ --> $DIR/move-errors.rs:102:11
+ |
+LL | match x {
+ | ^ cannot move out of here
+LL |
+LL | F(s, mut t) => (),
+ | - ----- ...and here
+ | |
+ | data moved 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, mut t) => (),
+ | +++
+help: consider borrowing the pattern binding
+ |
+LL | F(s, ref mut t) => (),
+ | +++
+
+error[E0507]: cannot move out of `x` as enum variant `Err` which is behind a shared reference
+ --> $DIR/move-errors.rs:110:11
+ |
+LL | match *x {
+ | ^^
+LL |
+LL | Ok(s) | Err(s) => (),
+ | -
+ | |
+ | data moved here
+ | move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *x {
+LL + match x {
+ |
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0507, E0508, E0509.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/nll/move-subpaths-moves-root.rs b/tests/ui/nll/move-subpaths-moves-root.rs
new file mode 100644
index 000000000..d266c6bb6
--- /dev/null
+++ b/tests/ui/nll/move-subpaths-moves-root.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let x = (vec![1, 2, 3], );
+ drop(x.0);
+ drop(x); //~ ERROR use of partially moved value
+}
diff --git a/tests/ui/nll/move-subpaths-moves-root.stderr b/tests/ui/nll/move-subpaths-moves-root.stderr
new file mode 100644
index 000000000..ae9287f92
--- /dev/null
+++ b/tests/ui/nll/move-subpaths-moves-root.stderr
@@ -0,0 +1,13 @@
+error[E0382]: use of partially moved value: `x`
+ --> $DIR/move-subpaths-moves-root.rs:4:10
+ |
+LL | drop(x.0);
+ | --- value partially moved here
+LL | drop(x);
+ | ^ value used here after partial move
+ |
+ = note: partial move occurs because `x.0` has type `Vec<i32>`, 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/nll/mutating_references.rs b/tests/ui/nll/mutating_references.rs
new file mode 100644
index 000000000..eb46b30b6
--- /dev/null
+++ b/tests/ui/nll/mutating_references.rs
@@ -0,0 +1,24 @@
+// run-pass
+
+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.value);
+ if let Some(n) = list.next.as_mut() {
+ list = n;
+ } else {
+ return result;
+ }
+ }
+}
+
+fn main() {
+ let mut list = List { value: 1, next: None };
+ let vec = to_refs(&mut list);
+ assert_eq!(vec![&mut 1], vec);
+}
diff --git a/tests/ui/nll/normalization-bounds-error.rs b/tests/ui/nll/normalization-bounds-error.rs
new file mode 100644
index 000000000..b6cfcd987
--- /dev/null
+++ b/tests/ui/nll/normalization-bounds-error.rs
@@ -0,0 +1,15 @@
+// Check that we error when a bound from the impl is not satisfied when
+// normalizing an associated type.
+
+trait Visitor<'d> {
+ type Value;
+}
+
+impl<'a, 'd: 'a> Visitor<'d> for &'a () {
+ type Value = ();
+}
+
+fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
+//~^ ERROR
+
+fn main() {}
diff --git a/tests/ui/nll/normalization-bounds-error.stderr b/tests/ui/nll/normalization-bounds-error.stderr
new file mode 100644
index 000000000..0fc3670d6
--- /dev/null
+++ b/tests/ui/nll/normalization-bounds-error.stderr
@@ -0,0 +1,27 @@
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
+ --> $DIR/normalization-bounds-error.rs:12:31
+ |
+LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'d` as defined here...
+ --> $DIR/normalization-bounds-error.rs:12:14
+ |
+LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
+ | ^^
+note: ...but the lifetime must also be valid for the lifetime `'a` as defined here...
+ --> $DIR/normalization-bounds-error.rs:12:18
+ |
+LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
+ | ^^
+note: ...so that the types are compatible
+ --> $DIR/normalization-bounds-error.rs:12:31
+ |
+LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `Visitor<'d>`
+ found `Visitor<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
diff --git a/tests/ui/nll/normalization-bounds.rs b/tests/ui/nll/normalization-bounds.rs
new file mode 100644
index 000000000..bb6d981e0
--- /dev/null
+++ b/tests/ui/nll/normalization-bounds.rs
@@ -0,0 +1,15 @@
+// Check that lifetime bounds get checked the right way around with NLL enabled.
+
+// check-pass
+
+trait Visitor<'d> {
+ type Value;
+}
+
+impl<'a, 'd: 'a> Visitor<'d> for &'a () {
+ type Value = ();
+}
+
+fn visit_seq<'d: 'a, 'a>() -> <&'a () as Visitor<'d>>::Value {}
+
+fn main() {}
diff --git a/tests/ui/nll/outlives-suggestion-more.rs b/tests/ui/nll/outlives-suggestion-more.rs
new file mode 100644
index 000000000..2e1359fe5
--- /dev/null
+++ b/tests/ui/nll/outlives-suggestion-more.rs
@@ -0,0 +1,26 @@
+// Test the more elaborate outlives suggestions.
+
+// Should suggest: 'a: 'c, 'b: 'd
+fn foo1<'a, 'b, 'c, 'd>(x: &'a usize, y: &'b usize) -> (&'c usize, &'d usize) {
+ (x, y) //~ERROR lifetime may not live long enough
+ //~^ERROR lifetime may not live long enough
+}
+
+// Should suggest: 'a: 'c and use 'static instead of 'b
+fn foo2<'a, 'b, 'c>(x: &'a usize, y: &'b usize) -> (&'c usize, &'static usize) {
+ (x, y) //~ERROR lifetime may not live long enough
+ //~^ERROR lifetime may not live long enough
+}
+
+// Should suggest: 'a and 'b are the same and use 'static instead of 'c
+fn foo3<'a, 'b, 'c, 'd, 'e>(
+ x: &'a usize,
+ y: &'b usize,
+ z: &'c usize,
+) -> (&'b usize, &'a usize, &'static usize) {
+ (x, y, z) //~ERROR lifetime may not live long enough
+ //~^ERROR lifetime may not live long enough
+ //~^^ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/outlives-suggestion-more.stderr b/tests/ui/nll/outlives-suggestion-more.stderr
new file mode 100644
index 000000000..c8c604b5b
--- /dev/null
+++ b/tests/ui/nll/outlives-suggestion-more.stderr
@@ -0,0 +1,96 @@
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-more.rs:5:5
+ |
+LL | fn foo1<'a, 'b, 'c, 'd>(x: &'a usize, y: &'b usize) -> (&'c usize, &'d usize) {
+ | -- -- lifetime `'c` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a`
+ |
+ = help: consider adding the following bound: `'a: 'c`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-more.rs:5:5
+ |
+LL | fn foo1<'a, 'b, 'c, 'd>(x: &'a usize, y: &'b usize) -> (&'c usize, &'d usize) {
+ | -- -- lifetime `'d` defined here
+ | |
+ | lifetime `'b` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'d` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'd`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: add bound `'a: 'c`
+ = help: add bound `'b: 'd`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-more.rs:11:5
+ |
+LL | fn foo2<'a, 'b, 'c>(x: &'a usize, y: &'b usize) -> (&'c usize, &'static usize) {
+ | -- -- lifetime `'c` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a`
+ |
+ = help: consider adding the following bound: `'a: 'c`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-more.rs:11:5
+ |
+LL | fn foo2<'a, 'b, 'c>(x: &'a usize, y: &'b usize) -> (&'c usize, &'static usize) {
+ | -- lifetime `'b` defined here
+LL | (x, y)
+ | ^^^^^^ returning this value requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: add bound `'a: 'c`
+ = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-more.rs:21:5
+ |
+LL | fn foo3<'a, 'b, 'c, 'd, 'e>(
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, y, z)
+ | ^^^^^^^^^ 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: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-more.rs:21:5
+ |
+LL | fn foo3<'a, 'b, 'c, 'd, 'e>(
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, y, z)
+ | ^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-more.rs:21:5
+ |
+LL | fn foo3<'a, 'b, 'c, 'd, 'e>(
+ | -- lifetime `'c` defined here
+...
+LL | (x, y, z)
+ | ^^^^^^^^^ returning this value requires that `'c` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: `'a` and `'b` must be the same: replace one with the other
+ = help: replace `'c` with `'static`
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/nll/outlives-suggestion-simple.polonius.stderr b/tests/ui/nll/outlives-suggestion-simple.polonius.stderr
new file mode 100644
index 000000000..c00288f2e
--- /dev/null
+++ b/tests/ui/nll/outlives-suggestion-simple.polonius.stderr
@@ -0,0 +1,124 @@
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:6:5
+ |
+LL | fn foo1<'a, 'b>(x: &'a usize) -> &'b usize {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:10:5
+ |
+LL | fn foo2<'a>(x: &'a usize) -> &'static usize {
+ | -- lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:14:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ 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: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:14:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:22:5
+ |
+LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, x)
+ | ^^^^^^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:22:5
+ |
+LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ | -- -- lifetime `'c` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, x)
+ | ^^^^^^ returning this value requires that `'a` must outlive `'c`
+ |
+ = help: consider adding the following bound: `'a: 'c`
+
+help: add bound `'a: 'b + 'c`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:31:9
+ |
+LL | pub fn foo<'a>(x: &'a usize) -> Self {
+ | -- lifetime `'a` defined here
+LL | Foo { x }
+ | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:41:9
+ |
+LL | impl<'a> Bar<'a> {
+ | -- lifetime `'a` defined here
+LL | pub fn get<'b>(&self) -> &'b usize {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:52:9
+ |
+LL | impl<'a> Baz<'a> {
+ | -- lifetime `'a` defined here
+LL | fn get<'b>(&'b self) -> &'a i32 {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ returning this value requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error[E0521]: borrowed data escapes outside of associated function
+ --> $DIR/outlives-suggestion-simple.rs:73:9
+ |
+LL | fn get_bar(&self) -> Bar2 {
+ | -----
+ | |
+ | `self` declared here, outside of the associated function body
+ | `self` is a reference that is only valid in the associated function body
+LL | Bar2::new(&self)
+ | ^^^^^^^^^^^^^^^^ `self` escapes the associated function body here
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/outlives-suggestion-simple.rs b/tests/ui/nll/outlives-suggestion-simple.rs
new file mode 100644
index 000000000..2a5c31e3a
--- /dev/null
+++ b/tests/ui/nll/outlives-suggestion-simple.rs
@@ -0,0 +1,75 @@
+// Test the simplest of outlives suggestions.
+
+fn foo1<'a, 'b>(x: &'a usize) -> &'b usize {
+ x //~ERROR lifetime may not live long enough
+}
+
+fn foo2<'a>(x: &'a usize) -> &'static usize {
+ x //~ERROR lifetime may not live long enough
+}
+
+fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ (x, y) //~ERROR lifetime may not live long enough
+ //~^ERROR lifetime may not live long enough
+}
+
+fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ // FIXME: ideally, we suggest 'a: 'b + 'c, but as of today (may 04, 2019), the null error
+ // reporting stops after the first error in a MIR def so as not to produce too many errors, so
+ // currently we only report 'a: 'b. The user would then re-run and get another error.
+ (x, x) //~ERROR lifetime may not live long enough
+}
+
+struct Foo<'a> {
+ x: &'a usize,
+}
+
+impl Foo<'static> {
+ pub fn foo<'a>(x: &'a usize) -> Self {
+ Foo { x } //~ERROR lifetime may not live long enough
+ }
+}
+
+struct Bar<'a> {
+ x: &'a usize,
+}
+
+impl<'a> Bar<'a> {
+ pub fn get<'b>(&self) -> &'b usize {
+ self.x //~ERROR lifetime may not live long enough
+ }
+}
+
+// source: https://stackoverflow.com/questions/41417057/why-do-i-get-a-lifetime-error-when-i-use-a-mutable-reference-in-a-struct-instead
+struct Baz<'a> {
+ x: &'a mut i32,
+}
+
+impl<'a> Baz<'a> {
+ fn get<'b>(&'b self) -> &'a i32 {
+ self.x //~ERROR lifetime may not live long enough
+ }
+}
+
+// source: https://stackoverflow.com/questions/41204134/rust-lifetime-error
+struct Bar2<'a> {
+ bar: &'a str,
+}
+impl<'a> Bar2<'a> {
+ fn new(foo: &'a Foo2<'a>) -> Bar2<'a> {
+ Bar2 { bar: foo.raw }
+ }
+}
+
+pub struct Foo2<'a> {
+ raw: &'a str,
+ cell: std::cell::Cell<&'a str>,
+}
+impl<'a> Foo2<'a> {
+ // should not produce outlives suggestions to name 'self
+ fn get_bar(&self) -> Bar2 {
+ Bar2::new(&self) //~ERROR lifetime may not live long enough
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/outlives-suggestion-simple.stderr b/tests/ui/nll/outlives-suggestion-simple.stderr
new file mode 100644
index 000000000..a8368c494
--- /dev/null
+++ b/tests/ui/nll/outlives-suggestion-simple.stderr
@@ -0,0 +1,104 @@
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:4:5
+ |
+LL | fn foo1<'a, 'b>(x: &'a usize) -> &'b usize {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x
+ | ^ 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: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:8:5
+ |
+LL | fn foo2<'a>(x: &'a usize) -> &'static usize {
+ | -- lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:12:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ 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: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:12:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:20:5
+ |
+LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, x)
+ | ^^^^^^ 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: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:29:9
+ |
+LL | pub fn foo<'a>(x: &'a usize) -> Self {
+ | -- lifetime `'a` defined here
+LL | Foo { x }
+ | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:39:9
+ |
+LL | impl<'a> Bar<'a> {
+ | -- lifetime `'a` defined here
+LL | pub fn get<'b>(&self) -> &'b usize {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ associated 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: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:50:9
+ |
+LL | impl<'a> Baz<'a> {
+ | -- lifetime `'a` defined here
+LL | fn get<'b>(&'b self) -> &'a i32 {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:71:9
+ |
+LL | impl<'a> Foo2<'a> {
+ | -- lifetime `'a` defined here
+LL | // should not produce outlives suggestions to name 'self
+LL | fn get_bar(&self) -> Bar2 {
+ | - let's call the lifetime of this reference `'1`
+LL | Bar2::new(&self)
+ | ^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/nll/polonius/assignment-kills-loans.rs b/tests/ui/nll/polonius/assignment-kills-loans.rs
new file mode 100644
index 000000000..696bf61ce
--- /dev/null
+++ b/tests/ui/nll/polonius/assignment-kills-loans.rs
@@ -0,0 +1,87 @@
+#![allow(dead_code)]
+
+// This tests the various kinds of assignments there are. Polonius used to generate `killed`
+// facts only on simple assignments, but not projections, incorrectly causing errors to be emitted
+// for code accepted by NLL. They are all variations from example code in the NLL RFC.
+
+// check-pass
+// compile-flags: -Z polonius
+
+struct List<T> {
+ value: T,
+ next: Option<Box<List<T>>>,
+}
+
+// Assignment to a local: the `list` assignment should clear the existing
+// borrows of `list.value` and `list.next`
+fn assignment_to_local<T>(mut list: &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;
+ }
+ }
+}
+
+// Assignment to a deref projection: the `*list` assignment should clear the existing
+// borrows of `list.value` and `list.next`
+fn assignment_to_deref_projection<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;
+ }
+ }
+}
+
+// Assignment to a field projection: the `list.0` assignment should clear the existing
+// borrows of `list.0.value` and `list.0.next`
+fn assignment_to_field_projection<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;
+ }
+ }
+}
+
+// Assignment to a deref field projection: the `*list.0` assignment should clear the existing
+// borrows of `list.0.value` and `list.0.next`
+fn assignment_to_deref_field_projection<T>(mut list: (Box<&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;
+ }
+ }
+}
+
+// Similar to `assignment_to_deref_field_projection` but through a longer projection chain
+fn assignment_through_projection_chain<T>(
+ mut list: (((((Box<&mut List<T>>,),),),),),
+) -> Vec<&mut T> {
+ let mut result = vec![];
+ loop {
+ result.push(&mut ((((list.0).0).0).0).0.value);
+ if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
+ *((((list.0).0).0).0).0 = n;
+ } else {
+ return result;
+ }
+ }
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.rs b/tests/ui/nll/polonius/assignment-to-differing-field.rs
new file mode 100644
index 000000000..7ec3b9049
--- /dev/null
+++ b/tests/ui/nll/polonius/assignment-to-differing-field.rs
@@ -0,0 +1,49 @@
+#![allow(dead_code)]
+
+// Compared to `assignment-kills-loans.rs`, we check here
+// that we do not kill too many borrows. Assignments to the `.1`
+// field projections should leave the borrows on `.0` intact.
+
+// compile-flags: -Z polonius
+
+struct List<T> {
+ value: T,
+ next: Option<Box<List<T>>>,
+}
+
+
+fn assignment_to_field_projection<'a, T>(
+ mut list: (&'a mut List<T>, &'a mut List<T>),
+) -> Vec<&'a mut T> {
+ let mut result = vec![];
+ loop {
+ result.push(&mut (list.0).value);
+ //~^ ERROR cannot borrow `list.0.value` as mutable
+
+ if let Some(n) = (list.0).next.as_mut() {
+ //~^ ERROR cannot borrow `list.0.next` as mutable
+ list.1 = n;
+ } else {
+ return result;
+ }
+ }
+}
+
+fn assignment_through_projection_chain<'a, T>(
+ mut list: (((((Box<&'a mut List<T>>, Box<&'a mut List<T>>),),),),),
+) -> Vec<&'a mut T> {
+ let mut result = vec![];
+ loop {
+ result.push(&mut ((((list.0).0).0).0).0.value);
+ //~^ ERROR cannot borrow `list.0.0.0.0.0.value` as mutable
+
+ if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
+ //~^ ERROR cannot borrow `list.0.0.0.0.0.next` as mutable
+ *((((list.0).0).0).0).1 = n;
+ } else {
+ return result;
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.stderr b/tests/ui/nll/polonius/assignment-to-differing-field.stderr
new file mode 100644
index 000000000..afa1b9344
--- /dev/null
+++ b/tests/ui/nll/polonius/assignment-to-differing-field.stderr
@@ -0,0 +1,51 @@
+error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time
+ --> $DIR/assignment-to-differing-field.rs:20:21
+ |
+LL | fn assignment_to_field_projection<'a, T>(
+ | -- lifetime `'a` defined here
+...
+LL | result.push(&mut (list.0).value);
+ | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop
+...
+LL | return result;
+ | ------ returning this value requires that `list.0.value` is borrowed for `'a`
+
+error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time
+ --> $DIR/assignment-to-differing-field.rs:23:26
+ |
+LL | fn assignment_to_field_projection<'a, T>(
+ | -- lifetime `'a` defined here
+...
+LL | if let Some(n) = (list.0).next.as_mut() {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `list.0.next` was mutably borrowed here in the previous iteration of the loop
+ | argument requires that `list.0.next` is borrowed for `'a`
+
+error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time
+ --> $DIR/assignment-to-differing-field.rs:37:21
+ |
+LL | fn assignment_through_projection_chain<'a, T>(
+ | -- lifetime `'a` defined here
+...
+LL | result.push(&mut ((((list.0).0).0).0).0.value);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.value` was mutably borrowed here in the previous iteration of the loop
+...
+LL | return result;
+ | ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a`
+
+error[E0499]: cannot borrow `list.0.0.0.0.0.next` as mutable more than once at a time
+ --> $DIR/assignment-to-differing-field.rs:40:26
+ |
+LL | fn assignment_through_projection_chain<'a, T>(
+ | -- lifetime `'a` defined here
+...
+LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop
+ | argument requires that `list.0.0.0.0.0.next` is borrowed for `'a`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/nll/polonius/call-kills-loans.rs b/tests/ui/nll/polonius/call-kills-loans.rs
new file mode 100644
index 000000000..f430e9211
--- /dev/null
+++ b/tests/ui/nll/polonius/call-kills-loans.rs
@@ -0,0 +1,23 @@
+// `Call` terminators can write to a local which has existing loans
+// and those need to be killed like a regular assignment to a local.
+// This is a simplified version of issue 47680, is correctly accepted
+// by NLL but was incorrectly rejected by Polonius because of these
+// missing `killed` facts.
+
+// check-pass
+// compile-flags: -Z polonius
+
+struct Thing;
+
+impl Thing {
+ fn next(&mut self) -> &mut Self { unimplemented!() }
+}
+
+fn main() {
+ let mut temp = &mut Thing;
+
+ loop {
+ let v = temp.next();
+ temp = v; // accepted by NLL, was incorrectly rejected by Polonius
+ }
+}
diff --git a/tests/ui/nll/polonius/issue-46589.rs b/tests/ui/nll/polonius/issue-46589.rs
new file mode 100644
index 000000000..648280a1d
--- /dev/null
+++ b/tests/ui/nll/polonius/issue-46589.rs
@@ -0,0 +1,31 @@
+// This test is a copy of `ui/nll/issue-46589.rs` which fails in NLL but succeeds in Polonius.
+// As we can't have a test here which conditionally passes depending on a test
+// revision/compile-flags. We ensure here that it passes in Polonius mode.
+
+// check-pass
+// compile-flags: -Z polonius
+
+struct Foo;
+
+impl Foo {
+ fn get_self(&mut self) -> Option<&mut Self> {
+ Some(self)
+ }
+
+ fn new_self(&mut self) -> &mut Self {
+ self
+ }
+
+ fn trigger_bug(&mut self) {
+ let other = &mut (&mut *self);
+
+ *other = match (*other).get_self() {
+ Some(s) => s,
+ None => (*other).new_self()
+ };
+
+ let c = other;
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/polonius/polonius-smoke-test.rs b/tests/ui/nll/polonius/polonius-smoke-test.rs
new file mode 100644
index 000000000..c4344af71
--- /dev/null
+++ b/tests/ui/nll/polonius/polonius-smoke-test.rs
@@ -0,0 +1,46 @@
+// Check that Polonius borrow check works for simple cases.
+// compile-flags: -Z polonius
+
+pub fn return_ref_to_local() -> &'static i32 {
+ let x = 0;
+ &x //~ ERROR
+}
+
+pub fn use_while_mut() {
+ let mut x = 0;
+ let y = &mut x;
+ let z = x; //~ ERROR
+ let w = y;
+}
+
+pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 {
+ let y = &mut *x;
+ let z = x; //~ ERROR
+ y
+}
+
+// Cases like this are why we have Polonius.
+pub fn position_dependent_outlives(x: &mut i32, cond: bool) -> &mut i32 {
+ let y = &mut *x;
+ if cond {
+ return y;
+ } else {
+ *x = 0;
+ return x;
+ }
+}
+
+fn foo<'a, 'b>(p: &'b &'a mut usize) -> &'b usize {
+ p
+}
+
+// Check that we create constraints for well-formedness of function arguments
+fn well_formed_function_inputs() {
+ let s = &mut 1;
+ let r = &mut *s;
+ let tmp = foo(&r);
+ s; //~ ERROR
+ tmp;
+}
+
+fn main() {}
diff --git a/tests/ui/nll/polonius/polonius-smoke-test.stderr b/tests/ui/nll/polonius/polonius-smoke-test.stderr
new file mode 100644
index 000000000..fa1a6a9c9
--- /dev/null
+++ b/tests/ui/nll/polonius/polonius-smoke-test.stderr
@@ -0,0 +1,43 @@
+error[E0515]: cannot return reference to local variable `x`
+ --> $DIR/polonius-smoke-test.rs:6:5
+ |
+LL | &x
+ | ^^ returns a reference to data owned by the current function
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+ --> $DIR/polonius-smoke-test.rs:12:13
+ |
+LL | let y = &mut x;
+ | ------ borrow of `x` occurs here
+LL | let z = x;
+ | ^ use of borrowed `x`
+LL | let w = y;
+ | - borrow later used here
+
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/polonius-smoke-test.rs:18:13
+ |
+LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 {
+ | - let's call the lifetime of this reference `'1`
+LL | let y = &mut *x;
+ | ------- borrow of `*x` occurs here
+LL | let z = x;
+ | ^ move out of `x` occurs here
+LL | y
+ | - returning this value requires that `*x` is borrowed for `'1`
+
+error[E0505]: cannot move out of `s` because it is borrowed
+ --> $DIR/polonius-smoke-test.rs:42:5
+ |
+LL | let r = &mut *s;
+ | ------- borrow of `*s` occurs here
+LL | let tmp = foo(&r);
+LL | s;
+ | ^ move out of `s` occurs here
+LL | tmp;
+ | --- borrow later used here
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0503, E0505, E0515.
+For more information about an error, try `rustc --explain E0503`.
diff --git a/tests/ui/nll/polonius/storagedead-kills-loans.rs b/tests/ui/nll/polonius/storagedead-kills-loans.rs
new file mode 100644
index 000000000..669e077de
--- /dev/null
+++ b/tests/ui/nll/polonius/storagedead-kills-loans.rs
@@ -0,0 +1,28 @@
+// Whenever a `StorageDead` MIR statement destroys a value `x`,
+// we should kill all loans of `x`. This is extracted from `rand 0.4.6`,
+// is correctly accepted by NLL but was incorrectly rejected by
+// Polonius because of these missing `killed` facts.
+
+// check-pass
+// compile-flags: -Z polonius
+
+use std::{io, mem};
+use std::io::Read;
+
+#[allow(dead_code)]
+fn fill(r: &mut dyn Read, mut buf: &mut [u8]) -> io::Result<()> {
+ while buf.len() > 0 {
+ match r.read(buf).unwrap() {
+ 0 => return Err(io::Error::new(io::ErrorKind::Other,
+ "end of file reached")),
+ n => buf = &mut mem::replace(&mut buf, &mut [])[n..],
+ // ^- Polonius had multiple errors on the previous line (where NLL has none)
+ // as it didn't know `buf` was killed here, and would
+ // incorrectly reject both the borrow expression, and the assignment.
+ }
+ }
+ Ok(())
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/polonius/subset-relations.rs b/tests/ui/nll/polonius/subset-relations.rs
new file mode 100644
index 000000000..f223ab177
--- /dev/null
+++ b/tests/ui/nll/polonius/subset-relations.rs
@@ -0,0 +1,29 @@
+// Checks that Polonius can compute cases of universal regions errors:
+// "illegal subset relation errors", cases where analysis finds that
+// two free regions outlive each other, without any evidence that this
+// relation holds.
+
+// compile-flags: -Z polonius
+
+// returning `y` requires that `'b: 'a`, but it's not known to be true
+fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ y //~ ERROR
+}
+
+// `'b: 'a` is explicitly declared
+fn valid_subset<'a, 'b: 'a>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ y
+}
+
+// because of `x`, it is implied that `'b: 'a` holds
+fn implied_bounds_subset<'a, 'b>(x: &'a &'b mut u32) -> &'a u32 {
+ x
+}
+
+// `'b: 'a` is declared, and `'a: 'c` is known via implied bounds:
+// `'b: 'c` is therefore known to hold transitively
+fn transitively_valid_subset<'a, 'b: 'a, 'c>(x: &'c &'a u32, y: &'b u32) -> &'c u32 {
+ y
+}
+
+fn main() {}
diff --git a/tests/ui/nll/polonius/subset-relations.stderr b/tests/ui/nll/polonius/subset-relations.stderr
new file mode 100644
index 000000000..6df5563ea
--- /dev/null
+++ b/tests/ui/nll/polonius/subset-relations.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/subset-relations.rs:10:5
+ |
+LL | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | y
+ | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/process_or_insert_default.rs b/tests/ui/nll/process_or_insert_default.rs
new file mode 100644
index 000000000..84ac9bbd0
--- /dev/null
+++ b/tests/ui/nll/process_or_insert_default.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+use std::collections::HashMap;
+
+fn process_or_insert_default(map: &mut HashMap<usize, String>, key: usize) {
+ match map.get_mut(&key) {
+ Some(value) => {
+ process(value);
+ }
+ None => {
+ map.insert(key, "".to_string());
+ }
+ }
+}
+
+fn process(x: &str) {
+ assert_eq!(x, "Hello, world");
+}
+
+fn main() {
+ let map = &mut HashMap::new();
+ map.insert(22, format!("Hello, world"));
+ map.insert(44, format!("Goodbye, world"));
+ process_or_insert_default(map, 22);
+ process_or_insert_default(map, 66);
+ assert_eq!(map[&66], "");
+}
diff --git a/tests/ui/nll/projection-return.rs b/tests/ui/nll/projection-return.rs
new file mode 100644
index 000000000..be141339a
--- /dev/null
+++ b/tests/ui/nll/projection-return.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+#![feature(rustc_attrs)]
+
+trait Foo {
+ type Bar;
+}
+
+impl Foo for () {
+ type Bar = u32;
+}
+
+fn foo() -> <() as Foo>::Bar {
+ 22
+}
+
+fn main() { }
diff --git a/tests/ui/nll/promotable-mutable-zst-doesnt-conflict.rs b/tests/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
new file mode 100644
index 000000000..3b06b0db3
--- /dev/null
+++ b/tests/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
@@ -0,0 +1,11 @@
+// Check that mutable promoted length zero arrays don't check for conflicting
+// access
+
+// check-pass
+
+pub fn main() {
+ let mut x: Vec<&[i32; 0]> = Vec::new();
+ for _ in 0..10 {
+ x.push(&[]);
+ }
+}
diff --git a/tests/ui/nll/promoted-bounds.rs b/tests/ui/nll/promoted-bounds.rs
new file mode 100644
index 000000000..5f95ae13c
--- /dev/null
+++ b/tests/ui/nll/promoted-bounds.rs
@@ -0,0 +1,25 @@
+fn shorten_lifetime<'a, 'b, 'min>(a: &'a i32, b: &'b i32) -> &'min i32
+where
+ 'a: 'min,
+ 'b: 'min,
+{
+ if *a < *b {
+ &a
+ } else {
+ &b
+ }
+}
+
+fn main() {
+ let promoted_fn_item_ref = &shorten_lifetime;
+
+ let a = &5;
+ let ptr = {
+ let l = 3;
+ let b = &l; //~ ERROR does not live long enough
+ let c = promoted_fn_item_ref(a, b);
+ c
+ };
+
+ println!("ptr = {:?}", ptr);
+}
diff --git a/tests/ui/nll/promoted-bounds.stderr b/tests/ui/nll/promoted-bounds.stderr
new file mode 100644
index 000000000..df347f4e7
--- /dev/null
+++ b/tests/ui/nll/promoted-bounds.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `l` does not live long enough
+ --> $DIR/promoted-bounds.rs:19:17
+ |
+LL | let ptr = {
+ | --- borrow later stored here
+LL | let l = 3;
+LL | let b = &l;
+ | ^^ borrowed value does not live long enough
+...
+LL | };
+ | - `l` 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/nll/promoted-closure-pair.rs b/tests/ui/nll/promoted-closure-pair.rs
new file mode 100644
index 000000000..cc9f17fd4
--- /dev/null
+++ b/tests/ui/nll/promoted-closure-pair.rs
@@ -0,0 +1,10 @@
+// Check that we handle multiple closures in the same promoted constant.
+
+fn foo() -> &'static i32 {
+ let z = 0;
+ let p = &(|y| y, |y| y);
+ p.0(&z);
+ p.1(&z) //~ ERROR cannot return
+}
+
+fn main() {}
diff --git a/tests/ui/nll/promoted-closure-pair.stderr b/tests/ui/nll/promoted-closure-pair.stderr
new file mode 100644
index 000000000..000bdf858
--- /dev/null
+++ b/tests/ui/nll/promoted-closure-pair.stderr
@@ -0,0 +1,12 @@
+error[E0515]: cannot return value referencing local variable `z`
+ --> $DIR/promoted-closure-pair.rs:7:5
+ |
+LL | p.1(&z)
+ | ^^^^--^
+ | | |
+ | | `z` is borrowed here
+ | 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/nll/promoted-liveness.rs b/tests/ui/nll/promoted-liveness.rs
new file mode 100644
index 000000000..e5a8e1e5c
--- /dev/null
+++ b/tests/ui/nll/promoted-liveness.rs
@@ -0,0 +1,8 @@
+// Test that promoted that have larger mir bodies than their containing function
+// don't cause an ICE.
+
+// check-pass
+
+fn main() {
+ &["0", "1", "2", "3", "4", "5", "6", "7"];
+}
diff --git a/tests/ui/nll/rc-loop.rs b/tests/ui/nll/rc-loop.rs
new file mode 100644
index 000000000..e59303d1f
--- /dev/null
+++ b/tests/ui/nll/rc-loop.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+// A test for something that NLL enables. It sometimes happens that
+// the `while let` pattern makes some borrows from a variable (in this
+// case, `x`) that you need in order to compute the next value for
+// `x`. The lexical checker makes this very painful. The NLL checker
+// does not.
+
+use std::rc::Rc;
+
+#[derive(Debug, PartialEq, Eq)]
+enum Foo {
+ Base(usize),
+ Next(Rc<Foo>),
+}
+
+fn find_base(mut x: Rc<Foo>) -> Rc<Foo> {
+ while let Foo::Next(n) = &*x {
+ x = n.clone();
+ }
+ x
+}
+
+fn main() {
+ let chain = Rc::new(Foo::Next(Rc::new(Foo::Base(44))));
+ let base = find_base(chain);
+ assert_eq!(&*base, &Foo::Base(44));
+}
diff --git a/tests/ui/nll/ref-suggestion.rs b/tests/ui/nll/ref-suggestion.rs
new file mode 100644
index 000000000..346d118f0
--- /dev/null
+++ b/tests/ui/nll/ref-suggestion.rs
@@ -0,0 +1,17 @@
+fn main() {
+ let x = vec![1];
+ let y = x;
+ x; //~ ERROR use of moved value
+
+ let x = vec![1];
+ let mut y = x;
+ x; //~ ERROR use of moved value
+
+ let x = (Some(vec![1]), ());
+
+ match x {
+ (Some(y), ()) => {},
+ _ => {},
+ }
+ x; //~ ERROR use of partially moved value
+}
diff --git a/tests/ui/nll/ref-suggestion.stderr b/tests/ui/nll/ref-suggestion.stderr
new file mode 100644
index 000000000..b1f5117cb
--- /dev/null
+++ b/tests/ui/nll/ref-suggestion.stderr
@@ -0,0 +1,48 @@
+error[E0382]: use of moved value: `x`
+ --> $DIR/ref-suggestion.rs:4:5
+ |
+LL | let x = vec![1];
+ | - move occurs because `x` has type `Vec<i32>`, which does not implement the `Copy` trait
+LL | let y = x;
+ | - value moved here
+LL | x;
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | let y = x.clone();
+ | ++++++++
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/ref-suggestion.rs:8:5
+ |
+LL | let x = vec![1];
+ | - move occurs because `x` has type `Vec<i32>`, which does not implement the `Copy` trait
+LL | let mut y = x;
+ | - value moved here
+LL | x;
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | let mut y = x.clone();
+ | ++++++++
+
+error[E0382]: use of partially moved value: `x`
+ --> $DIR/ref-suggestion.rs:16:5
+ |
+LL | (Some(y), ()) => {},
+ | - value partially moved here
+...
+LL | x;
+ | ^ value used here after partial move
+ |
+ = note: partial move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | (Some(ref y), ()) => {},
+ | +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/nll/reference-carried-through-struct-field.rs b/tests/ui/nll/reference-carried-through-struct-field.rs
new file mode 100644
index 000000000..effd61084
--- /dev/null
+++ b/tests/ui/nll/reference-carried-through-struct-field.rs
@@ -0,0 +1,10 @@
+struct Wrap<'a> { w: &'a mut u32 }
+
+fn foo() {
+ let mut x = 22;
+ let wrapper = Wrap { w: &mut x };
+ x += 1; //~ ERROR cannot use `x` because it was mutably borrowed [E0503]
+ *wrapper.w += 1;
+}
+
+fn main() { }
diff --git a/tests/ui/nll/reference-carried-through-struct-field.stderr b/tests/ui/nll/reference-carried-through-struct-field.stderr
new file mode 100644
index 000000000..56d878e43
--- /dev/null
+++ b/tests/ui/nll/reference-carried-through-struct-field.stderr
@@ -0,0 +1,13 @@
+error[E0503]: cannot use `x` because it was mutably borrowed
+ --> $DIR/reference-carried-through-struct-field.rs:6:5
+ |
+LL | let wrapper = Wrap { w: &mut x };
+ | ------ borrow of `x` occurs here
+LL | x += 1;
+ | ^^^^^^ use of borrowed `x`
+LL | *wrapper.w += 1;
+ | --------------- 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/nll/region-ends-after-if-condition.rs b/tests/ui/nll/region-ends-after-if-condition.rs
new file mode 100644
index 000000000..f67de03ca
--- /dev/null
+++ b/tests/ui/nll/region-ends-after-if-condition.rs
@@ -0,0 +1,32 @@
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` includes the points after `&v[0]` up to (but not
+// including) the call to `use_x`. The `else` branch is not included.
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+struct MyStruct {
+ field: String
+}
+
+fn foo1() {
+ let mut my_struct = MyStruct { field: format!("Hello") };
+
+ let value = &my_struct.field;
+ if value.is_empty() {
+ my_struct.field.push_str("Hello, world!");
+ }
+}
+
+fn foo2() {
+ let mut my_struct = MyStruct { field: format!("Hello") };
+
+ let value = &my_struct.field;
+ if value.is_empty() {
+ my_struct.field.push_str("Hello, world!");
+ //~^ ERROR [E0502]
+ }
+ drop(value);
+}
+
+fn main() { }
diff --git a/tests/ui/nll/region-ends-after-if-condition.stderr b/tests/ui/nll/region-ends-after-if-condition.stderr
new file mode 100644
index 000000000..c03e38579
--- /dev/null
+++ b/tests/ui/nll/region-ends-after-if-condition.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable
+ --> $DIR/region-ends-after-if-condition.rs:26:9
+ |
+LL | let value = &my_struct.field;
+ | ---------------- immutable borrow occurs here
+LL | if value.is_empty() {
+LL | my_struct.field.push_str("Hello, world!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+...
+LL | drop(value);
+ | ----- 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/nll/relate_tys/fn-subtype.rs b/tests/ui/nll/relate_tys/fn-subtype.rs
new file mode 100644
index 000000000..ba89fa19c
--- /dev/null
+++ b/tests/ui/nll/relate_tys/fn-subtype.rs
@@ -0,0 +1,8 @@
+// Test that NLL produces correct spans for higher-ranked subtyping errors.
+//
+// compile-flags:-Zno-leak-check
+
+fn main() {
+ let x: fn(&'static ()) = |_| {};
+ let y: for<'a> fn(&'a ()) = x; //~ ERROR mismatched types [E0308]
+}
diff --git a/tests/ui/nll/relate_tys/fn-subtype.stderr b/tests/ui/nll/relate_tys/fn-subtype.stderr
new file mode 100644
index 000000000..21073647e
--- /dev/null
+++ b/tests/ui/nll/relate_tys/fn-subtype.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/fn-subtype.rs:7:33
+ |
+LL | let y: for<'a> fn(&'a ()) = x;
+ | ^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'a> fn(&'a ())`
+ found fn pointer `fn(&())`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs b/tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs
new file mode 100644
index 000000000..7891bab09
--- /dev/null
+++ b/tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs
@@ -0,0 +1,24 @@
+// Test that the NLL `relate_tys` code correctly deduces that a
+// function returning either argument CANNOT be upcast to one
+// that returns always its first argument.
+//
+// compile-flags:-Zno-leak-check
+
+fn make_it() -> for<'a> fn(&'a u32, &'a u32) -> &'a u32 {
+ panic!()
+}
+
+fn foo() {
+ let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
+ //~^ ERROR mismatched types [E0308]
+ drop(a);
+}
+
+fn bar() {
+ // The code path for patterns is mildly different, so go ahead and
+ // test that too:
+ let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
+ //~^ ERROR mismatched types [E0308]
+}
+
+fn main() {}
diff --git a/tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr b/tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
new file mode 100644
index 000000000..7d76c916d
--- /dev/null
+++ b/tests/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+ --> $DIR/hr-fn-aaa-as-aba.rs:12:58
+ |
+LL | let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
+ | ^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32`
+ found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32`
+
+error[E0308]: mismatched types
+ --> $DIR/hr-fn-aaa-as-aba.rs:20:12
+ |
+LL | let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32`
+ found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs b/tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs
new file mode 100644
index 000000000..92730341c
--- /dev/null
+++ b/tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs
@@ -0,0 +1,23 @@
+// Test an interesting corner case that ought to be legal (though the
+// current code actually gets it wrong, see below): a fn that takes
+// two arguments that are references with the same lifetime is in fact
+// equivalent to a fn that takes two references with distinct
+// lifetimes. This is true because the two functions can call one
+// another -- effectively, the single lifetime `'a` is just inferred
+// to be the intersection of the two distinct lifetimes.
+//
+// check-pass
+// compile-flags:-Zno-leak-check
+
+use std::cell::Cell;
+
+fn make_cell_aa() -> Cell<for<'a> fn(&'a u32, &'a u32)> {
+ panic!()
+}
+
+fn aa_eq_ab() {
+ let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
+ drop(a);
+}
+
+fn main() { }
diff --git a/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs b/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs
new file mode 100644
index 000000000..7cc0acf45
--- /dev/null
+++ b/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs
@@ -0,0 +1,15 @@
+// Test that the NLL `relate_tys` code correctly deduces that a
+// function returning always its first argument can be upcast to one
+// that returns either first or second argument.
+//
+// check-pass
+// compile-flags:-Zno-leak-check
+
+fn make_it() -> for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 {
+ panic!()
+}
+
+fn main() {
+ let a: for<'a> fn(&'a u32, &'a u32) -> &'a u32 = make_it();
+ drop(a);
+}
diff --git a/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
new file mode 100644
index 000000000..05e2ea047
--- /dev/null
+++ b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
@@ -0,0 +1,34 @@
+// Test that the NLL solver cannot find a solution
+// for `exists<R1> { forall<R1> { R2: R1 } }`.
+//
+// In this test, the impl should match `fn(T)` for some `T`,
+// but we ask it to match `for<'a> fn(&'a ())`. Due to argument
+// contravariance, this effectively requires a `T = &'b ()` where
+// `forall<'a> { 'a: 'b }`. Therefore, we get an error.
+//
+// Note the use of `-Zno-leak-check` here. This is presently required in order
+// to skip the leak-check errors.
+//
+// c.f. Issue #57642.
+//
+// compile-flags:-Zno-leak-check
+
+trait Y {
+ type F;
+ fn make_f() -> Self::F;
+}
+
+impl<T> Y for fn(T) {
+ type F = fn(T);
+
+ fn make_f() -> Self::F {
+ |_| {}
+ }
+}
+
+fn main() {
+ let _x = <fn(&())>::make_f();
+ //~^ ERROR implementation of `Y` is not general enough
+ //~| ERROR implementation of `Y` is not general enough
+ //~| ERROR implementation of `Y` is not general enough
+}
diff --git a/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
new file mode 100644
index 000000000..b945ffedd
--- /dev/null
+++ b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
@@ -0,0 +1,29 @@
+error: implementation of `Y` is not general enough
+ --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14
+ |
+LL | let _x = <fn(&())>::make_f();
+ | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+ |
+ = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())`
+ = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+
+error: implementation of `Y` is not general enough
+ --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14
+ |
+LL | let _x = <fn(&())>::make_f();
+ | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+ |
+ = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())`
+ = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+
+error: implementation of `Y` is not general enough
+ --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14
+ |
+LL | let _x = <fn(&())>::make_f();
+ | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+ |
+ = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())`
+ = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/nll/relate_tys/issue-48071.rs b/tests/ui/nll/relate_tys/issue-48071.rs
new file mode 100644
index 000000000..73361a0d3
--- /dev/null
+++ b/tests/ui/nll/relate_tys/issue-48071.rs
@@ -0,0 +1,24 @@
+// Regression test for #48071. This test used to ICE because -- in
+// the leak-check -- it would pass since we knew that the return type
+// was `'static`, and hence `'static: 'a` was legal even for a
+// placeholder region, but in NLL land it would fail because we had
+// rewritten `'static` to a region variable.
+//
+// check-pass
+
+trait Foo {
+ fn foo(&self) { }
+}
+
+impl Foo for () {
+}
+
+type MakeFooFn = for<'a> fn(&'a u8) -> Box<dyn Foo + 'a>;
+
+fn make_foo(x: &u8) -> Box<dyn Foo + 'static> {
+ Box::new(())
+}
+
+fn main() {
+ let x: MakeFooFn = make_foo as MakeFooFn;
+}
diff --git a/tests/ui/nll/relate_tys/opaque-hrtb.rs b/tests/ui/nll/relate_tys/opaque-hrtb.rs
new file mode 100644
index 000000000..261372523
--- /dev/null
+++ b/tests/ui/nll/relate_tys/opaque-hrtb.rs
@@ -0,0 +1,14 @@
+trait MyTrait<T> {}
+
+struct Foo;
+impl<T> MyTrait<T> for Foo {}
+
+fn bar<Input>() -> impl MyTrait<Input> {
+ Foo
+}
+
+fn foo() -> impl for<'a> MyTrait<&'a str> {
+ bar() //~ ERROR implementation of `MyTrait` is not general enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/relate_tys/opaque-hrtb.stderr b/tests/ui/nll/relate_tys/opaque-hrtb.stderr
new file mode 100644
index 000000000..d75ec2b57
--- /dev/null
+++ b/tests/ui/nll/relate_tys/opaque-hrtb.stderr
@@ -0,0 +1,11 @@
+error: implementation of `MyTrait` is not general enough
+ --> $DIR/opaque-hrtb.rs:11:5
+ |
+LL | bar()
+ | ^^^^^ implementation of `MyTrait` is not general enough
+ |
+ = note: `impl MyTrait<&'2 str>` must implement `MyTrait<&'1 str>`, for any lifetime `'1`...
+ = note: ...but it actually implements `MyTrait<&'2 str>`, for some specific lifetime `'2`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/relate_tys/trait-hrtb.rs b/tests/ui/nll/relate_tys/trait-hrtb.rs
new file mode 100644
index 000000000..7f40e93cd
--- /dev/null
+++ b/tests/ui/nll/relate_tys/trait-hrtb.rs
@@ -0,0 +1,14 @@
+// Test that NLL generates proper error spans for trait HRTB errors
+//
+// compile-flags:-Zno-leak-check
+
+trait Foo<'a> {}
+
+fn make_foo<'a>() -> Box<dyn Foo<'a>> {
+ panic!()
+}
+
+fn main() {
+ let x: Box<dyn Foo<'static>> = make_foo();
+ let y: Box<dyn for<'a> Foo<'a>> = x; //~ ERROR mismatched types [E0308]
+}
diff --git a/tests/ui/nll/relate_tys/trait-hrtb.stderr b/tests/ui/nll/relate_tys/trait-hrtb.stderr
new file mode 100644
index 000000000..aa1927711
--- /dev/null
+++ b/tests/ui/nll/relate_tys/trait-hrtb.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/trait-hrtb.rs:13:39
+ |
+LL | let y: Box<dyn for<'a> Foo<'a>> = x;
+ | ^ one type is more general than the other
+ |
+ = note: expected trait object `dyn for<'a> Foo<'a>`
+ found trait object `dyn Foo<'_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/nll/relate_tys/universe-violation.rs b/tests/ui/nll/relate_tys/universe-violation.rs
new file mode 100644
index 000000000..c5f9d4406
--- /dev/null
+++ b/tests/ui/nll/relate_tys/universe-violation.rs
@@ -0,0 +1,15 @@
+// Test that the NLL `relate_tys` code correctly deduces that a
+// function returning either argument CANNOT be upcast to one
+// that returns always its first argument.
+//
+// compile-flags:-Zno-leak-check
+
+fn make_it() -> fn(&'static u32) -> &'static u32 {
+ panic!()
+}
+
+fn main() {
+ let a: fn(_) -> _ = make_it();
+ let b: fn(&u32) -> &u32 = a; //~ ERROR mismatched types [E0308]
+ drop(a);
+}
diff --git a/tests/ui/nll/relate_tys/universe-violation.stderr b/tests/ui/nll/relate_tys/universe-violation.stderr
new file mode 100644
index 000000000..fe801b42c
--- /dev/null
+++ b/tests/ui/nll/relate_tys/universe-violation.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/universe-violation.rs:13:31
+ |
+LL | let b: fn(&u32) -> &u32 = a;
+ | ^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'a> fn(&'a u32) -> &'a u32`
+ found fn pointer `fn(&u32) -> &u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/nll/relate_tys/var-appears-twice.rs b/tests/ui/nll/relate_tys/var-appears-twice.rs
new file mode 100644
index 000000000..77129f446
--- /dev/null
+++ b/tests/ui/nll/relate_tys/var-appears-twice.rs
@@ -0,0 +1,25 @@
+// Test that the NLL `relate_tys` code correctly deduces that a
+// function returning always its first argument can be upcast to one
+// that returns either first or second argument.
+
+use std::cell::Cell;
+
+type DoubleCell<A> = Cell<(A, A)>;
+type DoublePair<A> = (A, A);
+
+fn make_cell<'b>(x: &'b u32) -> Cell<(&'static u32, &'b u32)> {
+ panic!()
+}
+
+fn main() {
+ let a: &'static u32 = &22;
+ let b = 44;
+
+ // Here we get an error because `DoubleCell<_>` requires the same type
+ // on both parts of the `Cell`, and we can't have that.
+ let x: DoubleCell<_> = make_cell(&b); //~ ERROR
+
+ // Here we do not get an error because `DoublePair<_>` permits
+ // variance on the lifetimes involved.
+ let y: DoublePair<_> = make_cell(&b).get();
+}
diff --git a/tests/ui/nll/relate_tys/var-appears-twice.stderr b/tests/ui/nll/relate_tys/var-appears-twice.stderr
new file mode 100644
index 000000000..d032ce6f2
--- /dev/null
+++ b/tests/ui/nll/relate_tys/var-appears-twice.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `b` does not live long enough
+ --> $DIR/var-appears-twice.rs:20:38
+ |
+LL | let x: DoubleCell<_> = make_cell(&b);
+ | ------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `b` is borrowed for `'static`
+...
+LL | }
+ | - `b` 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/nll/return-ref-mut-issue-46557.rs b/tests/ui/nll/return-ref-mut-issue-46557.rs
new file mode 100644
index 000000000..dca61d39d
--- /dev/null
+++ b/tests/ui/nll/return-ref-mut-issue-46557.rs
@@ -0,0 +1,8 @@
+// Regression test for issue #46557
+
+fn gimme_static_mut() -> &'static mut u32 {
+ let ref mut x = 1234543;
+ x //~ ERROR cannot return value referencing temporary value [E0515]
+}
+
+fn main() {}
diff --git a/tests/ui/nll/return-ref-mut-issue-46557.stderr b/tests/ui/nll/return-ref-mut-issue-46557.stderr
new file mode 100644
index 000000000..720440a0a
--- /dev/null
+++ b/tests/ui/nll/return-ref-mut-issue-46557.stderr
@@ -0,0 +1,11 @@
+error[E0515]: cannot return value referencing temporary value
+ --> $DIR/return-ref-mut-issue-46557.rs:5:5
+ |
+LL | let ref mut x = 1234543;
+ | ------- 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/nll/return_from_loop.rs b/tests/ui/nll/return_from_loop.rs
new file mode 100644
index 000000000..495410894
--- /dev/null
+++ b/tests/ui/nll/return_from_loop.rs
@@ -0,0 +1,35 @@
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` includes the points after `&v[0]` up to (but not
+// including) the call to `use_x`. The `else` branch is not included.
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+struct MyStruct {
+ field: String
+}
+
+fn main() {
+}
+
+fn nll_fail() {
+ let mut my_struct = MyStruct { field: format!("Hello") };
+
+ let value = &mut my_struct.field;
+ loop {
+ my_struct.field.push_str("Hello, world!");
+ //~^ ERROR [E0499]
+ value.len();
+ return;
+ }
+}
+
+fn nll_ok() {
+ let mut my_struct = MyStruct { field: format!("Hello") };
+
+ let value = &mut my_struct.field;
+ loop {
+ my_struct.field.push_str("Hello, world!");
+ return;
+ }
+}
diff --git a/tests/ui/nll/return_from_loop.stderr b/tests/ui/nll/return_from_loop.stderr
new file mode 100644
index 000000000..bd2b8b158
--- /dev/null
+++ b/tests/ui/nll/return_from_loop.stderr
@@ -0,0 +1,15 @@
+error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time
+ --> $DIR/return_from_loop.rs:20:9
+ |
+LL | let value = &mut my_struct.field;
+ | -------------------- first mutable borrow occurs here
+LL | loop {
+LL | my_struct.field.push_str("Hello, world!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+LL |
+LL | value.len();
+ | ----------- 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/nll/self-assign-ref-mut.rs b/tests/ui/nll/self-assign-ref-mut.rs
new file mode 100644
index 000000000..1ca4cf3a7
--- /dev/null
+++ b/tests/ui/nll/self-assign-ref-mut.rs
@@ -0,0 +1,20 @@
+// Check that `*y` isn't borrowed after `y = y`.
+
+// check-pass
+
+fn main() {
+ let mut x = 1;
+ {
+ let mut y = &mut x;
+ y = y;
+ y;
+ }
+ x;
+ {
+ let mut y = &mut x;
+ y = y;
+ y = y;
+ y;
+ }
+ x;
+}
diff --git a/tests/ui/nll/snocat-regression.rs b/tests/ui/nll/snocat-regression.rs
new file mode 100644
index 000000000..b2e5995aa
--- /dev/null
+++ b/tests/ui/nll/snocat-regression.rs
@@ -0,0 +1,16 @@
+// Regression test from https://github.com/rust-lang/rust/pull/98109
+
+pub fn negotiate<S>(link: S)
+where
+ for<'a> &'a S: 'a,
+{
+ || {
+ //~^ ERROR `S` does not live long enough
+ //
+ // FIXME(#98437). This regressed at some point and
+ // probably should work.
+ let _x = link;
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/snocat-regression.stderr b/tests/ui/nll/snocat-regression.stderr
new file mode 100644
index 000000000..086898473
--- /dev/null
+++ b/tests/ui/nll/snocat-regression.stderr
@@ -0,0 +1,14 @@
+error: `S` does not live long enough
+ --> $DIR/snocat-regression.rs:7:5
+ |
+LL | / || {
+LL | |
+LL | | //
+LL | | // FIXME(#98437). This regressed at some point and
+LL | | // probably should work.
+LL | | let _x = link;
+LL | | };
+ | |_____^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/trait-associated-constant.rs b/tests/ui/nll/trait-associated-constant.rs
new file mode 100644
index 000000000..e13ae80f9
--- /dev/null
+++ b/tests/ui/nll/trait-associated-constant.rs
@@ -0,0 +1,31 @@
+// Test cases where we put various lifetime constraints on trait
+// associated constants.
+
+#![feature(rustc_attrs)]
+
+use std::option::Option;
+
+trait Anything<'a: 'b, 'b> {
+ const AC: Option<&'b str>;
+}
+
+struct OKStruct1 { }
+
+impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct1 {
+ const AC: Option<&'b str> = None;
+}
+
+struct FailStruct { }
+
+impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
+ const AC: Option<&'c str> = None;
+ //~^ ERROR: const not compatible with trait
+}
+
+struct OKStruct2 { }
+
+impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct2 {
+ const AC: Option<&'a str> = None;
+}
+
+fn main() {}
diff --git a/tests/ui/nll/trait-associated-constant.stderr b/tests/ui/nll/trait-associated-constant.stderr
new file mode 100644
index 000000000..cf1c52ba7
--- /dev/null
+++ b/tests/ui/nll/trait-associated-constant.stderr
@@ -0,0 +1,22 @@
+error[E0308]: const not compatible with trait
+ --> $DIR/trait-associated-constant.rs:21:5
+ |
+LL | const AC: Option<&'c str> = None;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+ |
+ = note: expected enum `Option<&'b str>`
+ found enum `Option<&'c str>`
+note: the lifetime `'c` as defined here...
+ --> $DIR/trait-associated-constant.rs:20:18
+ |
+LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
+ | ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+ --> $DIR/trait-associated-constant.rs:20:14
+ |
+LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.rs b/tests/ui/nll/ty-outlives/impl-trait-captures.rs
new file mode 100644
index 000000000..67b31b8bc
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/impl-trait-captures.rs
@@ -0,0 +1,15 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+
+trait Foo<'a> {
+}
+
+impl<'a, T> Foo<'a> for T { }
+
+fn foo<'a, T>(x: &T) -> impl Foo<'a> {
+ x
+ //~^ ERROR captures lifetime that does not appear in bounds
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
new file mode 100644
index 000000000..7b9ed171d
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -0,0 +1,16 @@
+error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
+ --> $DIR/impl-trait-captures.rs:11:5
+ |
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
+ | -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here
+LL | x
+ | ^
+ |
+help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound
+ |
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) {
+ | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/nll/ty-outlives/impl-trait-outlives.rs b/tests/ui/nll/ty-outlives/impl-trait-outlives.rs
new file mode 100644
index 000000000..68ccb51fc
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/impl-trait-outlives.rs
@@ -0,0 +1,38 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+
+use std::fmt::Debug;
+
+fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn correct_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: 'a + Debug,
+{
+ x
+}
+
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: 'b + Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: 'b + Debug,
+ 'b: 'a,
+{
+ x
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/impl-trait-outlives.stderr b/tests/ui/nll/ty-outlives/impl-trait-outlives.stderr
new file mode 100644
index 000000000..64b08a9b3
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/impl-trait-outlives.stderr
@@ -0,0 +1,25 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/impl-trait-outlives.rs:11:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Debug + 'a,
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/impl-trait-outlives.rs:26:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + Debug + 'a,
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/issue-53789-1.rs b/tests/ui/nll/ty-outlives/issue-53789-1.rs
new file mode 100644
index 000000000..a5201d4bb
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/issue-53789-1.rs
@@ -0,0 +1,87 @@
+// Regression test for #53789.
+//
+// check-pass
+
+use std::collections::BTreeMap;
+
+trait ValueTree {
+ type Value;
+}
+
+trait Strategy {
+ type Value: ValueTree;
+}
+
+type StrategyFor<A> = StrategyType<'static, A>;
+type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
+
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V) {
+ type Value = TupleValueTree<(K, V)>;
+}
+
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> {
+ type Value = BTreeMapValueTree<K, V>;
+}
+
+struct TupleValueTree<T> {
+ tree: T,
+}
+
+struct BTreeMapStrategy<K, V>(std::marker::PhantomData<(K, V)>)
+where
+ K: Strategy,
+ V: Strategy;
+
+struct BTreeMapValueTree<K, V>(std::marker::PhantomData<(K, V)>)
+where
+ K: ValueTree,
+ V: ValueTree;
+
+impl<K, V> Strategy for BTreeMapStrategy<K, V>
+where
+ K: Strategy,
+ V: Strategy,
+{
+ type Value = BTreeMapValueTree<K::Value, V::Value>;
+}
+
+impl<K, V> ValueTree for BTreeMapValueTree<K, V>
+where
+ K: ValueTree,
+ V: ValueTree,
+{
+ type Value = BTreeMap<K::Value, V::Value>;
+}
+
+trait Arbitrary<'a>: Sized {
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
+ type Parameters;
+ type Strategy: Strategy<Value = Self::ValueTree>;
+ type ValueTree: ValueTree<Value = Self>;
+}
+
+impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
+where
+ A: Arbitrary<'static>,
+ B: Arbitrary<'static>,
+ StrategyFor<A>: 'static,
+ StrategyFor<B>: 'static,
+{
+ type ValueTree = <Self::Strategy as Strategy>::Value;
+ type Parameters = (A::Parameters, B::Parameters);
+ type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
+ fn arbitrary_with(args: Self::Parameters) -> BTreeMapStrategy<A::Strategy, B::Strategy> {
+ let (a, b) = args;
+ btree_map(any_with::<A>(a), any_with::<B>(b))
+ }
+}
+
+fn btree_map<K: Strategy + 'static, V: Strategy>(key: K, value: V) -> BTreeMapStrategy<K, V> {
+ unimplemented!()
+}
+
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
+ unimplemented!()
+}
+
+fn main() { }
diff --git a/tests/ui/nll/ty-outlives/issue-53789-2.rs b/tests/ui/nll/ty-outlives/issue-53789-2.rs
new file mode 100644
index 000000000..5109a0e4a
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/issue-53789-2.rs
@@ -0,0 +1,249 @@
+// Regression test for #53789.
+//
+// check-pass
+
+use std::cmp::Ord;
+use std::collections::BTreeMap;
+use std::ops::Range;
+
+macro_rules! valuetree {
+ () => {
+ type ValueTree = <Self::Strategy as $crate::Strategy>::Value;
+ };
+}
+
+macro_rules! product_unpack {
+ ($factor: pat) => {
+ ($factor,)
+ };
+ ($($factor: pat),*) => {
+ ( $( $factor ),* )
+ };
+ ($($factor: pat),*,) => {
+ ( $( $factor ),* )
+ };
+}
+
+macro_rules! product_type {
+ ($factor: ty) => {
+ ($factor,)
+ };
+ ($($factor: ty),*) => {
+ ( $( $factor, )* )
+ };
+ ($($factor: ty),*,) => {
+ ( $( $factor, )* )
+ };
+}
+
+macro_rules! default {
+ ($type: ty, $val: expr) => {
+ impl Default for $type {
+ fn default() -> Self {
+ $val.into()
+ }
+ }
+ };
+}
+
+// Pervasive internal sugar
+macro_rules! mapfn {
+ ($(#[$meta:meta])* [$($vis:tt)*]
+ fn $name:ident[$($gen:tt)*]($parm:ident: $input:ty) -> $output:ty {
+ $($body:tt)*
+ }) => {
+ $(#[$meta])*
+ #[derive(Clone, Copy)]
+ $($vis)* struct $name;
+ impl $($gen)* statics::MapFn<$input> for $name {
+ type Output = $output;
+ }
+ }
+}
+
+macro_rules! opaque_strategy_wrapper {
+ ($(#[$smeta:meta])* pub struct $stratname:ident
+ [$($sgen:tt)*][$($swhere:tt)*]
+ ($innerstrat:ty) -> $stratvtty:ty;
+
+ $(#[$vmeta:meta])* pub struct $vtname:ident
+ [$($vgen:tt)*][$($vwhere:tt)*]
+ ($innervt:ty) -> $actualty:ty;
+ ) => {
+ $(#[$smeta])* struct $stratname $($sgen)* (std::marker::PhantomData<(K, V)>)
+ $($swhere)*;
+
+ $(#[$vmeta])* struct $vtname $($vgen)* ($innervt) $($vwhere)*;
+
+ impl $($sgen)* Strategy for $stratname $($sgen)* $($swhere)* {
+ type Value = $stratvtty;
+ }
+
+ impl $($vgen)* ValueTree for $vtname $($vgen)* $($vwhere)* {
+ type Value = $actualty;
+ }
+ }
+}
+
+trait ValueTree {
+ type Value;
+}
+
+trait Strategy {
+ type Value: ValueTree;
+}
+
+#[derive(Clone)]
+struct VecStrategy<T: Strategy> {
+ element: T,
+ size: Range<usize>,
+}
+
+fn vec<T: Strategy>(element: T, size: Range<usize>) -> VecStrategy<T> {
+ VecStrategy { element: element, size: size }
+}
+
+type ValueFor<S> = <<S as Strategy>::Value as ValueTree>::Value;
+
+trait Arbitrary<'a>: Sized {
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
+
+ type Parameters: Default;
+ type Strategy: Strategy<Value = Self::ValueTree>;
+ type ValueTree: ValueTree<Value = Self>;
+}
+
+type StrategyFor<A> = StrategyType<'static, A>;
+type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
+
+//#[derive(Clone, PartialEq, Eq, Hash, Debug, From, Into)]
+struct SizeBounds(Range<usize>);
+default!(SizeBounds, 0..100);
+
+impl From<Range<usize>> for SizeBounds {
+ fn from(high: Range<usize>) -> Self {
+ unimplemented!()
+ }
+}
+
+impl From<SizeBounds> for Range<usize> {
+ fn from(high: SizeBounds) -> Self {
+ unimplemented!()
+ }
+}
+
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
+ unimplemented!()
+}
+
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V)
+where
+ <K as ValueTree>::Value: Ord,
+{
+ type Value = TupleValueTree<(K, V)>;
+}
+
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)>
+where
+ <K as ValueTree>::Value: Ord,
+{
+ type Value = BTreeMapValueTree<K, V>;
+}
+
+#[derive(Clone)]
+struct VecValueTree<T: ValueTree> {
+ elements: Vec<T>,
+}
+
+#[derive(Clone, Copy)]
+struct TupleValueTree<T> {
+ tree: T,
+}
+
+opaque_strategy_wrapper! {
+ #[derive(Clone)]
+ pub struct BTreeMapStrategy[<K, V>]
+ [where K : Strategy, V : Strategy, ValueFor<K> : Ord](
+ statics::Filter<statics::Map<VecStrategy<(K,V)>,
+ VecToBTreeMap>, MinSize>)
+ -> BTreeMapValueTree<K::Value, V::Value>;
+
+ #[derive(Clone)]
+ pub struct BTreeMapValueTree[<K, V>]
+ [where K : ValueTree, V : ValueTree, K::Value : Ord](
+ statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>,
+ VecToBTreeMap>, MinSize>)
+ -> BTreeMap<K::Value, V::Value>;
+}
+
+type RangedParams2<A, B> = product_type![SizeBounds, A, B];
+
+impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
+where
+ A: Arbitrary<'static> + Ord,
+ B: Arbitrary<'static>,
+ StrategyFor<A>: 'static,
+ StrategyFor<B>: 'static,
+{
+ valuetree!();
+ type Parameters = RangedParams2<A::Parameters, B::Parameters>;
+ type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
+ let product_unpack![range, a, b] = args;
+ btree_map(any_with::<A>(a), any_with::<B>(b), range.into())
+ }
+}
+
+#[derive(Clone, Copy)]
+struct MinSize(usize);
+
+mapfn! {
+ [] fn VecToBTreeMap[<K : Ord, V>]
+ (vec: Vec<(K, V)>) -> BTreeMap<K, V>
+ {
+ vec.into_iter().collect()
+ }
+}
+
+fn btree_map<K: Strategy + 'static, V: Strategy + 'static>(
+ key: K,
+ value: V,
+ size: Range<usize>,
+) -> BTreeMapStrategy<K, V>
+where
+ ValueFor<K>: Ord,
+{
+ unimplemented!()
+}
+
+mod statics {
+ pub(super) trait MapFn<T> {
+ type Output;
+ }
+
+ #[derive(Clone)]
+ pub struct Filter<S, F> {
+ source: S,
+ fun: F,
+ }
+
+ impl<S, F> Filter<S, F> {
+ pub fn new(source: S, whence: String, filter: F) -> Self {
+ unimplemented!()
+ }
+ }
+
+ #[derive(Clone)]
+ pub struct Map<S, F> {
+ source: S,
+ fun: F,
+ }
+
+ impl<S, F> Map<S, F> {
+ pub fn new(source: S, fun: F) -> Self {
+ unimplemented!()
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/issue-55756.rs b/tests/ui/nll/ty-outlives/issue-55756.rs
new file mode 100644
index 000000000..e1a3bc3c4
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/issue-55756.rs
@@ -0,0 +1,37 @@
+// Regression test for #55756.
+//
+// In this test, the result of `self.callee` is a projection `<D as
+// Database<'?0>>::Guard`. As it may contain a destructor, the dropck
+// rules require that this type outlivess the scope of `state`. Unfortunately,
+// our region inference is not smart enough to figure out how to
+// translate a requirement like
+//
+// <D as Database<'0>>::guard: 'r
+//
+// into a requirement that `'0: 'r` -- in particular, it fails to do
+// so because it *also* knows that `<D as Database<'a>>::Guard: 'a`
+// from the trait definition. Faced with so many choices, the current
+// solver opts to do nothing.
+//
+// Fixed by tweaking the solver to recognize that the constraint from
+// the environment duplicates one from the trait.
+//
+// check-pass
+
+#![crate_type="lib"]
+
+pub trait Database<'a> {
+ type Guard: 'a;
+}
+
+pub struct Stateful<'a, D: 'a>(&'a D);
+
+impl<'b, D: for <'a> Database<'a>> Stateful<'b, D> {
+ pub fn callee<'a>(&'a self) -> <D as Database<'a>>::Guard {
+ unimplemented!()
+ }
+ pub fn caller<'a>(&'a self) -> <D as Database<'a>>::Guard {
+ let state = self.callee();
+ unimplemented!()
+ }
+}
diff --git a/tests/ui/nll/ty-outlives/projection-body.rs b/tests/ui/nll/ty-outlives/projection-body.rs
new file mode 100644
index 000000000..b03a539eb
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-body.rs
@@ -0,0 +1,27 @@
+// Test that when we infer the lifetime to a subset of the fn body, it
+// works out.
+//
+// check-pass
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<T>()
+where
+ for<'x> T: MyTrait<'x>,
+{
+ // Here the region `'c` in `<T as MyTrait<'c>>::Output` will be
+ // inferred to a subset of the fn body.
+ let x = bar::<T::Output>();
+ drop(x);
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-implied-bounds.rs b/tests/ui/nll/ty-outlives/projection-implied-bounds.rs
new file mode 100644
index 000000000..e1dac0824
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-implied-bounds.rs
@@ -0,0 +1,40 @@
+// Test that we can deduce when projections like `T::Item` outlive the
+// function body. Test that this does not imply that `T: 'a` holds.
+
+// compile-flags:-Zverbose
+
+use std::cell::Cell;
+
+fn twice<F, T>(mut value: T, mut f: F)
+where
+ F: FnMut(&T, Cell<&Option<T::Item>>),
+ T: Iterator,
+{
+ let mut n = value.next();
+ f(&value, Cell::new(&n));
+ f(&value, Cell::new(&n));
+}
+
+fn generic1<T: Iterator>(value: T) {
+ // No error here:
+ twice(value, |value_ref, item| invoke1(item));
+}
+
+fn invoke1<'a, T>(x: Cell<&'a Option<T>>)
+where
+ T: 'a,
+{
+}
+
+fn generic2<T: Iterator>(value: T) {
+ twice(value, |value_ref, item| invoke2(value_ref, item));
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)
+where
+ T: 'a,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-implied-bounds.stderr b/tests/ui/nll/ty-outlives/projection-implied-bounds.stderr
new file mode 100644
index 000000000..d949e29b2
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-implied-bounds.stderr
@@ -0,0 +1,14 @@
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/projection-implied-bounds.rs:30:36
+ |
+LL | twice(value, |value_ref, item| invoke2(value_ref, item));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn generic2<T: Iterator + 'static>(value: T) {
+ | +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-closure.rs b/tests/ui/nll/ty-outlives/projection-no-regions-closure.rs
new file mode 100644
index 000000000..2d9c008c7
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-no-regions-closure.rs
@@ -0,0 +1,55 @@
+// compile-flags:-Zverbose
+
+// Tests closures that propagate an outlives relationship to their
+// creator where the subject is a projection with no regions (`<T as
+// Iterator>::Item`, to be exact).
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+trait Anything { }
+
+impl<T> Anything for T { }
+
+fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Anything + 'a>
+ where F: FnOnce(Box<T>) -> Box<dyn Anything + 'a>
+{
+ op(x)
+}
+
+#[rustc_regions]
+fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+ T: Iterator,
+{
+ with_signature(x, |mut y| Box::new(y.next()))
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+#[rustc_regions]
+fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+ T: 'a + Iterator,
+{
+ with_signature(x, |mut y| Box::new(y.next()))
+}
+
+#[rustc_regions]
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+ T: 'b + Iterator,
+{
+ with_signature(x, |mut y| Box::new(y.next()))
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+#[rustc_regions]
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+ T: 'b + Iterator,
+ 'b: 'a,
+{
+ with_signature(x, |mut y| Box::new(y.next()))
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
new file mode 100644
index 000000000..4933b9348
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -0,0 +1,118 @@
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:25:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where <T as std::iter::Iterator>::Item: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:21:1
+ |
+LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: Iterator,
+ | |________________^
+ |
+ = note: defining type: no_region::<'_#1r, T>
+
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-closure.rs:25:31
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:34:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where <T as std::iter::Iterator>::Item: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:30:1
+ |
+LL | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: 'a + Iterator,
+ | |_____________________^
+ |
+ = note: defining type: correct_region::<'_#1r, T>
+
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:42:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as std::iter::Iterator>::Item: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:38:1
+ |
+LL | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: 'b + Iterator,
+ | |_____________________^
+ |
+ = note: defining type: wrong_region::<'_#1r, '_#2r, T>
+
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-closure.rs:42:31
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:52:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as std::iter::Iterator>::Item: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:47:1
+ |
+LL | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: 'b + Iterator,
+LL | | 'b: 'a,
+ | |___________^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-fn.rs b/tests/ui/nll/ty-outlives/projection-no-regions-fn.rs
new file mode 100644
index 000000000..a10a0366a
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-no-regions-fn.rs
@@ -0,0 +1,40 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+
+trait Anything { }
+
+impl<T> Anything for T { }
+
+fn no_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
+where
+ T: Iterator,
+{
+ Box::new(x.next())
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+fn correct_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
+where
+ T: 'a + Iterator,
+{
+ Box::new(x.next())
+}
+
+fn wrong_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
+where
+ T: 'b + Iterator,
+{
+ Box::new(x.next())
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+fn outlives_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
+where
+ T: 'b + Iterator,
+ 'b: 'a,
+{
+ Box::new(x.next())
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr
new file mode 100644
index 000000000..e0ff544fe
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-no-regions-fn.stderr
@@ -0,0 +1,21 @@
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-fn.rs:13:5
+ |
+LL | Box::new(x.next())
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-fn.rs:28:5
+ |
+LL | Box::new(x.next())
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-closure.rs b/tests/ui/nll/ty-outlives/projection-one-region-closure.rs
new file mode 100644
index 000000000..af361e990
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-one-region-closure.rs
@@ -0,0 +1,83 @@
+// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
+// outlive `'a` and there are no bounds in the trait definition of
+// `Anything`. This means that the constraint can only be satisfied in two
+// ways:
+//
+// - by ensuring that `T: 'a` and `'b: 'a`, or
+// - by something in the where clauses.
+//
+// As of this writing, the where clause option does not work because
+// of limitations in our region inferencing system (this is true both
+// with and without NLL). See `projection_outlives`.
+//
+// Ensuring that both `T: 'a` and `'b: 'a` holds does work (`elements_outlive`).
+
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a> {
+ type AssocType;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+ F: FnOnce(Cell<&'a ()>, T),
+{
+ op(cell, t)
+}
+
+fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+ //~^ ERROR the parameter type `T` may not live long enough
+ //~| ERROR
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ 'a: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+ //~^ ERROR the parameter type `T` may not live long enough
+ //~| ERROR
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+ // We are projecting `<T as Anything<'b>>::AssocType`, and we know
+ // that this outlives `'a` because of the where-clause.
+
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ T: 'a,
+ 'b: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
new file mode 100644
index 000000000..dbda04c42
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -0,0 +1,155 @@
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:45:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where T: '_#2r
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-one-region-closure.rs:41:1
+ |
+LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+ | |____________________^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-one-region-closure.rs:45:39
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Anything<'b> + 'a,
+ | ++++
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-closure.rs:45:39
+ |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:56:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+ = note: where '_#2r: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-closure.rs:51:1
+ |
+LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'a: 'a,
+ | |___________^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-one-region-closure.rs:56:39
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Anything<'b> + 'a,
+ | ++++
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-closure.rs:56:39
+ |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:70:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-closure.rs:62:1
+ |
+LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T::AssocType: 'a,
+ | |_____________________^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:80:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+ = note: where '_#2r: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-closure.rs:74:1
+ |
+LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T: 'a,
+LL | | 'b: 'a,
+ | |___________^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
new file mode 100644
index 000000000..6f8513491
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
@@ -0,0 +1,84 @@
+// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
+// outlive `'a` and there is a unique bound in the trait definition of
+// `Anything` -- i.e., we know that `AssocType` outlives `'b`. In this
+// case, the best way to satisfy the trait bound is to show that `'b:
+// 'a`, which can be done in various ways.
+
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a> {
+ type AssocType: 'a;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+ F: FnOnce(Cell<&'a ()>, T),
+{
+ op(cell, t)
+}
+
+fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+ //~^ ERROR
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ 'a: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+ //~^ ERROR
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+ // We are projecting `<T as Anything<'b>>::AssocType`, and we know
+ // that this outlives `'a` because of the where-clause.
+
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ 'b: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'a>,
+{
+ // Note that in this case the closure still propagates an external
+ // requirement between two variables in its signature, but the
+ // creator maps both those two region variables to `'a` on its
+ // side.
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
new file mode 100644
index 000000000..250c796e2
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -0,0 +1,152 @@
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:37:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:33:1
+ |
+LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+ | |____________________^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-trait-bound-closure.rs:37:39
+ |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:47:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#2r: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:42:1
+ |
+LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'a: 'a,
+ | |___________^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-trait-bound-closure.rs:47:39
+ |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:60:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:52:1
+ |
+LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T::AssocType: 'a,
+ | |_____________________^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:69:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#2r: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:64:1
+ |
+LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'b: 'a,
+ | |___________^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:81:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:73:1
+ |
+LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'a>,
+ | |____________________^
+ |
+ = note: defining type: one_region::<'_#1r, T>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs
new file mode 100644
index 000000000..7c0a3bc72
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs
@@ -0,0 +1,88 @@
+// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
+// outlive `'static`. In this case, we don't get any errors, and in fact
+// we don't even propagate constraints from the closures to the callers.
+
+// compile-flags:-Zverbose
+// check-pass
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a> {
+ type AssocType: 'static;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+ F: FnOnce(Cell<&'a ()>, T),
+{
+ op(cell, t)
+}
+
+fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ 'a: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+ // This error is unfortunate. This code ought to type-check: we
+ // are projecting `<T as Anything<'b>>::AssocType`, and we know
+ // that this outlives `'a` because of the where-clause. However,
+ // the way the region checker works, we don't register this
+ // outlives obligation, and hence we get an error: this is because
+ // what we see is a projection like `<T as
+ // Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
+ // equal `'b` or not, so we ignore the where-clause. Obviously we
+ // can do better here with a more involved verification step.
+
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ 'b: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'a>,
+{
+ // Note that in this case the closure still propagates an external
+ // requirement between two variables in its signature, but the
+ // creator maps both those two region variables to `'a` on its
+ // side.
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
new file mode 100644
index 000000000..b27186b05
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
@@ -0,0 +1,114 @@
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:36:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:32:1
+ |
+LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+ | |____________________^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:45:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:40:1
+ |
+LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'a: 'a,
+ | |___________^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:64:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:49:1
+ |
+LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T::AssocType: 'a,
+ | |_____________________^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:73:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:68:1
+ |
+LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'b: 'a,
+ | |___________^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:85:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:77:1
+ |
+LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'a>,
+ | |____________________^
+ |
+ = note: defining type: one_region::<'_#1r, T>
+
diff --git a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
new file mode 100644
index 000000000..7b4a3c03a
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
@@ -0,0 +1,112 @@
+// Test cases where we constrain `<T as Anything<'a, 'b>>::AssocType`
+// to outlive `'a` and there are two bounds in the trait definition of
+// `Anything` -- i.e., we know that `AssocType` outlives `'a` and
+// `'b`. In this case, it's not clear what is the best way to satisfy
+// the trait bound, and hence we propagate it to the caller as a type
+// test.
+
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a, 'b> {
+ type AssocType: 'a + 'b;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+ F: FnOnce(Cell<&'a ()>, T),
+{
+ op(cell, t)
+}
+
+fn require<'a, 'b, 'c, T>(_cell: Cell<&'a ()>, _t: T)
+where
+ T: Anything<'b, 'c>,
+ T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'c>,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+ //~^ ERROR may not live long enough
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'c>,
+ 'a: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+ //~^ ERROR may not live long enough
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'c>,
+ T::AssocType: 'a,
+{
+ // We are projecting `<T as Anything<'b>>::AssocType`, and we know
+ // that this outlives `'a` because of the where-clause.
+
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'c>,
+ 'b: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'c>,
+ 'c: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'b>,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+ //~^ ERROR lifetime may not live long enough
+}
+
+#[rustc_regions]
+fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'b>,
+ 'b: 'a,
+{
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'a, 'a>,
+{
+ // Note that in this case the closure still propagates an external
+ // requirement between two variables in its signature, but the
+ // creator maps both those two region variables to `'a` on its
+ // side.
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
new file mode 100644
index 000000000..90f049142
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -0,0 +1,236 @@
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:38:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:34:1
+ |
+LL | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+ | |________________________^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
+
+error[E0309]: the associated type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:38:39
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
+ = note: ...so that the type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:43:1
+ |
+LL | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | 'a: 'a,
+ | |___________^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
+
+error[E0309]: the associated type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:48:39
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
+ = note: ...so that the type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:53:1
+ |
+LL | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | T::AssocType: 'a,
+ | |_____________________^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:70:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:65:1
+ |
+LL | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | 'b: 'a,
+ | |___________^
+ |
+ = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:79:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:74:1
+ |
+LL | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | 'c: 'a,
+ | |___________^
+ |
+ = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:87:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(0, 'b)>>::AssocType: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:83:1
+ |
+LL | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'b>,
+ | |________________________^
+ |
+ = note: defining type: two_regions::<'_#1r, T>
+
+error: lifetime may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:87:5
+ |
+LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of the type `Cell<&'_#8r ()>`, which makes the generic argument `&'_#8r ()` invariant
+ = note: the struct `Cell<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:97:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:92:1
+ |
+LL | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'b>,
+LL | | 'b: 'a,
+ | |___________^
+ |
+ = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:109:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where <T as Anything<ReEarlyBound(0, 'a), ReEarlyBound(0, 'a)>>::AssocType: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:101:1
+ |
+LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'a, 'a>,
+ | |________________________^
+ |
+ = note: defining type: one_region::<'_#1r, T>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs
new file mode 100644
index 000000000..dce88b88c
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs
@@ -0,0 +1,34 @@
+// Test that we are able to establish that `<T as
+// MyTrait<'a>>::Output` outlives `'b` here. We need to prove however
+// that `<T as MyTrait<'a>>::Output` outlives `'a`, so we also have to
+// prove that `'b: 'a`.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<'a, 'b, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'b,
+{
+ bar::<T::Output>() //~ ERROR may not live long enough
+}
+
+fn foo2<'a, 'b, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'b,
+ 'b: 'a,
+{
+ bar::<T::Output>() // OK
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
new file mode 100644
index 000000000..b4435fe06
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
@@ -0,0 +1,12 @@
+error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+ --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5
+ |
+LL | bar::<T::Output>()
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+ = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs
new file mode 100644
index 000000000..987148dce
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs
@@ -0,0 +1,25 @@
+// Test that if we need to prove that `<T as MyTrait<'a>>::Output:
+// 'a`, but we only know that `<T as MyTrait<'b>>::Output: 'a`, that
+// doesn't suffice.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<'a, 'b, T>() -> &'a ()
+where
+ for<'x> T: MyTrait<'x>,
+ <T as MyTrait<'b>>::Output: 'a,
+{
+ bar::<<T as MyTrait<'a>>::Output>()
+ //~^ ERROR the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
new file mode 100644
index 000000000..ddeaf3c1f
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
@@ -0,0 +1,12 @@
+error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+ --> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5
+ |
+LL | bar::<<T as MyTrait<'a>>::Output>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+ = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-env.rs b/tests/ui/nll/ty-outlives/projection-where-clause-env.rs
new file mode 100644
index 000000000..a41116232
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-env.rs
@@ -0,0 +1,28 @@
+// Test that when we have a `<T as MyTrait<'a>>::Output: 'a`
+// relationship in the environment we take advantage of it. In this
+// case, that means we **don't** have to prove that `T: 'a`.
+//
+// Regression test for #53121.
+//
+// check-pass
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'a,
+{
+ bar::<T::Output>()
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-none.rs b/tests/ui/nll/ty-outlives/projection-where-clause-none.rs
new file mode 100644
index 000000000..bb201e5c0
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-none.rs
@@ -0,0 +1,24 @@
+// Test that we are NOT able to establish that `<T as
+// MyTrait<'a>>::Output: 'a` outlives `'a` here -- we have only one
+// recourse, which is to prove that `T: 'a` and `'a: 'a`, but we don't
+// know that `T: 'a`.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+{
+ bar::<T::Output>() //~ ERROR the parameter type `T` may not live long enough
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-none.stderr b/tests/ui/nll/ty-outlives/projection-where-clause-none.stderr
new file mode 100644
index 000000000..0df44644d
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-none.stderr
@@ -0,0 +1,14 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-where-clause-none.rs:14:5
+ |
+LL | bar::<T::Output>()
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: MyTrait<'a> + 'a,
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/projection-where-clause-trait.rs b/tests/ui/nll/ty-outlives/projection-where-clause-trait.rs
new file mode 100644
index 000000000..1a40d3b4c
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/projection-where-clause-trait.rs
@@ -0,0 +1,25 @@
+// Test that we are able to establish that `<T as
+// MyTrait<'a>>::Output: 'a` outlives `'a` (because the trait says
+// so).
+//
+// check-pass
+
+trait MyTrait<'a> {
+ type Output: 'a;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+{
+ bar::<T::Output>()
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs
new file mode 100644
index 000000000..4d8380599
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs
@@ -0,0 +1,39 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Invoke in such a way that the callee knows:
+//
+// - 'a: 'x
+//
+// and it must prove that `T: 'x`. Callee passes along `T: 'a`.
+fn twice<'a, F, T>(v: Cell<&'a ()>, value: T, mut f: F)
+where
+ F: for<'x> FnMut(Option<Cell<&'a &'x ()>>, &T),
+{
+ f(None, &value);
+ f(None, &value);
+}
+
+#[rustc_regions]
+fn generic<T>(value: T) {
+ let cell = Cell::new(&());
+ twice(cell, value, |a, b| invoke(a, b));
+}
+
+#[rustc_regions]
+fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+ twice(cell, value, |a, b| invoke(a, b));
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn invoke<'a, 'x, T>(x: Option<Cell<&'x &'a ()>>, y: &T)
+where
+ T: 'x,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
new file mode 100644
index 000000000..a442cf12d
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -0,0 +1,59 @@
+note: external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:24:24
+ |
+LL | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^
+ |
+ = note: defining type: generic::<T>::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) T)),
+ (),
+ ]
+ = note: number of external vids: 2
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:22:1
+ |
+LL | fn generic<T>(value: T) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: generic::<T>
+
+note: external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
+ |
+LL | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^
+ |
+ = note: defining type: generic_fail::<T>::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) T)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: number of external vids: 3
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:28:1
+ |
+LL | fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: generic_fail::<T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:31
+ |
+LL | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn generic_fail<'a, T: 'a>(cell: Cell<&'a ()>, value: T) {
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs
new file mode 100644
index 000000000..4343c3aee
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs
@@ -0,0 +1,53 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::fmt::Debug;
+
+fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Debug + 'a>
+ where F: FnOnce(Box<T>) -> Box<dyn Debug + 'a>
+{
+ op(x)
+}
+
+#[rustc_regions]
+fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
+where
+ T: Debug,
+{
+ // Here, the closure winds up being required to prove that `T:
+ // 'a`. In principle, it could know that, except that it is
+ // type-checked in a fully generic way, and hence it winds up with
+ // a propagated requirement that `T: '_#2`, where `'_#2` appears
+ // in the return type. The caller makes the mapping from `'_#2` to
+ // `'a` (and subsequently reports an error).
+
+ with_signature(x, |y| y)
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'a + Debug,
+{
+ x
+}
+
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'b + Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'b + Debug,
+ 'b: 'a,
+{
+ x
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
new file mode 100644
index 000000000..35979c8bf
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -0,0 +1,49 @@
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
+ |
+LL | with_signature(x, |y| y)
+ | ^^^
+ |
+ = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>,
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where T: '_#2r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:15:1
+ |
+LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
+LL | | where
+LL | | T: Debug,
+ | |_____________^
+ |
+ = note: defining type: no_region::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:27
+ |
+LL | with_signature(x, |y| y)
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Debug + 'a,
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + Debug + 'a,
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs
new file mode 100644
index 000000000..b80287610
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs
@@ -0,0 +1,82 @@
+// Test that we can propagate `T: 'a` obligations to our caller. See
+// `correct_region` for an explanation of how this test is setup; it's
+// somewhat intricate.
+
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+fn with_signature<'a, T, F>(a: Cell<&'a ()>, b: T, op: F)
+where
+ F: FnOnce(Cell<&'a ()>, T),
+{
+ op(a, b)
+}
+
+fn require<'a, T>(_a: &Cell<&'a ()>, _b: &T)
+where
+ T: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
+ with_signature(a, b, |x, y| {
+ // See `correct_region`, which explains the point of this
+ // test. The only difference is that, in the case of this
+ // function, there is no where clause *anywhere*, and hence we
+ // get an error (but reported by the closure creator).
+ require(&x, &y)
+ //~^ ERROR the parameter type `T` may not live long enough
+ })
+}
+
+#[rustc_regions]
+fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
+where
+ T: 'a,
+{
+ with_signature(a, b, |x, y| {
+ // Key point of this test:
+ //
+ // The *closure* is being type-checked with all of its free
+ // regions "universalized". In particular, it does not know
+ // that `x` has the type `Cell<&'a ()>`, but rather treats it
+ // as if the type of `x` is `Cell<&'A ()>`, where `'A` is some
+ // fresh, independent region distinct from the `'a` which
+ // appears in the environment. The call to `require` here
+ // forces us then to prove that `T: 'A`, but the closure
+ // cannot do it on its own. It has to surface this requirement
+ // to its creator (which knows that `'a == 'A`).
+ require(&x, &y)
+ })
+}
+
+#[rustc_regions]
+fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+where
+ T: 'b,
+{
+ with_signature(a, b, |x, y| {
+ // See `correct_region`
+ require(&x, &y)
+ //~^ ERROR the parameter type `T` may not live long enough
+ })
+}
+
+#[rustc_regions]
+fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+where
+ T: 'b,
+ 'b: 'a,
+{
+ with_signature(a, b, |x, y| {
+ // See `correct_region`
+ require(&x, &y)
+ })
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
new file mode 100644
index 000000000..4c97db58c
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -0,0 +1,122 @@
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: no_region::<T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: number of external vids: 3
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:26:1
+ |
+LL | fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: no_region::<T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:32:9
+ |
+LL | require(&x, &y)
+ | ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) {
+ | ++++
+
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:42:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where T: '_#2r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:1
+ |
+LL | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
+LL | | where
+LL | | T: 'a,
+ | |__________^
+ |
+ = note: defining type: correct_region::<'_#1r, T>
+
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:63:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where T: '_#2r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:59:1
+ |
+LL | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+LL | | where
+LL | | T: 'b,
+ | |__________^
+ |
+ = note: defining type: wrong_region::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:65:9
+ |
+LL | require(&x, &y)
+ | ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + 'a,
+ | ++++
+
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1
+ |
+LL | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+LL | | where
+LL | | T: 'b,
+LL | | 'b: 'a,
+ | |___________^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/ty-param-fn-body.rs b/tests/ui/nll/ty-outlives/ty-param-fn-body.rs
new file mode 100644
index 000000000..98239f416
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-fn-body.rs
@@ -0,0 +1,27 @@
+// Test that we assume that universal types like `T` outlive the
+// function body.
+
+#![allow(warnings)]
+
+use std::cell::Cell;
+
+// No errors here, because `'a` is local to the body.
+fn region_within_body<T>(t: T) {
+ let some_int = 22;
+ let cell = Cell::new(&some_int);
+ outlives(cell, t)
+}
+
+// Error here, because T: 'a is not satisfied.
+fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
+ outlives(cell, t)
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn outlives<'a, T>(x: Cell<&'a usize>, y: T)
+where
+ T: 'a,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/ty-param-fn-body.stderr b/tests/ui/nll/ty-outlives/ty-param-fn-body.stderr
new file mode 100644
index 000000000..5fb69255d
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-fn-body.stderr
@@ -0,0 +1,14 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-fn-body.rs:17:5
+ |
+LL | outlives(cell, t)
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn region_static<'a, T: 'a>(cell: Cell<&'a usize>, t: T) {
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/ty-param-fn.rs b/tests/ui/nll/ty-outlives/ty-param-fn.rs
new file mode 100644
index 000000000..4393a3b41
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-fn.rs
@@ -0,0 +1,36 @@
+#![allow(warnings)]
+
+use std::fmt::Debug;
+
+fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'a + Debug,
+{
+ x
+}
+
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'b + Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'b + Debug,
+ 'b: 'a,
+{
+ x
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/ty-param-fn.stderr b/tests/ui/nll/ty-outlives/ty-param-fn.stderr
new file mode 100644
index 000000000..825b26d2f
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-fn.stderr
@@ -0,0 +1,25 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-fn.rs:9:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Debug + 'a,
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-fn.rs:24:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + Debug + 'a,
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/ty-outlives/ty-param-implied-bounds.rs b/tests/ui/nll/ty-outlives/ty-param-implied-bounds.rs
new file mode 100644
index 000000000..9042844e8
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/ty-param-implied-bounds.rs
@@ -0,0 +1,28 @@
+// compile-flags:-Zverbose
+// check-pass
+
+// Test that we assume that universal types like `T` outlive the
+// function body.
+
+use std::cell::Cell;
+
+fn twice<F, T>(value: T, mut f: F)
+where
+ F: FnMut(Cell<&T>),
+{
+ f(Cell::new(&value));
+ f(Cell::new(&value));
+}
+
+fn generic<T>(value: T) {
+ // No error here:
+ twice(value, |r| invoke(r));
+}
+
+fn invoke<'a, T>(x: Cell<&'a T>)
+where
+ T: 'a,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/wf-unreachable.rs b/tests/ui/nll/ty-outlives/wf-unreachable.rs
new file mode 100644
index 000000000..c6f4c4afa
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/wf-unreachable.rs
@@ -0,0 +1,52 @@
+// Test that we check that user type annotations are well-formed, even in dead
+// code.
+
+fn uninit<'a>() {
+ return;
+ let x: &'static &'a (); //~ ERROR lifetime may not live long enough
+}
+
+fn var_type<'a>() {
+ return;
+ let x: &'static &'a () = &&(); //~ ERROR lifetime may not live long enough
+}
+
+fn uninit_infer<'a>() {
+ let x: &'static &'a _; //~ ERROR lifetime may not live long enough
+ x = && ();
+}
+
+fn infer<'a>() {
+ return;
+ let x: &'static &'a _ = &&(); //~ ERROR lifetime may not live long enough
+}
+
+fn uninit_no_var<'a>() {
+ return;
+ let _: &'static &'a (); //~ ERROR lifetime may not live long enough
+}
+
+fn no_var<'a>() {
+ return;
+ let _: &'static &'a () = &&(); //~ ERROR lifetime may not live long enough
+}
+
+fn infer_no_var<'a>() {
+ return;
+ let _: &'static &'a _ = &&(); //~ ERROR lifetime may not live long enough
+}
+
+trait X<'a, 'b> {}
+
+struct C<'a, 'b, T: X<'a, 'b>>(T, &'a (), &'b ());
+
+impl X<'_, '_> for i32 {}
+impl<'a> X<'a, 'a> for () {}
+
+// This type annotation is not well-formed because we substitute `()` for `_`.
+fn required_substs<'a>() {
+ return;
+ let _: C<'static, 'a, _> = C((), &(), &()); //~ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/wf-unreachable.stderr b/tests/ui/nll/ty-outlives/wf-unreachable.stderr
new file mode 100644
index 000000000..da3bc2083
--- /dev/null
+++ b/tests/ui/nll/ty-outlives/wf-unreachable.stderr
@@ -0,0 +1,73 @@
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:6:12
+ |
+LL | fn uninit<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let x: &'static &'a ();
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:11:12
+ |
+LL | fn var_type<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let x: &'static &'a () = &&();
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:15:12
+ |
+LL | fn uninit_infer<'a>() {
+ | -- lifetime `'a` defined here
+LL | let x: &'static &'a _;
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:21:12
+ |
+LL | fn infer<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let x: &'static &'a _ = &&();
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:26:12
+ |
+LL | fn uninit_no_var<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: &'static &'a ();
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:31:12
+ |
+LL | fn no_var<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: &'static &'a () = &&();
+ | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:36:12
+ |
+LL | fn infer_no_var<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: &'static &'a _ = &&();
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:49:12
+ |
+LL | fn required_substs<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: C<'static, 'a, _> = C((), &(), &());
+ | ^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/nll/type-alias-free-regions.rs b/tests/ui/nll/type-alias-free-regions.rs
new file mode 100644
index 000000000..fd5566f35
--- /dev/null
+++ b/tests/ui/nll/type-alias-free-regions.rs
@@ -0,0 +1,31 @@
+// Test that we don't assume that type aliases have the same type parameters
+// as the type they alias and then panic when we see this.
+
+type A<'a> = &'a isize;
+type B<'a> = Box<A<'a>>;
+
+struct C<'a> {
+ f: Box<B<'a>>
+}
+
+trait FromBox<'a> {
+ fn from_box(b: Box<B>) -> Self;
+}
+
+impl<'a> FromBox<'a> for C<'a> {
+ fn from_box(b: Box<B>) -> Self {
+ C { f: b } //~ ERROR
+ }
+}
+
+trait FromTuple<'a> {
+ fn from_tuple( b: (B,)) -> Self;
+}
+
+impl<'a> FromTuple<'a> for C<'a> {
+ fn from_tuple(b: (B,)) -> Self {
+ C { f: Box::new(b.0) } //~ ERROR
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/type-alias-free-regions.stderr b/tests/ui/nll/type-alias-free-regions.stderr
new file mode 100644
index 000000000..45fd5a2f1
--- /dev/null
+++ b/tests/ui/nll/type-alias-free-regions.stderr
@@ -0,0 +1,22 @@
+error: lifetime may not live long enough
+ --> $DIR/type-alias-free-regions.rs:17:9
+ |
+LL | impl<'a> FromBox<'a> for C<'a> {
+ | -- lifetime `'a` defined here
+LL | fn from_box(b: Box<B>) -> Self {
+ | - has type `Box<Box<&'1 isize>>`
+LL | C { f: b }
+ | ^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/type-alias-free-regions.rs:27:9
+ |
+LL | impl<'a> FromTuple<'a> for C<'a> {
+ | -- lifetime `'a` defined here
+LL | fn from_tuple(b: (B,)) -> Self {
+ | - has type `(Box<&'1 isize>,)`
+LL | C { f: Box::new(b.0) }
+ | ^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/type-check-pointer-coercions.rs b/tests/ui/nll/type-check-pointer-coercions.rs
new file mode 100644
index 000000000..66da57248
--- /dev/null
+++ b/tests/ui/nll/type-check-pointer-coercions.rs
@@ -0,0 +1,37 @@
+fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 {
+ x //~ ERROR
+}
+
+fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 {
+ x //~ ERROR
+}
+
+fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 {
+ // Two errors because *mut is invariant
+ x //~ ERROR
+ //~| ERROR
+}
+
+fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 {
+ x //~ ERROR
+}
+
+fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 {
+ let z = &[x; 3];
+ let y = z as *const &i32;
+ y //~ ERROR
+}
+
+fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] {
+ let z = &[x; 3];
+ let y = z as *const [&i32; 3];
+ y //~ ERROR
+}
+
+fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] {
+ let z = &[[x; 2]; 3];
+ let y = z as *const [&i32; 2];
+ y //~ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/type-check-pointer-coercions.stderr b/tests/ui/nll/type-check-pointer-coercions.stderr
new file mode 100644
index 000000000..ef2d92878
--- /dev/null
+++ b/tests/ui/nll/type-check-pointer-coercions.stderr
@@ -0,0 +1,111 @@
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:2:5
+ |
+LL | fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x
+ | ^ 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: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:6:5
+ |
+LL | fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x
+ | ^ 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: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:11:5
+ |
+LL | fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | // Two errors because *mut is invariant
+LL | x
+ | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable pointer to `&i32`
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:11:5
+ |
+LL | fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | // Two errors because *mut is invariant
+LL | x
+ | ^ 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`
+ = note: requirement occurs because of a mutable pointer to `&i32`
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'b` and `'a` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:16:5
+ |
+LL | fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x
+ | ^ 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: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:22:5
+ |
+LL | fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | y
+ | ^ 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: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:28:5
+ |
+LL | fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | y
+ | ^ 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: lifetime may not live long enough
+ --> $DIR/type-check-pointer-coercions.rs:34:5
+ |
+LL | fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | y
+ | ^ 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 8 previous errors
+
diff --git a/tests/ui/nll/type-check-pointer-comparisons.rs b/tests/ui/nll/type-check-pointer-comparisons.rs
new file mode 100644
index 000000000..7b0ffeaef
--- /dev/null
+++ b/tests/ui/nll/type-check-pointer-comparisons.rs
@@ -0,0 +1,31 @@
+// Check that we assert that pointers have a common subtype for comparisons
+
+fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
+ x == y;
+ //~^ ERROR lifetime may not live long enough
+ //~| ERROR lifetime may not live long enough
+}
+
+fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
+ x == y;
+ //~^ ERROR lifetime may not live long enough
+ //~| ERROR lifetime may not live long enough
+}
+
+fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) {
+ f == g;
+ //~^ ERROR lifetime may not live long enough
+ //~| ERROR lifetime may not live long enough
+}
+
+fn compare_hr_fn_ptr<'a>(f: fn(&'a i32), g: fn(&i32)) {
+ // Ideally this should compile with the operands swapped as well, but HIR
+ // type checking prevents it (and stops compilation) for now.
+ f == g; // OK
+}
+
+fn compare_const_fn_ptr<'a>(f: *const fn(&'a i32), g: *const fn(&i32)) {
+ f == g; // OK
+}
+
+fn main() {}
diff --git a/tests/ui/nll/type-check-pointer-comparisons.stderr b/tests/ui/nll/type-check-pointer-comparisons.stderr
new file mode 100644
index 000000000..0d8480a42
--- /dev/null
+++ b/tests/ui/nll/type-check-pointer-comparisons.stderr
@@ -0,0 +1,98 @@
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-comparisons.rs:4:5
+ |
+LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x == y;
+ | ^ requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to `&i32`
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-comparisons.rs:4:10
+ |
+LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x == y;
+ | ^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to `&i32`
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-comparisons.rs:10:5
+ |
+LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x == y;
+ | ^ requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable pointer to `&i32`
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-comparisons.rs:10:10
+ |
+LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x == y;
+ | ^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable pointer to `&i32`
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-comparisons.rs:16:5
+ |
+LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | f == g;
+ | ^ requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to `&i32`
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/type-check-pointer-comparisons.rs:16:10
+ |
+LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | f == g;
+ | ^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to `&i32`
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/nll/type-test-universe.rs b/tests/ui/nll/type-test-universe.rs
new file mode 100644
index 000000000..f9801c07d
--- /dev/null
+++ b/tests/ui/nll/type-test-universe.rs
@@ -0,0 +1,21 @@
+// Regression test for #98095: make sure that
+// we detect that S needs to outlive 'static.
+
+fn outlives_forall<T>()
+where
+ for<'u> T: 'u,
+{
+}
+
+fn test1<S>() {
+ outlives_forall::<S>();
+ //~^ ERROR `S` does not live long enough
+}
+
+struct Value<'a>(&'a ());
+fn test2<'a>() {
+ outlives_forall::<Value<'a>>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/type-test-universe.stderr b/tests/ui/nll/type-test-universe.stderr
new file mode 100644
index 000000000..31e17d64b
--- /dev/null
+++ b/tests/ui/nll/type-test-universe.stderr
@@ -0,0 +1,22 @@
+error: `S` does not live long enough
+ --> $DIR/type-test-universe.rs:11:5
+ |
+LL | outlives_forall::<S>();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+ --> $DIR/type-test-universe.rs:17:5
+ |
+LL | fn test2<'a>() {
+ | -- lifetime `'a` defined here
+LL | outlives_forall::<Value<'a>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+ |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+ --> $DIR/type-test-universe.rs:6:16
+ |
+LL | for<'u> T: 'u,
+ | ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/unused-mut-issue-50343.fixed b/tests/ui/nll/unused-mut-issue-50343.fixed
new file mode 100644
index 000000000..5632de1cd
--- /dev/null
+++ b/tests/ui/nll/unused-mut-issue-50343.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#![deny(unused_mut)]
+#![allow(unused_variables)] // for rustfix
+
+fn main() {
+ vec![(42, 22)].iter().map(|(x, _y)| ()).count();
+ //~^ ERROR: variable does not need to be mutable
+}
diff --git a/tests/ui/nll/unused-mut-issue-50343.rs b/tests/ui/nll/unused-mut-issue-50343.rs
new file mode 100644
index 000000000..c849ac8c7
--- /dev/null
+++ b/tests/ui/nll/unused-mut-issue-50343.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#![deny(unused_mut)]
+#![allow(unused_variables)] // for rustfix
+
+fn main() {
+ vec![(42, 22)].iter().map(|(mut x, _y)| ()).count();
+ //~^ ERROR: variable does not need to be mutable
+}
diff --git a/tests/ui/nll/unused-mut-issue-50343.stderr b/tests/ui/nll/unused-mut-issue-50343.stderr
new file mode 100644
index 000000000..cb02d7620
--- /dev/null
+++ b/tests/ui/nll/unused-mut-issue-50343.stderr
@@ -0,0 +1,16 @@
+error: variable does not need to be mutable
+ --> $DIR/unused-mut-issue-50343.rs:7:33
+ |
+LL | vec![(42, 22)].iter().map(|(mut x, _y)| ()).count();
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+note: the lint level is defined here
+ --> $DIR/unused-mut-issue-50343.rs:3:9
+ |
+LL | #![deny(unused_mut)]
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/adt-brace-enums.rs b/tests/ui/nll/user-annotations/adt-brace-enums.rs
new file mode 100644
index 000000000..0d9828342
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-brace-enums.rs
@@ -0,0 +1,50 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+enum SomeEnum<T> {
+ SomeVariant { t: T }
+}
+
+fn no_annot() {
+ let c = 66;
+ SomeEnum::SomeVariant { t: &c };
+}
+
+fn annot_underscore() {
+ let c = 66;
+ SomeEnum::SomeVariant::<_> { t: &c };
+}
+
+fn annot_reference_any_lifetime() {
+ let c = 66;
+ SomeEnum::SomeVariant::<&u32> { t: &c };
+}
+
+fn annot_reference_static_lifetime() {
+ let c = 66;
+ SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let c = 66;
+ SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ SomeEnum::SomeVariant::<&'a u32> { t: c };
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let _closure = || {
+ let c = 66;
+ SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let _closure = || {
+ SomeEnum::SomeVariant::<&'a u32> { t: c };
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/adt-brace-enums.stderr b/tests/ui/nll/user-annotations/adt-brace-enums.stderr
new file mode 100644
index 000000000..253e38251
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-brace-enums.stderr
@@ -0,0 +1,42 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-brace-enums.rs:25:48
+ |
+LL | SomeEnum::SomeVariant::<&'static u32> { t: &c };
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-brace-enums.rs:30:43
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+LL | let c = 66;
+LL | SomeEnum::SomeVariant::<&'a u32> { t: &c };
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-brace-enums.rs:40:47
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | SomeEnum::SomeVariant::<&'a u32> { t: &c };
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/adt-brace-structs.rs b/tests/ui/nll/user-annotations/adt-brace-structs.rs
new file mode 100644
index 000000000..bdbfd87d5
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-brace-structs.rs
@@ -0,0 +1,48 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+struct SomeStruct<T> { t: T }
+
+fn no_annot() {
+ let c = 66;
+ SomeStruct { t: &c };
+}
+
+fn annot_underscore() {
+ let c = 66;
+ SomeStruct::<_> { t: &c };
+}
+
+fn annot_reference_any_lifetime() {
+ let c = 66;
+ SomeStruct::<&u32> { t: &c };
+}
+
+fn annot_reference_static_lifetime() {
+ let c = 66;
+ SomeStruct::<&'static u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let c = 66;
+ SomeStruct::<&'a u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ SomeStruct::<&'a u32> { t: c };
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let _closure = || {
+ let c = 66;
+ SomeStruct::<&'a u32> { t: &c }; //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let _closure = || {
+ SomeStruct::<&'a u32> { t: c };
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/adt-brace-structs.stderr b/tests/ui/nll/user-annotations/adt-brace-structs.stderr
new file mode 100644
index 000000000..8b9d1705d
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-brace-structs.stderr
@@ -0,0 +1,42 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-brace-structs.rs:23:37
+ |
+LL | SomeStruct::<&'static u32> { t: &c };
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-brace-structs.rs:28:32
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+LL | let c = 66;
+LL | SomeStruct::<&'a u32> { t: &c };
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-brace-structs.rs:38:36
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | SomeStruct::<&'a u32> { t: &c };
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/adt-nullary-enums.rs b/tests/ui/nll/user-annotations/adt-nullary-enums.rs
new file mode 100644
index 000000000..53853668d
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-nullary-enums.rs
@@ -0,0 +1,69 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![allow(warnings)]
+
+use std::cell::Cell;
+
+enum SomeEnum<T> {
+ SomeVariant(T),
+ SomeOtherVariant,
+}
+
+fn combine<T>(_: T, _: T) { }
+
+fn no_annot() {
+ let c = 66;
+ combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant);
+}
+
+fn annot_underscore() {
+ let c = 66;
+ combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::<Cell<_>>);
+}
+
+fn annot_reference_any_lifetime() {
+ let c = 66;
+ combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::<Cell<&u32>>);
+}
+
+fn annot_reference_static_lifetime() {
+ let c = 66;
+ combine(
+ SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+ SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
+ );
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let c = 66;
+ combine(
+ SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+ SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
+ );
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ combine(SomeEnum::SomeVariant(Cell::new(c)), SomeEnum::SomeOtherVariant::<Cell<&'a u32>>);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let _closure = || {
+ let c = 66;
+ combine(
+ SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+ SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
+ );
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let _closure = || {
+ combine(
+ SomeEnum::SomeVariant(Cell::new(c)),
+ SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
+ );
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
new file mode 100644
index 000000000..3326fa521
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -0,0 +1,45 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-nullary-enums.rs:33:41
+ |
+LL | / combine(
+LL | | SomeEnum::SomeVariant(Cell::new(&c)),
+ | | ^^ borrowed value does not live long enough
+LL | | SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
+LL | | );
+ | |_____- argument requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-nullary-enums.rs:41:41
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | SomeEnum::SomeVariant(Cell::new(&c)),
+ | ----------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+...
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-nullary-enums.rs:54:45
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | SomeEnum::SomeVariant(Cell::new(&c)),
+ | ----------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+...
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/adt-tuple-enums.rs b/tests/ui/nll/user-annotations/adt-tuple-enums.rs
new file mode 100644
index 000000000..efe8dfda1
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-tuple-enums.rs
@@ -0,0 +1,53 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![allow(warnings)]
+
+enum SomeEnum<T> {
+ SomeVariant(T),
+ SomeOtherVariant,
+}
+
+fn no_annot() {
+ let c = 66;
+ SomeEnum::SomeVariant(&c);
+}
+
+fn annot_underscore() {
+ let c = 66;
+ SomeEnum::SomeVariant::<_>(&c);
+}
+
+fn annot_reference_any_lifetime() {
+ let c = 66;
+ SomeEnum::SomeVariant::<&u32>(&c);
+}
+
+fn annot_reference_static_lifetime() {
+ let c = 66;
+ SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let c = 66;
+ SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ SomeEnum::SomeVariant::<&'a u32>(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let _closure = || {
+ let c = 66;
+ SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let _closure = || {
+ SomeEnum::SomeVariant::<&'a u32>(c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/adt-tuple-enums.stderr b/tests/ui/nll/user-annotations/adt-tuple-enums.stderr
new file mode 100644
index 000000000..2fa704263
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-tuple-enums.stderr
@@ -0,0 +1,42 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-enums.rs:28:43
+ |
+LL | SomeEnum::SomeVariant::<&'static u32>(&c);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-enums.rs:33:38
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+LL | let c = 66;
+LL | SomeEnum::SomeVariant::<&'a u32>(&c);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-enums.rs:43:42
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | SomeEnum::SomeVariant::<&'a u32>(&c);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.rs b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.rs
new file mode 100644
index 000000000..116583223
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.rs
@@ -0,0 +1,71 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+struct SomeStruct<T>(T);
+
+fn no_annot() {
+ let c = 66;
+ let f = SomeStruct;
+ f(&c);
+}
+
+fn annot_underscore() {
+ let c = 66;
+ let f = SomeStruct::<_>;
+ f(&c);
+}
+
+fn annot_reference_any_lifetime() {
+ let c = 66;
+ let f = SomeStruct::<&u32>;
+ f(&c);
+}
+
+fn annot_reference_static_lifetime() {
+ let c = 66;
+ let f = SomeStruct::<&'static u32>;
+ f(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let c = 66;
+ let f = SomeStruct::<&'a u32>;
+ f(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ let f = SomeStruct::<&'a u32>;
+ f(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let _closure = || {
+ let c = 66;
+ let f = SomeStruct::<&'a u32>;
+ f(&c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_across_closure<'a>(_: &'a u32) {
+ let f = SomeStruct::<&'a u32>;
+ let _closure = || {
+ let c = 66;
+ f(&c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let _closure = || {
+ let f = SomeStruct::<&'a u32>;
+ f(c);
+ };
+}
+
+fn annot_reference_named_lifetime_across_closure_ok<'a>(c: &'a u32) {
+ let f = SomeStruct::<&'a u32>;
+ let _closure = || {
+ f(c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
new file mode 100644
index 000000000..9664fb9f5
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
@@ -0,0 +1,56 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-struct-calls.rs:27:7
+ |
+LL | f(&c);
+ | --^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-struct-calls.rs:33:7
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | f(&c);
+ | --^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-struct-calls.rs:45:11
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | f(&c);
+ | --^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-struct-calls.rs:53:11
+ |
+LL | let f = SomeStruct::<&'a u32>;
+ | - lifetime `'1` appears in the type of `f`
+...
+LL | f(&c);
+ | --^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'1`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct.rs b/tests/ui/nll/user-annotations/adt-tuple-struct.rs
new file mode 100644
index 000000000..37284e1fd
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-tuple-struct.rs
@@ -0,0 +1,48 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+struct SomeStruct<T>(T);
+
+fn no_annot() {
+ let c = 66;
+ SomeStruct(&c);
+}
+
+fn annot_underscore() {
+ let c = 66;
+ SomeStruct::<_>(&c);
+}
+
+fn annot_reference_any_lifetime() {
+ let c = 66;
+ SomeStruct::<&u32>(&c);
+}
+
+fn annot_reference_static_lifetime() {
+ let c = 66;
+ SomeStruct::<&'static u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let c = 66;
+ SomeStruct::<&'a u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ SomeStruct::<&'a u32>(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let _closure = || {
+ let c = 66;
+ SomeStruct::<&'a u32>(&c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let _closure = || {
+ SomeStruct::<&'a u32>(c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct.stderr
new file mode 100644
index 000000000..76b525225
--- /dev/null
+++ b/tests/ui/nll/user-annotations/adt-tuple-struct.stderr
@@ -0,0 +1,42 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-struct.rs:23:32
+ |
+LL | SomeStruct::<&'static u32>(&c);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-struct.rs:28:27
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+LL | let c = 66;
+LL | SomeStruct::<&'a u32>(&c);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/adt-tuple-struct.rs:38:31
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | SomeStruct::<&'a u32>(&c);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/ascribed-type-wf.rs b/tests/ui/nll/user-annotations/ascribed-type-wf.rs
new file mode 100644
index 000000000..5db02c46e
--- /dev/null
+++ b/tests/ui/nll/user-annotations/ascribed-type-wf.rs
@@ -0,0 +1,17 @@
+// Regression test for #101350.
+// check-fail
+
+trait Trait {
+ type Ty;
+}
+
+impl Trait for &'static () {
+ type Ty = ();
+}
+
+fn extend<'a>() {
+ None::<<&'a () as Trait>::Ty>;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/ascribed-type-wf.stderr b/tests/ui/nll/user-annotations/ascribed-type-wf.stderr
new file mode 100644
index 000000000..91e7c6b8e
--- /dev/null
+++ b/tests/ui/nll/user-annotations/ascribed-type-wf.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/ascribed-type-wf.rs:13:5
+ |
+LL | fn extend<'a>() {
+ | -- lifetime `'a` defined here
+LL | None::<<&'a () as Trait>::Ty>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/cast_static_lifetime.rs b/tests/ui/nll/user-annotations/cast_static_lifetime.rs
new file mode 100644
index 000000000..bb6129dac
--- /dev/null
+++ b/tests/ui/nll/user-annotations/cast_static_lifetime.rs
@@ -0,0 +1,6 @@
+#![allow(warnings)]
+
+fn main() {
+ let x = 22_u32;
+ let y: &u32 = (&x) as &'static u32; //~ ERROR `x` does not live long enough
+}
diff --git a/tests/ui/nll/user-annotations/cast_static_lifetime.stderr b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr
new file mode 100644
index 000000000..4599d04e7
--- /dev/null
+++ b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/cast_static_lifetime.rs:5:19
+ |
+LL | let y: &u32 = (&x) as &'static u32;
+ | ^^^^----------------
+ | |
+ | borrowed value does not live long enough
+ | type annotation requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` 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/nll/user-annotations/closure-sig.rs b/tests/ui/nll/user-annotations/closure-sig.rs
new file mode 100644
index 000000000..4dbd3fd8d
--- /dev/null
+++ b/tests/ui/nll/user-annotations/closure-sig.rs
@@ -0,0 +1,15 @@
+// This test fails if #104478 is fixed before #104477.
+
+// check-pass
+
+struct Printer<'a, 'b>(&'a (), &'b ());
+
+impl Printer<'_, '_> {
+ fn test(self) {
+ let clo = |_: &'_ Self| {};
+ clo(&self);
+ clo(&self);
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/closure-substs.polonius.stderr b/tests/ui/nll/user-annotations/closure-substs.polonius.stderr
new file mode 100644
index 000000000..af159a6cd
--- /dev/null
+++ b/tests/ui/nll/user-annotations/closure-substs.polonius.stderr
@@ -0,0 +1,61 @@
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:8:16
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | return x;
+ | ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:15:16
+ |
+LL | |x: &i32| -> &'static i32 {
+ | - let's call the lifetime of this reference `'1`
+LL | return x;
+ | ^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:15:16
+ |
+LL | |x: &i32| -> &'static i32 {
+ | - - let's call the lifetime of this reference `'2`
+ | |
+ | let's call the lifetime of this reference `'1`
+LL | return x;
+ | ^ returning this value requires that `'1` must outlive `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:22:9
+ |
+LL | fn bar<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | b(x);
+ | ^^^^ argument requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/closure-substs.rs:29:9
+ |
+LL | |x: &i32, b: fn(&'static i32)| {
+ | - `x` is a reference that is only valid in the closure body
+LL | b(x);
+ | ^^^^ `x` escapes the closure body here
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/closure-substs.rs:29:9
+ |
+LL | |x: &i32, b: fn(&'static i32)| {
+ | - - `b` declared here, outside of the closure body
+ | |
+ | `x` is a reference that is only valid in the closure body
+LL | b(x);
+ | ^^^^ `x` escapes the closure body here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/user-annotations/closure-substs.rs b/tests/ui/nll/user-annotations/closure-substs.rs
new file mode 100644
index 000000000..f7af54e8d
--- /dev/null
+++ b/tests/ui/nll/user-annotations/closure-substs.rs
@@ -0,0 +1,31 @@
+// Test that we enforce user-provided type annotations on closures.
+
+fn foo<'a>() {
+ // Here `x` is free in the closure sig:
+ |x: &'a i32| -> &'static i32 {
+ return x; //~ ERROR lifetime may not live long enough
+ };
+}
+
+fn foo1() {
+ // Here `x` is bound in the closure sig:
+ |x: &i32| -> &'static i32 {
+ return x; //~ ERROR lifetime may not live long enough
+ };
+}
+
+fn bar<'a>() {
+ // Here `x` is free in the closure sig:
+ |x: &'a i32, b: fn(&'static i32)| {
+ b(x); //~ ERROR lifetime may not live long enough
+ };
+}
+
+fn bar1() {
+ // Here `x` is bound in the closure sig:
+ |x: &i32, b: fn(&'static i32)| {
+ b(x); //~ ERROR borrowed data escapes outside of closure
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/closure-substs.stderr b/tests/ui/nll/user-annotations/closure-substs.stderr
new file mode 100644
index 000000000..1e8de4ba9
--- /dev/null
+++ b/tests/ui/nll/user-annotations/closure-substs.stderr
@@ -0,0 +1,42 @@
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:6:16
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | return x;
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:13:16
+ |
+LL | |x: &i32| -> &'static i32 {
+ | - let's call the lifetime of this reference `'1`
+LL | return x;
+ | ^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:20:9
+ |
+LL | fn bar<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | b(x);
+ | ^^^^ argument requires that `'a` must outlive `'static`
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/closure-substs.rs:27:9
+ |
+LL | |x: &i32, b: fn(&'static i32)| {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | `x` is a reference that is only valid in the closure body
+LL | b(x);
+ | ^^^^
+ | |
+ | `x` escapes the closure body here
+ | argument requires that `'1` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-inherent-1.rs b/tests/ui/nll/user-annotations/constant-in-expr-inherent-1.rs
new file mode 100644
index 000000000..e3a8a5f58
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-inherent-1.rs
@@ -0,0 +1,12 @@
+struct Foo<'a> { x: &'a u32 }
+
+impl<'a> Foo<'a> {
+ const C: &'a u32 = &22;
+}
+
+fn foo<'a>(_: &'a u32) -> &'static u32 {
+ <Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/tests/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
new file mode 100644
index 000000000..c39301588
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/constant-in-expr-inherent-1.rs:8:5
+ |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | <Foo<'a>>::C
+ | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.rs b/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.rs
new file mode 100644
index 000000000..90696d4b1
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.rs
@@ -0,0 +1,27 @@
+// Test that we still check constants are well-formed, even when we there's no
+// type annotation to check.
+
+const FUN: fn(&'static ()) = |_| {};
+struct A;
+impl A {
+ const ASSOCIATED_FUN: fn(&'static ()) = |_| {};
+}
+
+struct B<'a>(&'a ());
+impl B<'static> {
+ const ALSO_ASSOCIATED_FUN: fn(&'static ()) = |_| {};
+}
+
+trait Z: 'static {
+ const TRAIT_ASSOCIATED_FUN: fn(&'static Self) = |_| ();
+}
+
+impl Z for () {}
+
+fn main() {
+ let x = ();
+ FUN(&x); //~ ERROR `x` does not live long enough
+ A::ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
+ B::ALSO_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
+ <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough
+}
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr b/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
new file mode 100644
index 000000000..12065a85a
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
@@ -0,0 +1,50 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/constant-in-expr-inherent-2.rs:23:9
+ |
+LL | FUN(&x);
+ | ----^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `x` is borrowed for `'static`
+...
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/constant-in-expr-inherent-2.rs:24:23
+ |
+LL | A::ASSOCIATED_FUN(&x);
+ | ------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `x` is borrowed for `'static`
+...
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/constant-in-expr-inherent-2.rs:25:28
+ |
+LL | B::ALSO_ASSOCIATED_FUN(&x);
+ | -----------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `x` is borrowed for `'static`
+LL | <_>::TRAIT_ASSOCIATED_FUN(&x);
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/constant-in-expr-inherent-2.rs:26:31
+ |
+LL | <_>::TRAIT_ASSOCIATED_FUN(&x);
+ | --------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` dropped here while still borrowed
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-normalize.rs b/tests/ui/nll/user-annotations/constant-in-expr-normalize.rs
new file mode 100644
index 000000000..b7095430d
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-normalize.rs
@@ -0,0 +1,22 @@
+trait Mirror {
+ type Me;
+}
+
+impl<T> Mirror for T {
+ type Me = T;
+}
+
+trait Foo<'a> {
+ const C: <&'a u32 as Mirror>::Me;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: &'a u32 = &22;
+}
+
+fn foo<'a>(_: &'a u32) -> &'static u32 {
+ <() as Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-normalize.stderr b/tests/ui/nll/user-annotations/constant-in-expr-normalize.stderr
new file mode 100644
index 000000000..541a2cfaf
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-normalize.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/constant-in-expr-normalize.rs:18:5
+ |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | <() as Foo<'a>>::C
+ | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs
new file mode 100644
index 000000000..e0400b2cc
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs
@@ -0,0 +1,14 @@
+trait Foo<'a> {
+ const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: &'a u32 = &22;
+}
+
+fn foo<'a>(_: &'a u32) -> &'static u32 {
+ <() as Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
new file mode 100644
index 000000000..ea0fcb6d6
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/constant-in-expr-trait-item-1.rs:10:5
+ |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | <() as Foo<'a>>::C
+ | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs
new file mode 100644
index 000000000..73c4e577b
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs
@@ -0,0 +1,14 @@
+trait Foo<'a> {
+ const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: &'a u32 = &22;
+}
+
+fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+ <T as Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
new file mode 100644
index 000000000..ff549f1d8
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/constant-in-expr-trait-item-2.rs:10:5
+ |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | <T as Foo<'a>>::C
+ | ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
new file mode 100644
index 000000000..567e31ef9
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
@@ -0,0 +1,14 @@
+trait Foo<'a> {
+ const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: &'a u32 = &22;
+}
+
+fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+ T::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
new file mode 100644
index 000000000..7f160d8e3
--- /dev/null
+++ b/tests/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/constant-in-expr-trait-item-3.rs:10:5
+ |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | T::C
+ | ^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/downcast-infer.rs b/tests/ui/nll/user-annotations/downcast-infer.rs
new file mode 100644
index 000000000..b27429f4d
--- /dev/null
+++ b/tests/ui/nll/user-annotations/downcast-infer.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+// Check that we don't try to downcast `_` when type-checking the annotation.
+fn main() {
+ let x = Some(Some(Some(1)));
+
+ match x {
+ Some::<Option<_>>(Some(Some(v))) => (),
+ _ => (),
+ }
+}
diff --git a/tests/ui/nll/user-annotations/dump-adt-brace-struct.rs b/tests/ui/nll/user-annotations/dump-adt-brace-struct.rs
new file mode 100644
index 000000000..ccda9129d
--- /dev/null
+++ b/tests/ui/nll/user-annotations/dump-adt-brace-struct.rs
@@ -0,0 +1,20 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+struct SomeStruct<T> { t: T }
+
+#[rustc_dump_user_substs]
+fn main() {
+ SomeStruct { t: 22 }; // Nothing given, no annotation.
+
+ SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation.
+
+ SomeStruct::<u32> { t: 22 }; // No lifetime bounds given.
+
+ SomeStruct::<&'static u32> { t: &22 }; //~ ERROR [&ReStatic u32]
+}
diff --git a/tests/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/tests/ui/nll/user-annotations/dump-adt-brace-struct.stderr
new file mode 100644
index 000000000..586062190
--- /dev/null
+++ b/tests/ui/nll/user-annotations/dump-adt-brace-struct.stderr
@@ -0,0 +1,8 @@
+error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None }
+ --> $DIR/dump-adt-brace-struct.rs:19:5
+ |
+LL | SomeStruct::<&'static u32> { t: &22 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/dump-fn-method.rs b/tests/ui/nll/user-annotations/dump-fn-method.rs
new file mode 100644
index 000000000..148d63d84
--- /dev/null
+++ b/tests/ui/nll/user-annotations/dump-fn-method.rs
@@ -0,0 +1,57 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+// Note: we reference the names T and U in the comments below.
+trait Bazoom<T> {
+ fn method<U>(&self, arg: T, arg2: U) { }
+}
+
+impl<S, T> Bazoom<T> for S {
+}
+
+fn foo<'a, T>(_: T) { }
+
+#[rustc_dump_user_substs]
+fn main() {
+ // Here: nothing is given, so we don't have any annotation.
+ let x = foo;
+ x(22);
+
+ // Here: `u32` is given, which doesn't contain any lifetimes, so we don't
+ // have any annotation.
+ let x = foo::<u32>;
+ x(22);
+
+ let x = foo::<&'static u32>; //~ ERROR [&ReStatic u32]
+ x(&22);
+
+ // Here: we only want the `T` to be given, the rest should be variables.
+ //
+ // (`T` refers to the declaration of `Bazoom`)
+ let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [^0, u32, ^1]
+ x(&22, 44, 66);
+
+ // Here: all are given and definitely contain no lifetimes, so we
+ // don't have any annotation.
+ let x = <u8 as Bazoom<u16>>::method::<u32>;
+ x(&22, 44, 66);
+
+ // Here: all are given and we have a lifetime.
+ let x = <u8 as Bazoom<&'static u16>>::method::<u32>; //~ ERROR [u8, &ReStatic u16, u32]
+ x(&22, &44, 66);
+
+ // Here: we want in particular that *only* the method `U`
+ // annotation is given, the rest are variables.
+ //
+ // (`U` refers to the declaration of `Bazoom`)
+ let y = 22_u32;
+ y.method::<u32>(44, 66); //~ ERROR [^0, ^1, u32]
+
+ // Here: nothing is given, so we don't have any annotation.
+ let y = 22_u32;
+ y.method(44, 66);
+}
diff --git a/tests/ui/nll/user-annotations/dump-fn-method.stderr b/tests/ui/nll/user-annotations/dump-fn-method.stderr
new file mode 100644
index 000000000..d139efa88
--- /dev/null
+++ b/tests/ui/nll/user-annotations/dump-fn-method.stderr
@@ -0,0 +1,26 @@
+error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None }
+ --> $DIR/dump-fn-method.rs:29:13
+ |
+LL | let x = foo::<&'static u32>;
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None }
+ --> $DIR/dump-fn-method.rs:35:13
+ |
+LL | let x = <_ as Bazoom<u32>>::method::<_>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: user substs: UserSubsts { substs: [u8, &ReStatic u16, u32], user_self_ty: None }
+ --> $DIR/dump-fn-method.rs:44:13
+ |
+LL | let x = <u8 as Bazoom<&'static u16>>::method::<u32>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None }
+ --> $DIR/dump-fn-method.rs:52:5
+ |
+LL | y.method::<u32>(44, 66);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/nll/user-annotations/fns.rs b/tests/ui/nll/user-annotations/fns.rs
new file mode 100644
index 000000000..38db6d1c4
--- /dev/null
+++ b/tests/ui/nll/user-annotations/fns.rs
@@ -0,0 +1,48 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+fn some_fn<T>(arg: T) { }
+
+fn no_annot() {
+ let c = 66;
+ some_fn(&c); // OK
+}
+
+fn annot_underscore() {
+ let c = 66;
+ some_fn::<_>(&c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+ let c = 66;
+ some_fn::<&u32>(&c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+ let c = 66;
+ some_fn::<&'static u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let c = 66;
+ some_fn::<&'a u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ some_fn::<&'a u32>(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let _closure = || {
+ let c = 66;
+ some_fn::<&'a u32>(&c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let _closure = || {
+ some_fn::<&'a u32>(c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/fns.stderr b/tests/ui/nll/user-annotations/fns.stderr
new file mode 100644
index 000000000..e0640da39
--- /dev/null
+++ b/tests/ui/nll/user-annotations/fns.stderr
@@ -0,0 +1,42 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/fns.rs:23:29
+ |
+LL | some_fn::<&'static u32>(&c);
+ | ------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/fns.rs:28:24
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+LL | let c = 66;
+LL | some_fn::<&'a u32>(&c);
+ | -------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/fns.rs:38:28
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | some_fn::<&'a u32>(&c);
+ | -------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/inherent-associated-constants.rs b/tests/ui/nll/user-annotations/inherent-associated-constants.rs
new file mode 100644
index 000000000..fe2641fd6
--- /dev/null
+++ b/tests/ui/nll/user-annotations/inherent-associated-constants.rs
@@ -0,0 +1,15 @@
+struct A<'a>(&'a ());
+
+impl A<'static> {
+ const IC: i32 = 10;
+}
+
+fn non_wf_associated_const<'a>(x: i32) {
+ A::<'a>::IC; //~ ERROR lifetime may not live long enough
+}
+
+fn wf_associated_const<'a>(x: i32) {
+ A::<'static>::IC;
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/inherent-associated-constants.stderr b/tests/ui/nll/user-annotations/inherent-associated-constants.stderr
new file mode 100644
index 000000000..ffbfc40f5
--- /dev/null
+++ b/tests/ui/nll/user-annotations/inherent-associated-constants.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/inherent-associated-constants.rs:8:5
+ |
+LL | fn non_wf_associated_const<'a>(x: i32) {
+ | -- lifetime `'a` defined here
+LL | A::<'a>::IC;
+ | ^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/user-annotations/issue-54124.rs b/tests/ui/nll/user-annotations/issue-54124.rs
new file mode 100644
index 000000000..5ae03c894
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-54124.rs
@@ -0,0 +1,8 @@
+fn test<'a>() {
+ let _:fn(&()) = |_:&'a ()| {}; //~ ERROR lifetime may not live long enough
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+ test();
+}
diff --git a/tests/ui/nll/user-annotations/issue-54124.stderr b/tests/ui/nll/user-annotations/issue-54124.stderr
new file mode 100644
index 000000000..2556af2dd
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-54124.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-54124.rs:2:22
+ |
+LL | fn test<'a>() {
+ | -- lifetime `'a` defined here
+LL | let _:fn(&()) = |_:&'a ()| {};
+ | ^ - let's call the lifetime of this reference `'1`
+ | |
+ | requires that `'1` must outlive `'a`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-54124.rs:2:22
+ |
+LL | fn test<'a>() {
+ | -- lifetime `'a` defined here
+LL | let _:fn(&()) = |_:&'a ()| {};
+ | ^ requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/nll/user-annotations/issue-54570-bootstrapping.rs b/tests/ui/nll/user-annotations/issue-54570-bootstrapping.rs
new file mode 100644
index 000000000..ff5b2244e
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-54570-bootstrapping.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+// This test is reduced from a scenario pnkfelix encountered while
+// bootstrapping the compiler.
+
+#[derive(Copy, Clone)]
+pub struct Spanned<T> {
+ pub node: T,
+ pub span: Span,
+}
+
+pub type Variant = Spanned<VariantKind>;
+// #[derive(Clone)] pub struct Variant { pub node: VariantKind, pub span: Span, }
+
+#[derive(Clone)]
+pub struct VariantKind { }
+
+#[derive(Copy, Clone)]
+pub struct Span;
+
+pub fn variant_to_span(variant: Variant) {
+ match variant {
+ Variant {
+ span: _span,
+ ..
+ } => { }
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/issue-55219.rs b/tests/ui/nll/user-annotations/issue-55219.rs
new file mode 100644
index 000000000..147413663
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-55219.rs
@@ -0,0 +1,18 @@
+// Regression test for #55219:
+//
+// The `Self::HASH_LEN` here expands to a "self-type" where `T` is not
+// known. This unbound inference variable was causing an ICE.
+//
+// check-pass
+
+pub struct Foo<T>(T);
+
+impl<T> Foo<T> {
+ const HASH_LEN: usize = 20;
+
+ fn stuff() {
+ let _ = Self::HASH_LEN;
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/issue-55241.rs b/tests/ui/nll/user-annotations/issue-55241.rs
new file mode 100644
index 000000000..29969c7b4
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-55241.rs
@@ -0,0 +1,26 @@
+// Regression test for #55241:
+//
+// The reference to `C::HASHED_NULL_NODE` resulted in a type like `<C
+// as NodeCodec<_>>::Out`; normalizing this type requires knowing the
+// value of `_`; solving that requires having normalized, so we can
+// test against `C: NodeCodec<H>` in the environment.
+//
+// run-pass
+
+pub trait Hasher {
+ type Out: Eq;
+}
+
+pub trait NodeCodec<H: Hasher> {
+ const HASHED_NULL_NODE: H::Out;
+}
+
+pub trait Trie<H: Hasher, C: NodeCodec<H>> {
+ /// Returns the root of the trie.
+ fn root(&self) -> &H::Out;
+
+ /// Is the trie empty?
+ fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs b/tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs
new file mode 100644
index 000000000..c71937a50
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs
@@ -0,0 +1,68 @@
+// This test is ensuring that type ascriptions on let bindings
+// constrain both:
+//
+// 1. the input expression on the right-hand side (after any potential
+// coercion, and allowing for covariance), *and*
+//
+// 2. the bindings (if any) nested within the pattern on the left-hand
+// side (and here, the type-constraint is *invariant*).
+
+#![allow(dead_code, unused_mut)]
+type PairUncoupled<'a, 'b, T> = (&'a T, &'b T);
+type PairCoupledRegions<'a, T> = (&'a T, &'a T);
+type PairCoupledTypes<T> = (T, T);
+
+fn uncoupled_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((mut y, mut _z),): (PairUncoupled<u32>,) = ((s, &_x),); // ok
+ // Above compiling does *not* imply below would compile.
+ // ::std::mem::swap(&mut y, &mut _z);
+ y
+}
+
+fn swap_regions((mut y, mut _z): PairCoupledRegions<u32>) {
+ ::std::mem::swap(&mut y, &mut _z);
+}
+
+fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),): (PairCoupledRegions<u32>,) = ((s, &_x),);
+ // If above line compiled, so should line below ...
+
+ // swap_regions((y, _z));
+
+ // ... but the ascribed type also invalidates this use of `y`
+ y //~ ERROR lifetime may not live long enough
+}
+
+fn swap_types((mut y, mut _z): PairCoupledTypes<&u32>) {
+ ::std::mem::swap(&mut y, &mut _z);
+}
+
+fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),): (PairCoupledTypes<&u32>,) = ((s, &_x),);
+ // If above line compiled, so should line below ...
+
+ // swap_types((y, _z));
+
+ // ... but the ascribed type also invalidates this use of `y`
+ y //~ ERROR lifetime may not live long enough
+}
+
+fn swap_wilds((mut y, mut _z): PairCoupledTypes<&u32>) {
+ ::std::mem::swap(&mut y, &mut _z);
+}
+
+fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),): (PairCoupledTypes<_>,) = ((s, &_x),);
+ // If above line compiled, so should line below
+ // swap_wilds((y, _z));
+
+ // ... but the ascribed type also invalidates this use of `y`
+ y //~ ERROR lifetime may not live long enough
+}
+
+fn main() {
+ uncoupled_lhs(&3, &4);
+ coupled_regions_lhs(&3, &4);
+ coupled_types_lhs(&3, &4);
+ coupled_wilds_lhs(&3, &4);
+}
diff --git a/tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr
new file mode 100644
index 000000000..8399ef04e
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr
@@ -0,0 +1,29 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-55748-pat-types-constrain-bindings.rs:33:5
+ |
+LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+...
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-55748-pat-types-constrain-bindings.rs:47:5
+ |
+LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+...
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-55748-pat-types-constrain-bindings.rs:60:5
+ |
+LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+...
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs b/tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs
new file mode 100644
index 000000000..95c655654
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs
@@ -0,0 +1,40 @@
+// Check that repeated type variables are correctly handled
+
+#![allow(unused)]
+#![feature(type_ascription)]
+
+type PairUncoupled<'a, 'b, T> = (&'a T, &'b T);
+type PairCoupledTypes<T> = (T, T);
+type PairCoupledRegions<'a, T> = (&'a T, &'a T);
+
+fn uncoupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),) = type_ascribe!(((s, _x),), (PairUncoupled<_>,));
+ y // OK
+}
+
+fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledTypes<_>,));
+ y //~ ERROR lifetime may not live long enough
+}
+
+fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledRegions<_>,));
+ y //~ ERROR lifetime may not live long enough
+}
+
+fn cast_uncoupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),) = ((s, _x),) as (PairUncoupled<_>,);
+ y // OK
+}
+
+fn cast_coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,);
+ y //~ ERROR lifetime may not live long enough
+}
+
+fn cast_coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,);
+ y //~ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr b/tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr
new file mode 100644
index 000000000..8601691e8
--- /dev/null
+++ b/tests/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr
@@ -0,0 +1,38 @@
+error: lifetime may not live long enough
+ --> $DIR/issue-57731-ascibed-coupled-types.rs:17:5
+ |
+LL | fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledTypes<_>,));
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-57731-ascibed-coupled-types.rs:22:5
+ |
+LL | fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledRegions<_>,));
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-57731-ascibed-coupled-types.rs:32:5
+ |
+LL | fn cast_coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,);
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-57731-ascibed-coupled-types.rs:37:5
+ |
+LL | fn cast_coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,);
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/nll/user-annotations/method-call.rs b/tests/ui/nll/user-annotations/method-call.rs
new file mode 100644
index 000000000..beafc597a
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-call.rs
@@ -0,0 +1,69 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+trait Bazoom<T> {
+ fn method<U>(&self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn no_annot() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ a.method(b, &c); // OK
+}
+
+fn annot_underscore() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ a.method::<_>(b, &c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ a.method::<&u32>(b, &c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ a.method::<&'static u32>(b, &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ a.method::<&'a u32>(b, &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ let a = 22;
+ let b = 44;
+ a.method::<&'a u32>(b, c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let _closure = || {
+ let c = 66;
+ a.method::<&'a u32>(b, &c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let _closure = || {
+ a.method::<&'a u32>(b, c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/method-call.stderr b/tests/ui/nll/user-annotations/method-call.stderr
new file mode 100644
index 000000000..10447e45a
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-call.stderr
@@ -0,0 +1,42 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/method-call.rs:36:34
+ |
+LL | a.method::<&'static u32>(b, &c);
+ | -----------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/method-call.rs:43:29
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | a.method::<&'a u32>(b, &c);
+ | ------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/method-call.rs:57:33
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | a.method::<&'a u32>(b, &c);
+ | ------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.rs b/tests/ui/nll/user-annotations/method-ufcs-1.rs
new file mode 100644
index 000000000..950771f35
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-1.rs
@@ -0,0 +1,63 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+trait Bazoom<T>: Sized {
+ fn method<U>(self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn annot_underscore() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<_>>::method::<_>(&a, b, c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <&u32 as Bazoom<_>>::method(&a, b, c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ let x = <&'static u32 as Bazoom<_>>::method;
+ x(&a, b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(a: &'a u32) {
+ let b = 44;
+ let c = 66;
+ <&'a u32 as Bazoom<_>>::method(&a, b, c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let _closure = || {
+ let c = 66;
+ <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(a: &'a u32) {
+ let b = 44;
+ let c = 66;
+ let _closure = || {
+ <&'a u32 as Bazoom<_>>::method(&a, b, c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr
new file mode 100644
index 000000000..962ddfd2b
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr
@@ -0,0 +1,46 @@
+error[E0597]: `a` does not live long enough
+ --> $DIR/method-ufcs-1.rs:30:7
+ |
+LL | x(&a, b, c);
+ | --^^-------
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `a` is borrowed for `'static`
+LL | }
+ | - `a` dropped here while still borrowed
+
+error[E0597]: `a` does not live long enough
+ --> $DIR/method-ufcs-1.rs:37:36
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | <&'a u32 as Bazoom<_>>::method(&a, b, c);
+ | -------------------------------^^-------
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `a` is borrowed for `'a`
+LL | }
+ | - `a` dropped here while still borrowed
+
+error[E0597]: `a` does not live long enough
+ --> $DIR/method-ufcs-1.rs:51:41
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | let _closure = || {
+ | -- value captured here
+LL | let c = 66;
+LL | <&'a u32 as Bazoom<_>>::method(&a, b, c);
+ | --------------------------------^-------
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `a` is borrowed for `'a`
+LL | };
+LL | }
+ | - `a` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.rs b/tests/ui/nll/user-annotations/method-ufcs-2.rs
new file mode 100644
index 000000000..7dc0f0c12
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-2.rs
@@ -0,0 +1,63 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+trait Bazoom<T>: Sized {
+ fn method<U>(self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn annot_underscore() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<_>>::method(a, &b, c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<&u32>>::method(a, &b, c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ let x = <&'static u32 as Bazoom<_>>::method;
+ x(&a, b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(b: &'a u32) {
+ let a = 44;
+ let c = 66;
+ <_ as Bazoom<&'a u32>>::method(a, &b, c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let _closure = || {
+ let c = 66;
+ <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(b: &'a u32) {
+ let a = 44;
+ let c = 66;
+ let _closure = || {
+ <_ as Bazoom<&'a u32>>::method(a, &b, c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr
new file mode 100644
index 000000000..63d59905e
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr
@@ -0,0 +1,46 @@
+error[E0597]: `a` does not live long enough
+ --> $DIR/method-ufcs-2.rs:30:7
+ |
+LL | x(&a, b, c);
+ | --^^-------
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `a` is borrowed for `'static`
+LL | }
+ | - `a` dropped here while still borrowed
+
+error[E0597]: `b` does not live long enough
+ --> $DIR/method-ufcs-2.rs:37:39
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | <_ as Bazoom<&'a u32>>::method(a, &b, c);
+ | ----------------------------------^^----
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `b` is borrowed for `'a`
+LL | }
+ | - `b` dropped here while still borrowed
+
+error[E0597]: `b` does not live long enough
+ --> $DIR/method-ufcs-2.rs:51:44
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | let _closure = || {
+ | -- value captured here
+LL | let c = 66;
+LL | <_ as Bazoom<&'a u32>>::method(a, &b, c);
+ | -----------------------------------^----
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `b` is borrowed for `'a`
+LL | };
+LL | }
+ | - `b` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/method-ufcs-3.rs b/tests/ui/nll/user-annotations/method-ufcs-3.rs
new file mode 100644
index 000000000..59d2009d1
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-3.rs
@@ -0,0 +1,69 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+trait Bazoom<T> {
+ fn method<U>(&self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn no_annot() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<_>>::method(&a, b, &c); // OK
+}
+
+fn annot_underscore() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<_>>::method::<_>(&a, b, &c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<_>>::method::<&u32>(&a, b, &c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let c = 66;
+ <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+ let a = 22;
+ let b = 44;
+ <_ as Bazoom<_>>::method::<&'a u32>(&a, b, c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let _closure = || {
+ let c = 66;
+ <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
+ };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+ let a = 22;
+ let b = 44;
+ let _closure = || {
+ <_ as Bazoom<_>>::method::<&'a u32>(&a, b, c);
+ };
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/method-ufcs-3.stderr b/tests/ui/nll/user-annotations/method-ufcs-3.stderr
new file mode 100644
index 000000000..e7851833e
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-3.stderr
@@ -0,0 +1,42 @@
+error[E0597]: `c` does not live long enough
+ --> $DIR/method-ufcs-3.rs:36:53
+ |
+LL | <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c);
+ | ------------------------------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/method-ufcs-3.rs:43:48
+ |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c);
+ | -------------------------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | }
+ | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+ --> $DIR/method-ufcs-3.rs:57:52
+ |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+...
+LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c);
+ | -------------------------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `c` is borrowed for `'a`
+LL | };
+ | - `c` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-1.rs b/tests/ui/nll/user-annotations/method-ufcs-inherent-1.rs
new file mode 100644
index 000000000..7bfed61d4
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-1.rs
@@ -0,0 +1,18 @@
+// Check that substitutions given on the self type (here, `A`) carry
+// through to NLL.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+ fn new<'b, T>(x: &'a u32, y: T) -> Self {
+ Self { x }
+ }
+}
+
+fn foo<'a>() {
+ let v = 22;
+ let x = A::<'a>::new(&v, 22);
+ //~^ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr
new file mode 100644
index 000000000..94861babd
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `v` does not live long enough
+ --> $DIR/method-ufcs-inherent-1.rs:14:26
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let v = 22;
+LL | let x = A::<'a>::new(&v, 22);
+ | -------------^^-----
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `v` is borrowed for `'a`
+LL |
+LL | }
+ | - `v` 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/nll/user-annotations/method-ufcs-inherent-2.rs b/tests/ui/nll/user-annotations/method-ufcs-inherent-2.rs
new file mode 100644
index 000000000..cfbc0bcf6
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-2.rs
@@ -0,0 +1,19 @@
+// Check that substitutions given on the self type (here, `A`) can be
+// used in combination with annotations given for method arguments.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+ fn new<'b, T>(x: &'a u32, y: T) -> Self {
+ Self { x }
+ }
+}
+
+fn foo<'a>() {
+ let v = 22;
+ let x = A::<'a>::new::<&'a u32>(&v, &v);
+ //~^ ERROR
+ //~| ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
new file mode 100644
index 000000000..06f20d9b2
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
@@ -0,0 +1,33 @@
+error[E0597]: `v` does not live long enough
+ --> $DIR/method-ufcs-inherent-2.rs:14:37
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let v = 22;
+LL | let x = A::<'a>::new::<&'a u32>(&v, &v);
+ | ------------------------^^-----
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `v` is borrowed for `'a`
+...
+LL | }
+ | - `v` dropped here while still borrowed
+
+error[E0597]: `v` does not live long enough
+ --> $DIR/method-ufcs-inherent-2.rs:14:41
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let v = 22;
+LL | let x = A::<'a>::new::<&'a u32>(&v, &v);
+ | ----------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `v` is borrowed for `'a`
+...
+LL | }
+ | - `v` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-3.rs b/tests/ui/nll/user-annotations/method-ufcs-inherent-3.rs
new file mode 100644
index 000000000..7ddb13360
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-3.rs
@@ -0,0 +1,18 @@
+// Check that inherent methods invoked with `<T>::new` style
+// carry their annotations through to NLL.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+ fn new<'b, T>(x: &'a u32, y: T) -> Self {
+ Self { x }
+ }
+}
+
+fn foo<'a>() {
+ let v = 22;
+ let x = <A<'a>>::new(&v, 22);
+ //~^ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr
new file mode 100644
index 000000000..4ad61dc81
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `v` does not live long enough
+ --> $DIR/method-ufcs-inherent-3.rs:14:26
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let v = 22;
+LL | let x = <A<'a>>::new(&v, 22);
+ | -------------^^-----
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `v` is borrowed for `'a`
+LL |
+LL | }
+ | - `v` 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/nll/user-annotations/method-ufcs-inherent-4.rs b/tests/ui/nll/user-annotations/method-ufcs-inherent-4.rs
new file mode 100644
index 000000000..85e759739
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-4.rs
@@ -0,0 +1,20 @@
+// Check that inherent methods invoked with `<T>::new` style
+// carry their annotations through to NLL in connection with
+// method type parameters.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+ fn new<'b, T>(x: &'a u32, y: T) -> Self {
+ Self { x }
+ }
+}
+
+fn foo<'a>() {
+ let v = 22;
+ let x = <A<'a>>::new::<&'a u32>(&v, &v);
+ //~^ ERROR
+ //~| ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
new file mode 100644
index 000000000..0f83e99cd
--- /dev/null
+++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
@@ -0,0 +1,33 @@
+error[E0597]: `v` does not live long enough
+ --> $DIR/method-ufcs-inherent-4.rs:15:37
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let v = 22;
+LL | let x = <A<'a>>::new::<&'a u32>(&v, &v);
+ | ------------------------^^-----
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `v` is borrowed for `'a`
+...
+LL | }
+ | - `v` dropped here while still borrowed
+
+error[E0597]: `v` does not live long enough
+ --> $DIR/method-ufcs-inherent-4.rs:15:41
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let v = 22;
+LL | let x = <A<'a>>::new::<&'a u32>(&v, &v);
+ | ----------------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `v` is borrowed for `'a`
+...
+LL | }
+ | - `v` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/normalization-2.rs b/tests/ui/nll/user-annotations/normalization-2.rs
new file mode 100644
index 000000000..be23c3b74
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-2.rs
@@ -0,0 +1,152 @@
+// Make sure we honor region constraints when normalizing type annotations.
+
+// check-fail
+
+#![feature(more_qualified_paths)]
+
+trait Trait {
+ type Assoc;
+}
+
+impl<T> Trait for T
+where
+ T: 'static,
+{
+ type Assoc = MyTy<()>;
+}
+
+enum MyTy<T> {
+ Unit,
+ Tuple(),
+ Struct {},
+ Dumb(T),
+}
+
+impl<T> MyTy<T> {
+ const CONST: () = ();
+ fn method<X>() {}
+ fn method2<X>(&self) {}
+}
+
+trait TraitAssoc {
+ const TRAIT_CONST: ();
+ fn trait_method<X>(&self);
+}
+impl<T> TraitAssoc for T {
+ const TRAIT_CONST: () = ();
+ fn trait_method<X>(&self) {}
+}
+
+type Ty<'a> = <&'a () as Trait>::Assoc;
+
+fn test_local<'a>() {
+ let _: Ty<'a> = MyTy::Unit;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_closure_sig<'a, 'b>() {
+ |_: Ty<'a>| {};
+ //~^ ERROR lifetime may not live long enough
+ || -> Option<Ty<'b>> { None };
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ <Ty<'a>>::method::<Ty<'static>>;
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'static>>::method::<Ty<'b>>;
+ //~^ ERROR lifetime may not live long enough
+
+ <Ty<'c>>::trait_method::<Ty<'static>>;
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'static>>::trait_method::<Ty<'d>>;
+ //~^ ERROR lifetime may not live long enough
+
+ <Ty<'e>>::CONST;
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'f>>::TRAIT_CONST;
+ //~^ ERROR lifetime may not live long enough
+
+ <Ty<'static>>::method::<Ty<'static>>;
+ <Ty<'static>>::trait_method::<Ty<'static>>;
+ <Ty<'static>>::CONST;
+ <Ty<'static>>::TRAIT_CONST;
+
+ MyTy::Unit::<Ty<'g>>;
+ //~^ ERROR lifetime may not live long enough
+ MyTy::<Ty<'h>>::Unit;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_call<'a, 'b, 'c>() {
+ <Ty<'a>>::method::<Ty<'static>>();
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'static>>::method::<Ty<'b>>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_variants<'a, 'b, 'c>() {
+ <Ty<'a>>::Struct {};
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'b>>::Tuple();
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'c>>::Unit;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_method_call<'a, 'b>(x: MyTy<()>) {
+ x.method2::<Ty<'a>>();
+ //~^ ERROR lifetime may not live long enough
+ x.trait_method::<Ty<'b>>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_struct_path<'a, 'b, 'c, 'd>() {
+ struct Struct<T> { x: Option<T>, }
+
+ trait Project {
+ type Struct;
+ type Enum;
+ }
+ impl<T> Project for T {
+ type Struct = Struct<()>;
+ type Enum = MyTy<()>;
+ }
+
+ // Resolves to enum variant
+ MyTy::<Ty<'a>>::Struct {}; // without SelfTy
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'b> as Project>::Enum::Struct {}; // with SelfTy
+ //~^ ERROR lifetime may not live long enough
+
+ // Resolves to struct and associated type respectively
+ Struct::<Ty<'c>> { x: None, }; // without SelfTy
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'d> as Project>::Struct { x: None, }; // with SelfTy
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ use MyTy::*;
+ match MyTy::Unit {
+ Struct::<Ty<'a>> {..} => {},
+ //~^ ERROR lifetime may not live long enough
+ Tuple::<Ty<'b>> (..) => {},
+ //~^ ERROR lifetime may not live long enough
+ Unit::<Ty<'c>> => {},
+ //~^ ERROR lifetime may not live long enough
+ Dumb(_) => {},
+ };
+ match MyTy::Unit {
+ <Ty<'d>>::Struct {..} => {},
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'e>>::Tuple (..) => {},
+ //~^ ERROR lifetime may not live long enough
+ <Ty<'f>>::Unit => {},
+ //~^ ERROR lifetime may not live long enough
+ Dumb(_) => {},
+ };
+}
+
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/normalization-2.stderr b/tests/ui/nll/user-annotations/normalization-2.stderr
new file mode 100644
index 000000000..5299282ea
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-2.stderr
@@ -0,0 +1,296 @@
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:43:12
+ |
+LL | fn test_local<'a>() {
+ | -- lifetime `'a` defined here
+LL | let _: Ty<'a> = MyTy::Unit;
+ | ^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:48:6
+ |
+LL | fn test_closure_sig<'a, 'b>() {
+ | -- lifetime `'a` defined here
+LL | |_: Ty<'a>| {};
+ | ^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:50:11
+ |
+LL | fn test_closure_sig<'a, 'b>() {
+ | -- lifetime `'b` defined here
+...
+LL | || -> Option<Ty<'b>> { None };
+ | ^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:55:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'a` defined here
+LL | <Ty<'a>>::method::<Ty<'static>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:57:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'static>>::method::<Ty<'b>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:60:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'c` defined here
+...
+LL | <Ty<'c>>::trait_method::<Ty<'static>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:62:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'d` defined here
+...
+LL | <Ty<'static>>::trait_method::<Ty<'d>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:65:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'e` defined here
+...
+LL | <Ty<'e>>::CONST;
+ | ^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:67:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'f` defined here
+...
+LL | <Ty<'f>>::TRAIT_CONST;
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'f` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:75:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'g` defined here
+...
+LL | MyTy::Unit::<Ty<'g>>;
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'g` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:77:5
+ |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+ | -- lifetime `'h` defined here
+...
+LL | MyTy::<Ty<'h>>::Unit;
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'h` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+ = help: replace `'d` with `'static`
+ = help: replace `'e` with `'static`
+ = help: replace `'f` with `'static`
+ = help: replace `'g` with `'static`
+ = help: replace `'h` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:82:5
+ |
+LL | fn test_call<'a, 'b, 'c>() {
+ | -- lifetime `'a` defined here
+LL | <Ty<'a>>::method::<Ty<'static>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:84:5
+ |
+LL | fn test_call<'a, 'b, 'c>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'static>>::method::<Ty<'b>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:89:5
+ |
+LL | fn test_variants<'a, 'b, 'c>() {
+ | -- lifetime `'a` defined here
+LL | <Ty<'a>>::Struct {};
+ | ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:91:5
+ |
+LL | fn test_variants<'a, 'b, 'c>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'b>>::Tuple();
+ | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:93:5
+ |
+LL | fn test_variants<'a, 'b, 'c>() {
+ | -- lifetime `'c` defined here
+...
+LL | <Ty<'c>>::Unit;
+ | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:98:7
+ |
+LL | fn test_method_call<'a, 'b>(x: MyTy<()>) {
+ | -- lifetime `'a` defined here
+LL | x.method2::<Ty<'a>>();
+ | ^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:100:7
+ |
+LL | fn test_method_call<'a, 'b>(x: MyTy<()>) {
+ | -- lifetime `'b` defined here
+...
+LL | x.trait_method::<Ty<'b>>();
+ | ^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:117:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'a` defined here
+...
+LL | MyTy::<Ty<'a>>::Struct {}; // without SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:119:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'b` defined here
+...
+LL | <Ty<'b> as Project>::Enum::Struct {}; // with SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:123:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'c` defined here
+...
+LL | Struct::<Ty<'c>> { x: None, }; // without SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:125:5
+ |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+ | -- lifetime `'d` defined here
+...
+LL | <Ty<'d> as Project>::Struct { x: None, }; // with SelfTy
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+ = help: replace `'d` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:132:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'a` defined here
+...
+LL | Struct::<Ty<'a>> {..} => {},
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:134:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'b` defined here
+...
+LL | Tuple::<Ty<'b>> (..) => {},
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:136:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'c` defined here
+...
+LL | Unit::<Ty<'c>> => {},
+ | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:141:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'d` defined here
+...
+LL | <Ty<'d>>::Struct {..} => {},
+ | ^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:143:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'e` defined here
+...
+LL | <Ty<'e>>::Tuple (..) => {},
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-2.rs:145:9
+ |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+ | -- lifetime `'f` defined here
+...
+LL | <Ty<'f>>::Unit => {},
+ | ^^^^^^^^^^^^^^ requires that `'f` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'a` with `'static`
+ = help: replace `'b` with `'static`
+ = help: replace `'c` with `'static`
+ = help: replace `'d` with `'static`
+ = help: replace `'e` with `'static`
+ = help: replace `'f` with `'static`
+
+error: aborting due to 28 previous errors
+
diff --git a/tests/ui/nll/user-annotations/normalization-default.rs b/tests/ui/nll/user-annotations/normalization-default.rs
new file mode 100644
index 000000000..fa52e6d85
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-default.rs
@@ -0,0 +1,22 @@
+// check-fail
+
+trait Trait { type Assoc; }
+impl<'a> Trait for &'a () { type Assoc = &'a (); }
+
+struct MyTuple<T, U = <&'static () as Trait>::Assoc>(T, U);
+fn test_tuple(x: &(), y: &()) {
+ MyTuple::<_>((), x);
+ //~^ ERROR
+ let _: MyTuple::<_> = MyTuple((), y);
+ //~^ ERROR
+}
+
+struct MyStruct<T, U = <&'static () as Trait>::Assoc> { val: (T, U), }
+fn test_struct(x: &(), y: &()) {
+ MyStruct::<_> { val: ((), x) };
+ //~^ ERROR
+ let _: MyStruct::<_> = MyStruct { val: ((), y) };
+ //~^ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/normalization-default.stderr b/tests/ui/nll/user-annotations/normalization-default.stderr
new file mode 100644
index 000000000..6c73ac692
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-default.stderr
@@ -0,0 +1,36 @@
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:8:22
+ |
+LL | fn test_tuple(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | MyTuple::<_>((), x);
+ | ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:10:12
+ |
+LL | fn test_tuple(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: MyTuple::<_> = MyTuple((), y);
+ | ^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:16:26
+ |
+LL | fn test_struct(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | MyStruct::<_> { val: ((), x) };
+ | ^^^^^^^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-default.rs:18:12
+ |
+LL | fn test_struct(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: MyStruct::<_> = MyStruct { val: ((), y) };
+ | ^^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/nll/user-annotations/normalization-infer.rs b/tests/ui/nll/user-annotations/normalization-infer.rs
new file mode 100644
index 000000000..8bfc272d4
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-infer.rs
@@ -0,0 +1,40 @@
+// Annnotations may contain projection types with inference variables as input.
+// Make sure we don't get ambiguities when normalizing them.
+
+// check-fail
+
+// Single impl.
+fn test1<A, B, C, D>(a: A, b: B, c: C) {
+ trait Tr { type Ty; }
+ impl<T: 'static> Tr for (T,) { type Ty = T; }
+
+ let _: <(_,) as Tr>::Ty = a; //~ ERROR type `A`
+ Some::<<(_,) as Tr>::Ty>(b); //~ ERROR type `B`
+ || -> <(_,) as Tr>::Ty { c }; //~ ERROR type `C`
+ |d: <(_,) as Tr>::Ty| -> D { d }; //~ ERROR type `D`
+}
+
+
+// Two impls. The selected impl depends on the actual type.
+fn test2<A, B, C>(a: A, b: B, c: C) {
+ trait Tr { type Ty; }
+ impl<T: 'static> Tr for (u8, T) { type Ty = T; }
+ impl<T> Tr for (i8, T) { type Ty = T; }
+ type Alias<X, Y> = (<(X, Y) as Tr>::Ty, X);
+
+ fn temp() -> String { todo!() }
+
+ // `u8` impl, requires static.
+ let _: Alias<_, _> = (a, 0u8); //~ ERROR type `A`
+ Some::<Alias<_, _>>((b, 0u8)); //~ ERROR type `B`
+ || -> Alias<_, _> { (c, 0u8) }; //~ ERROR type `C`
+
+ let _: Alias<_, _> = (&temp(), 0u8); //~ ERROR temporary value
+ Some::<Alias<_, _>>((&temp(), 0u8)); //~ ERROR temporary value
+
+ // `i8` impl, no region constraints.
+ let _: Alias<_, _> = (&temp(), 0i8);
+ Some::<Alias<_, _>>((&temp(), 0i8));
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/normalization-infer.stderr b/tests/ui/nll/user-annotations/normalization-infer.stderr
new file mode 100644
index 000000000..12854ab68
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-infer.stderr
@@ -0,0 +1,101 @@
+error[E0310]: the parameter type `A` may not live long enough
+ --> $DIR/normalization-infer.rs:11:12
+ |
+LL | let _: <(_,) as Tr>::Ty = a;
+ | ^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A: 'static, B, C, D>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `B` may not live long enough
+ --> $DIR/normalization-infer.rs:12:5
+ |
+LL | Some::<<(_,) as Tr>::Ty>(b);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A, B: 'static, C, D>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `C` may not live long enough
+ --> $DIR/normalization-infer.rs:13:11
+ |
+LL | || -> <(_,) as Tr>::Ty { c };
+ | ^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A, B, C: 'static, D>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `D` may not live long enough
+ --> $DIR/normalization-infer.rs:14:6
+ |
+LL | |d: <(_,) as Tr>::Ty| -> D { d };
+ | ^ ...so that the type `D` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test1<A, B, C, D: 'static>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `A` may not live long enough
+ --> $DIR/normalization-infer.rs:28:12
+ |
+LL | let _: Alias<_, _> = (a, 0u8);
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test2<A: 'static, B, C>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `B` may not live long enough
+ --> $DIR/normalization-infer.rs:29:5
+ |
+LL | Some::<Alias<_, _>>((b, 0u8));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test2<A, B: 'static, C>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0310]: the parameter type `C` may not live long enough
+ --> $DIR/normalization-infer.rs:30:11
+ |
+LL | || -> Alias<_, _> { (c, 0u8) };
+ | ^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test2<A, B, C: 'static>(a: A, b: B, c: C) {
+ | +++++++++
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/normalization-infer.rs:32:28
+ |
+LL | let _: Alias<_, _> = (&temp(), 0u8);
+ | ----------- ^^^^^^ creates a temporary value which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/normalization-infer.rs:33:27
+ |
+LL | Some::<Alias<_, _>>((&temp(), 0u8));
+ | --^^^^^^------ - temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary value which is freed while still in use
+ | this usage requires that borrow lasts for `'static`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0310, E0716.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/tests/ui/nll/user-annotations/normalization-self.rs b/tests/ui/nll/user-annotations/normalization-self.rs
new file mode 100644
index 000000000..c18760b53
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-self.rs
@@ -0,0 +1,26 @@
+// check-fail
+
+trait Trait { type Assoc; }
+impl<'a> Trait for &'a () { type Assoc = &'a (); }
+
+struct MyTuple<T>(T);
+impl MyTuple<<&'static () as Trait>::Assoc> {
+ fn test(x: &(), y: &()) {
+ Self(x);
+ //~^ ERROR
+ let _: Self = MyTuple(y);
+ //~^ ERROR
+ }
+}
+
+struct MyStruct<T> { val: T, }
+impl MyStruct<<&'static () as Trait>::Assoc> {
+ fn test(x: &(), y: &()) {
+ Self { val: x };
+ //~^ ERROR
+ let _: Self = MyStruct { val: y };
+ //~^ ERROR
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/normalization-self.stderr b/tests/ui/nll/user-annotations/normalization-self.stderr
new file mode 100644
index 000000000..e231ed03c
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization-self.stderr
@@ -0,0 +1,36 @@
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:9:14
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | Self(x);
+ | ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:11:16
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: Self = MyTuple(y);
+ | ^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:19:21
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'1`
+LL | Self { val: x };
+ | ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/normalization-self.rs:21:16
+ |
+LL | fn test(x: &(), y: &()) {
+ | - let's call the lifetime of this reference `'2`
+...
+LL | let _: Self = MyStruct { val: y };
+ | ^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/nll/user-annotations/normalization.rs b/tests/ui/nll/user-annotations/normalization.rs
new file mode 100644
index 000000000..c2e892f57
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization.rs
@@ -0,0 +1,17 @@
+// Test that we enforce a `&'static` requirement that is only visible
+// after normalization.
+
+trait Foo { type Out; }
+impl Foo for () { type Out = &'static u32; }
+impl<'a> Foo for &'a () { type Out = &'a u32; }
+
+fn main() {
+ let a = 22;
+ let _: <() as Foo>::Out = &a; //~ ERROR
+
+ let a = 22;
+ let _: <&'static () as Foo>::Out = &a; //~ ERROR
+
+ let a = 22;
+ let _: <&'_ () as Foo>::Out = &a;
+}
diff --git a/tests/ui/nll/user-annotations/normalization.stderr b/tests/ui/nll/user-annotations/normalization.stderr
new file mode 100644
index 000000000..975cb4b66
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalization.stderr
@@ -0,0 +1,25 @@
+error[E0597]: `a` does not live long enough
+ --> $DIR/normalization.rs:10:31
+ |
+LL | let _: <() as Foo>::Out = &a;
+ | ---------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `a` is borrowed for `'static`
+...
+LL | }
+ | - `a` dropped here while still borrowed
+
+error[E0597]: `a` does not live long enough
+ --> $DIR/normalization.rs:13:40
+ |
+LL | let _: <&'static () as Foo>::Out = &a;
+ | ------------------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `a` is borrowed for `'static`
+...
+LL | }
+ | - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/normalize-self-ty.rs b/tests/ui/nll/user-annotations/normalize-self-ty.rs
new file mode 100644
index 000000000..df905c878
--- /dev/null
+++ b/tests/ui/nll/user-annotations/normalize-self-ty.rs
@@ -0,0 +1,23 @@
+// Regression test for #55183: check a case where the self type from
+// the inherent impl requires normalization to be equal to the
+// user-provided type.
+//
+// check-pass
+
+trait Mirror {
+ type Me;
+}
+
+impl<T> Mirror for T {
+ type Me = T;
+}
+
+struct Foo<A, B>(A, B);
+
+impl<A> Foo<A, <A as Mirror>::Me> {
+ fn m(_: A) { }
+}
+
+fn main() {
+ <Foo<&'static u32, &u32>>::m(&22);
+}
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs b/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
new file mode 100644
index 000000000..59cd69c0c
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
@@ -0,0 +1,22 @@
+enum Foo<'a> {
+ Bar { field: &'a u32 }
+}
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo::Bar { field: &y };
+ //~^ ERROR `y` does not live long enough
+ let Foo::Bar::<'static> { field: _z } = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo::Bar { field: &y };
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::Bar::<'static> { field: _z } => {
+ }
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
new file mode 100644
index 000000000..a97e7a9fd
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
@@ -0,0 +1,26 @@
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_enum_variant.rs:7:33
+ |
+LL | let foo = Foo::Bar { field: &y };
+ | ^^ borrowed value does not live long enough
+LL |
+LL | let Foo::Bar::<'static> { field: _z } = foo;
+ | --------------------------------- type annotation requires that `y` is borrowed for `'static`
+LL | }
+ | - `y` dropped here while still borrowed
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_enum_variant.rs:14:33
+ |
+LL | let foo = Foo::Bar { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | Foo::Bar::<'static> { field: _z } => {
+ | --------------------------------- type annotation requires that `y` is borrowed for `'static`
+...
+LL | }
+ | - `y` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs b/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs
new file mode 100644
index 000000000..1586c4ea3
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs
@@ -0,0 +1,20 @@
+struct Foo<'a> { field: &'a u32 }
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo { field: &y };
+ //~^ ERROR `y` does not live long enough
+ let Foo::<'static> { field: _z } = foo;
+}
+
+fn in_main() {
+ let y = 22;
+ let foo = Foo { field: &y };
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::<'static> { field: _z } => {
+ }
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
new file mode 100644
index 000000000..408d7c2a5
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
@@ -0,0 +1,26 @@
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_struct.rs:5:28
+ |
+LL | let foo = Foo { field: &y };
+ | ^^ borrowed value does not live long enough
+LL |
+LL | let Foo::<'static> { field: _z } = foo;
+ | ---------------------------- type annotation requires that `y` is borrowed for `'static`
+LL | }
+ | - `y` dropped here while still borrowed
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_struct.rs:12:28
+ |
+LL | let foo = Foo { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | Foo::<'static> { field: _z } => {
+ | ---------------------------- type annotation requires that `y` is borrowed for `'static`
+...
+LL | }
+ | - `y` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs
new file mode 100644
index 000000000..6fa59fdd8
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs
@@ -0,0 +1,22 @@
+enum Foo<'a> {
+ Bar(&'a u32)
+}
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo::Bar(&y);
+ //~^ ERROR `y` does not live long enough
+ let Foo::Bar::<'static>(_z) = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo::Bar(&y);
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::Bar::<'static>(_z) => {
+ }
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
new file mode 100644
index 000000000..920c906f6
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
@@ -0,0 +1,26 @@
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_enum_variant.rs:7:24
+ |
+LL | let foo = Foo::Bar(&y);
+ | ^^ borrowed value does not live long enough
+LL |
+LL | let Foo::Bar::<'static>(_z) = foo;
+ | ----------------------- type annotation requires that `y` is borrowed for `'static`
+LL | }
+ | - `y` dropped here while still borrowed
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_enum_variant.rs:14:24
+ |
+LL | let foo = Foo::Bar(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | Foo::Bar::<'static>(_z) => {
+ | ----------------------- type annotation requires that `y` is borrowed for `'static`
+...
+LL | }
+ | - `y` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs
new file mode 100644
index 000000000..7486aab0e
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs
@@ -0,0 +1,20 @@
+struct Foo<'a>(&'a u32);
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo(&y);
+ //~^ ERROR `y` does not live long enough
+ let Foo::<'static>(_z) = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo(&y);
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::<'static>(_z) => {
+ }
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
new file mode 100644
index 000000000..3f01638d8
--- /dev/null
+++ b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
@@ -0,0 +1,26 @@
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_struct.rs:5:19
+ |
+LL | let foo = Foo(&y);
+ | ^^ borrowed value does not live long enough
+LL |
+LL | let Foo::<'static>(_z) = foo;
+ | ------------------ type annotation requires that `y` is borrowed for `'static`
+LL | }
+ | - `y` dropped here while still borrowed
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_struct.rs:12:19
+ |
+LL | let foo = Foo(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | Foo::<'static>(_z) => {
+ | ------------------ type annotation requires that `y` is borrowed for `'static`
+...
+LL | }
+ | - `y` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/patterns.rs b/tests/ui/nll/user-annotations/patterns.rs
new file mode 100644
index 000000000..1f635d7f5
--- /dev/null
+++ b/tests/ui/nll/user-annotations/patterns.rs
@@ -0,0 +1,136 @@
+// Test that various patterns also enforce types.
+
+fn variable_no_initializer() {
+ let x = 22;
+ let y: &'static u32;
+ y = &x; //~ ERROR
+}
+
+fn tuple_no_initializer() {
+
+
+ let x = 22;
+ let (y, z): (&'static u32, &'static u32);
+ y = &x; //~ ERROR
+}
+
+fn ref_with_ascribed_static_type() -> u32 {
+ // Check the behavior in some wacky cases.
+ let x = 22;
+ let y = &x; //~ ERROR
+ let ref z: &'static u32 = y;
+ **z
+}
+
+fn ref_with_ascribed_any_type() -> u32 {
+ let x = 22;
+ let y = &x;
+ let ref z: &u32 = y;
+ **z
+}
+
+struct Single<T> { value: T }
+
+fn struct_no_initializer() {
+
+
+ let x = 22;
+ let Single { value: y }: Single<&'static u32>;
+ y = &x; //~ ERROR
+}
+
+
+fn struct_no_initializer_must_normalize() {
+ trait Indirect { type Assoc; }
+ struct StaticU32;
+ impl Indirect for StaticU32 { type Assoc = &'static u32; }
+ struct Single2<T: Indirect> { value: <T as Indirect>::Assoc }
+
+ let x = 22;
+ let Single2 { value: mut _y }: Single2<StaticU32>;
+ _y = &x; //~ ERROR
+}
+
+fn variable_with_initializer() {
+ let x = 22;
+ let y: &'static u32 = &x; //~ ERROR
+}
+
+fn underscore_with_initializer() {
+ let x = 22;
+ let _: &'static u32 = &x; //~ ERROR
+
+ let _: Vec<&'static String> = vec![&String::new()];
+ //~^ ERROR temporary value dropped while borrowed [E0716]
+
+ let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+ //~^ ERROR temporary value dropped while borrowed [E0716]
+
+ let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+ //~^ ERROR temporary value dropped while borrowed [E0716]
+}
+
+fn pair_underscores_with_initializer() {
+ let x = 22;
+ let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR
+}
+
+fn pair_variable_with_initializer() {
+ let x = 22;
+ let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR
+}
+
+fn struct_single_field_variable_with_initializer() {
+ let x = 22;
+ let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR
+}
+
+fn struct_single_field_underscore_with_initializer() {
+ let x = 22;
+ let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR
+}
+
+struct Double<T> { value1: T, value2: T }
+
+fn struct_double_field_underscore_with_initializer() {
+ let x = 22;
+ let Double { value1: _, value2: _ }: Double<&'static u32> = Double {
+ value1: &x, //~ ERROR
+ value2: &44,
+ };
+}
+
+fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
+
+
+
+
+
+
+ let y: &'a u32 = &22;
+ y //~ ERROR
+}
+
+fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
+
+
+
+
+
+
+
+ let (y, _z): (&'a u32, u32) = (&22, 44);
+ y //~ ERROR
+}
+
+fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 {
+ let Single { value: y }: Single<&'a u32> = Single { value: &22 };
+ y //~ ERROR
+}
+
+fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
+ let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR
+ y
+}
+
+fn main() { }
diff --git a/tests/ui/nll/user-annotations/patterns.stderr b/tests/ui/nll/user-annotations/patterns.stderr
new file mode 100644
index 000000000..de6f8f80f
--- /dev/null
+++ b/tests/ui/nll/user-annotations/patterns.stderr
@@ -0,0 +1,189 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:6:9
+ |
+LL | let y: &'static u32;
+ | ------------ type annotation requires that `x` is borrowed for `'static`
+LL | y = &x;
+ | ^^ borrowed value does not live long enough
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:14:9
+ |
+LL | let (y, z): (&'static u32, &'static u32);
+ | ---------------------------- type annotation requires that `x` is borrowed for `'static`
+LL | y = &x;
+ | ^^ borrowed value does not live long enough
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:20:13
+ |
+LL | let y = &x;
+ | ^^ borrowed value does not live long enough
+LL | let ref z: &'static u32 = y;
+ | ------------ type annotation requires that `x` is borrowed for `'static`
+LL | **z
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:39:9
+ |
+LL | let Single { value: y }: Single<&'static u32>;
+ | -------------------- type annotation requires that `x` is borrowed for `'static`
+LL | y = &x;
+ | ^^ borrowed value does not live long enough
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:51:10
+ |
+LL | let Single2 { value: mut _y }: Single2<StaticU32>;
+ | ------------------ type annotation requires that `x` is borrowed for `'static`
+LL | _y = &x;
+ | ^^ borrowed value does not live long enough
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:56:27
+ |
+LL | let y: &'static u32 = &x;
+ | ------------ ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:61:27
+ |
+LL | let _: &'static u32 = &x;
+ | ------------ ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `x` is borrowed for `'static`
+...
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/patterns.rs:63:41
+ |
+LL | let _: Vec<&'static String> = vec![&String::new()];
+ | -------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary value which is freed while still in use
+ | type annotation requires that borrow lasts for `'static`
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/patterns.rs:66:52
+ |
+LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+ | ------------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary value which is freed while still in use
+ | type annotation requires that borrow lasts for `'static`
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/patterns.rs:69:53
+ |
+LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
+ | ------------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary value which is freed while still in use
+ | type annotation requires that borrow lasts for `'static`
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:75:40
+ |
+LL | let (_, _): (&'static u32, u32) = (&x, 44);
+ | ------------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:80:40
+ |
+LL | let (y, _): (&'static u32, u32) = (&x, 44);
+ | ------------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:85:69
+ |
+LL | let Single { value: y }: Single<&'static u32> = Single { value: &x };
+ | -------------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:90:69
+ |
+LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x };
+ | -------------------- ^^ borrowed value does not live long enough
+ | |
+ | type annotation requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/patterns.rs:98:17
+ |
+LL | let Double { value1: _, value2: _ }: Double<&'static u32> = Double {
+ | -------------------- type annotation requires that `x` is borrowed for `'static`
+LL | value1: &x,
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `x` dropped here while still borrowed
+
+error: lifetime may not live long enough
+ --> $DIR/patterns.rs:111:5
+ |
+LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+...
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/patterns.rs:123:5
+ |
+LL | fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+...
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/patterns.rs:128:5
+ |
+LL | fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | let Single { value: y }: Single<&'a u32> = Single { value: &22 };
+LL | y
+ | ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/patterns.rs:132:18
+ |
+LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | let (y, _z): (&'static u32, u32) = (x, 44);
+ | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to 19 previous errors
+
+Some errors have detailed explanations: E0597, E0716.
+For more information about an error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/user-annotations/promoted-annotation.rs b/tests/ui/nll/user-annotations/promoted-annotation.rs
new file mode 100644
index 000000000..b92f8bfd2
--- /dev/null
+++ b/tests/ui/nll/user-annotations/promoted-annotation.rs
@@ -0,0 +1,10 @@
+// Test that type annotations are checked in promoted constants correctly.
+
+fn foo<'a>() {
+ let x = 0;
+ let f = &drop::<&'a i32>;
+ f(&x);
+ //~^ ERROR `x` does not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/promoted-annotation.stderr b/tests/ui/nll/user-annotations/promoted-annotation.stderr
new file mode 100644
index 000000000..cb99a6a36
--- /dev/null
+++ b/tests/ui/nll/user-annotations/promoted-annotation.stderr
@@ -0,0 +1,17 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/promoted-annotation.rs:6:7
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let x = 0;
+LL | let f = &drop::<&'a i32>;
+ | ---------------- assignment requires that `x` is borrowed for `'a`
+LL | f(&x);
+ | ^^ borrowed value does not live long enough
+LL |
+LL | }
+ | - `x` 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/nll/user-annotations/type-annotation-with-hrtb.rs b/tests/ui/nll/user-annotations/type-annotation-with-hrtb.rs
new file mode 100644
index 000000000..1f7c06038
--- /dev/null
+++ b/tests/ui/nll/user-annotations/type-annotation-with-hrtb.rs
@@ -0,0 +1,33 @@
+// Regression test for issue #69490
+
+// check-pass
+
+pub trait Trait<T> {
+ const S: &'static str;
+}
+
+impl<T> Trait<()> for T
+where
+ T: for<'a> Trait<&'a ()>,
+{
+ // Use of `T::S` here caused an ICE
+ const S: &'static str = T::S;
+}
+
+// Some similar cases that didn't ICE:
+
+impl<'a, T> Trait<()> for (T,)
+where
+ T: Trait<&'a ()>,
+{
+ const S: &'static str = T::S;
+}
+
+impl<T> Trait<()> for [T; 1]
+where
+ T: Trait<for<'a> fn(&'a ())>,
+{
+ const S: &'static str = T::S;
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.rs b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.rs
new file mode 100644
index 000000000..88d646dee
--- /dev/null
+++ b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.rs
@@ -0,0 +1,7 @@
+#![allow(warnings)]
+#![feature(type_ascription)]
+
+fn main() {
+ let x = 22_u32;
+ let y: &u32 = type_ascribe!(&x, &'static u32); //~ ERROR E0597
+}
diff --git a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
new file mode 100644
index 000000000..ccbf3c1d9
--- /dev/null
+++ b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `x` does not live long enough
+ --> $DIR/type_ascription_static_lifetime.rs:6:33
+ |
+LL | let y: &u32 = type_ascribe!(&x, &'static u32);
+ | --------------^^---------------
+ | | |
+ | | borrowed value does not live long enough
+ | type annotation requires that `x` is borrowed for `'static`
+LL | }
+ | - `x` 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/nll/user-annotations/wf-self-type.rs b/tests/ui/nll/user-annotations/wf-self-type.rs
new file mode 100644
index 000000000..539226aab
--- /dev/null
+++ b/tests/ui/nll/user-annotations/wf-self-type.rs
@@ -0,0 +1,13 @@
+struct Foo<'a, 'b: 'a>(&'a &'b ());
+
+impl<'a, 'b> Foo<'a, 'b> {
+ fn xmute(a: &'b ()) -> &'a () {
+ unreachable!()
+ }
+}
+
+pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
+ Foo::xmute(u) //~ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/wf-self-type.stderr b/tests/ui/nll/user-annotations/wf-self-type.stderr
new file mode 100644
index 000000000..1d3ae7cfb
--- /dev/null
+++ b/tests/ui/nll/user-annotations/wf-self-type.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/wf-self-type.rs:10:5
+ |
+LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | Foo::xmute(u)
+ | ^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/vimwiki-core-regression.rs b/tests/ui/nll/vimwiki-core-regression.rs
new file mode 100644
index 000000000..0a4ed7e0a
--- /dev/null
+++ b/tests/ui/nll/vimwiki-core-regression.rs
@@ -0,0 +1,37 @@
+// check-pass
+//
+// Regression test from crater run for
+// <https://github.com/rust-lang/rust/pull/98109>.
+
+
+pub trait ElementLike {}
+
+pub struct Located<T> where T: ElementLike {
+ inner: T,
+}
+
+pub struct BlockElement<'a>(&'a str);
+
+impl ElementLike for BlockElement<'_> {}
+
+
+pub struct Page<'a> {
+ /// Comprised of the elements within a page
+ pub elements: Vec<Located<BlockElement<'a>>>,
+}
+
+impl<'a, __IdxT> std::ops::Index<__IdxT> for Page<'a> where
+ Vec<Located<BlockElement<'a>>>: std::ops::Index<__IdxT>
+{
+ type Output =
+ <Vec<Located<BlockElement<'a>>> as
+ std::ops::Index<__IdxT>>::Output;
+
+ #[inline]
+ fn index(&self, idx: __IdxT) -> &Self::Output {
+ <Vec<Located<BlockElement<'a>>> as
+ std::ops::Index<__IdxT>>::index(&self.elements, idx)
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/nll/where_clauses_in_functions.rs b/tests/ui/nll/where_clauses_in_functions.rs
new file mode 100644
index 000000000..826065d02
--- /dev/null
+++ b/tests/ui/nll/where_clauses_in_functions.rs
@@ -0,0 +1,15 @@
+#![allow(dead_code)]
+
+fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32)
+where
+ 'a: 'b,
+{
+ (x, y)
+}
+
+fn bar<'a, 'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
+ foo(x, y)
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/where_clauses_in_functions.stderr b/tests/ui/nll/where_clauses_in_functions.stderr
new file mode 100644
index 000000000..afb25e3bc
--- /dev/null
+++ b/tests/ui/nll/where_clauses_in_functions.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/where_clauses_in_functions.rs:11:5
+ |
+LL | fn bar<'a, 'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | foo(x, y)
+ | ^^^^^^^^^ 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/nll/where_clauses_in_structs.rs b/tests/ui/nll/where_clauses_in_structs.rs
new file mode 100644
index 000000000..fae5d3811
--- /dev/null
+++ b/tests/ui/nll/where_clauses_in_structs.rs
@@ -0,0 +1,15 @@
+#![allow(dead_code)]
+
+use std::cell::Cell;
+
+struct Foo<'a: 'b, 'b> {
+ x: Cell<&'a u32>,
+ y: Cell<&'b u32>,
+}
+
+fn bar<'a, 'b>(x: Cell<&'a u32>, y: Cell<&'b u32>) {
+ Foo { x, y };
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/where_clauses_in_structs.stderr b/tests/ui/nll/where_clauses_in_structs.stderr
new file mode 100644
index 000000000..c46cfcb41
--- /dev/null
+++ b/tests/ui/nll/where_clauses_in_structs.stderr
@@ -0,0 +1,17 @@
+error: lifetime may not live long enough
+ --> $DIR/where_clauses_in_structs.rs:11:11
+ |
+LL | fn bar<'a, 'b>(x: Cell<&'a u32>, y: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | Foo { x, y };
+ | ^ this usage requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of the type `Cell<&u32>`, which makes the generic argument `&u32` invariant
+ = note: the struct `Cell<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+