summaryrefslogtreecommitdiffstats
path: root/tests/ui/pattern
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/pattern')
-rw-r--r--tests/ui/pattern/auxiliary/declarations-for-tuple-field-count-errors.rs20
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-copy.rs47
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs37
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr79
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs11
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr13
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs31
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr112
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs84
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs69
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr145
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs49
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs7
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr17
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs80
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr487
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs82
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr375
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs45
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs136
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr445
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs109
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr359
-rw-r--r--tests/ui/pattern/bindings-after-at/box-patterns.rs35
-rw-r--r--tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs14
-rw-r--r--tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr17
-rw-r--r--tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs48
-rw-r--r--tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr68
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs12
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs11
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr25
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs11
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr15
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-patterns.rs14
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs33
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr26
-rw-r--r--tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs43
-rw-r--r--tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs54
-rw-r--r--tests/ui/pattern/bindings-after-at/or-patterns.rs38
-rw-r--r--tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs29
-rw-r--r--tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr64
-rw-r--r--tests/ui/pattern/bindings-after-at/slice-patterns.rs39
-rw-r--r--tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs16
-rw-r--r--tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr43
-rw-r--r--tests/ui/pattern/for-loop-bad-item.rs20
-rw-r--r--tests/ui/pattern/for-loop-bad-item.stderr32
-rw-r--r--tests/ui/pattern/ignore-all-the-things.rs44
-rw-r--r--tests/ui/pattern/integer-range-binding.rs8
-rw-r--r--tests/ui/pattern/issue-10392.rs30
-rw-r--r--tests/ui/pattern/issue-106552.rs7
-rw-r--r--tests/ui/pattern/issue-106552.stderr35
-rw-r--r--tests/ui/pattern/issue-11577.rs18
-rw-r--r--tests/ui/pattern/issue-12582.rs21
-rw-r--r--tests/ui/pattern/issue-14221.rs21
-rw-r--r--tests/ui/pattern/issue-14221.stderr32
-rw-r--r--tests/ui/pattern/issue-15080.rs22
-rw-r--r--tests/ui/pattern/issue-17718-patterns.rs12
-rw-r--r--tests/ui/pattern/issue-17718-patterns.stderr21
-rw-r--r--tests/ui/pattern/issue-22546.rs52
-rw-r--r--tests/ui/pattern/issue-27320.rs15
-rw-r--r--tests/ui/pattern/issue-52240.rs16
-rw-r--r--tests/ui/pattern/issue-52240.stderr9
-rw-r--r--tests/ui/pattern/issue-6449.rs44
-rw-r--r--tests/ui/pattern/issue-66270-pat-struct-parser-recovery.rs14
-rw-r--r--tests/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr10
-rw-r--r--tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs21
-rw-r--r--tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr33
-rw-r--r--tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs40
-rw-r--r--tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr41
-rw-r--r--tests/ui/pattern/issue-68393-let-pat-assoc-constant.rs26
-rw-r--r--tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr15
-rw-r--r--tests/ui/pattern/issue-72565.rs8
-rw-r--r--tests/ui/pattern/issue-72565.stderr8
-rw-r--r--tests/ui/pattern/issue-72574-1.rs10
-rw-r--r--tests/ui/pattern/issue-72574-1.stderr34
-rw-r--r--tests/ui/pattern/issue-72574-2.rs12
-rw-r--r--tests/ui/pattern/issue-72574-2.stderr37
-rw-r--r--tests/ui/pattern/issue-74539.rs15
-rw-r--r--tests/ui/pattern/issue-74539.stderr37
-rw-r--r--tests/ui/pattern/issue-74702.rs7
-rw-r--r--tests/ui/pattern/issue-74702.stderr34
-rw-r--r--tests/ui/pattern/issue-74954.rs7
-rw-r--r--tests/ui/pattern/issue-80186-mut-binding-help-suggestion.rs9
-rw-r--r--tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr10
-rw-r--r--tests/ui/pattern/issue-8351-1.rs16
-rw-r--r--tests/ui/pattern/issue-8351-2.rs16
-rw-r--r--tests/ui/pattern/issue-88074-pat-range-type-inference-err.rs28
-rw-r--r--tests/ui/pattern/issue-88074-pat-range-type-inference-err.stderr19
-rw-r--r--tests/ui/pattern/issue-88074-pat-range-type-inference.rs16
-rw-r--r--tests/ui/pattern/issue-92074-macro-ice.rs36
-rw-r--r--tests/ui/pattern/issue-92074-macro-ice.stderr35
-rw-r--r--tests/ui/pattern/issue-95878.rs12
-rw-r--r--tests/ui/pattern/issue-95878.stderr8
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs29
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs48
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr216
-rw-r--r--tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs12
-rw-r--r--tests/ui/pattern/move-ref-patterns/issue-53840.rs20
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs120
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr404
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs28
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs32
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr63
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed12
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs12
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr17
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs10
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr17
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs79
-rw-r--r--tests/ui/pattern/non-constant-in-const-path.rs18
-rw-r--r--tests/ui/pattern/non-constant-in-const-path.stderr28
-rw-r--r--tests/ui/pattern/non-structural-match-types.rs14
-rw-r--r--tests/ui/pattern/non-structural-match-types.stderr14
-rw-r--r--tests/ui/pattern/pat-shadow-in-nested-binding.rs6
-rw-r--r--tests/ui/pattern/pat-shadow-in-nested-binding.stderr12
-rw-r--r--tests/ui/pattern/pat-struct-field-expr-has-type.rs9
-rw-r--r--tests/ui/pattern/pat-struct-field-expr-has-type.stderr14
-rw-r--r--tests/ui/pattern/pat-tuple-bad-type.rs15
-rw-r--r--tests/ui/pattern/pat-tuple-bad-type.stderr26
-rw-r--r--tests/ui/pattern/pat-tuple-field-count-cross.rs57
-rw-r--r--tests/ui/pattern/pat-tuple-field-count-cross.stderr531
-rw-r--r--tests/ui/pattern/pat-tuple-overfield.rs74
-rw-r--r--tests/ui/pattern/pat-tuple-overfield.stderr312
-rw-r--r--tests/ui/pattern/pat-tuple-underfield.rs67
-rw-r--r--tests/ui/pattern/pat-tuple-underfield.stderr167
-rw-r--r--tests/ui/pattern/pat-type-err-formal-param.rs8
-rw-r--r--tests/ui/pattern/pat-type-err-formal-param.stderr11
-rw-r--r--tests/ui/pattern/pat-type-err-let-stmt.rs16
-rw-r--r--tests/ui/pattern/pat-type-err-let-stmt.stderr51
-rw-r--r--tests/ui/pattern/patkind-litrange-no-expr.rs24
-rw-r--r--tests/ui/pattern/patkind-litrange-no-expr.stderr14
-rw-r--r--tests/ui/pattern/pattern-binding-disambiguation.rs57
-rw-r--r--tests/ui/pattern/pattern-binding-disambiguation.stderr63
-rw-r--r--tests/ui/pattern/pattern-error-continue.rs35
-rw-r--r--tests/ui/pattern/pattern-error-continue.stderr62
-rw-r--r--tests/ui/pattern/pattern-ident-path-generics.rs6
-rw-r--r--tests/ui/pattern/pattern-ident-path-generics.stderr14
-rw-r--r--tests/ui/pattern/pattern-tyvar-2.rs6
-rw-r--r--tests/ui/pattern/pattern-tyvar-2.stderr11
-rw-r--r--tests/ui/pattern/pattern-tyvar.rs12
-rw-r--r--tests/ui/pattern/pattern-tyvar.stderr14
-rw-r--r--tests/ui/pattern/rest-pat-semantic-disallowed.rs83
-rw-r--r--tests/ui/pattern/rest-pat-semantic-disallowed.stderr201
-rw-r--r--tests/ui/pattern/rest-pat-syntactic.rs73
-rw-r--r--tests/ui/pattern/rest-pat-syntactic.stderr24
-rw-r--r--tests/ui/pattern/size-and-align.rs20
-rw-r--r--tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed10
-rw-r--r--tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs9
-rw-r--r--tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr21
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.rs32
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.stderr37
-rw-r--r--tests/ui/pattern/usefulness/auxiliary/empty.rs10
-rw-r--r--tests/ui/pattern/usefulness/auxiliary/hidden.rs14
-rw-r--r--tests/ui/pattern/usefulness/auxiliary/unstable.rs23
-rw-r--r--tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs18
-rw-r--r--tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr8
-rw-r--r--tests/ui/pattern/usefulness/const-pat-ice.rs11
-rw-r--r--tests/ui/pattern/usefulness/const-private-fields.rs30
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.rs145
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.stderr202
-rw-r--r--tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs16
-rw-r--r--tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr34
-rw-r--r--tests/ui/pattern/usefulness/doc-hidden-fields.rs26
-rw-r--r--tests/ui/pattern/usefulness/doc-hidden-fields.stderr59
-rw-r--r--tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs43
-rw-r--r--tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr102
-rw-r--r--tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr303
-rw-r--r--tests/ui/pattern/usefulness/empty-match.normal.stderr303
-rw-r--r--tests/ui/pattern/usefulness/empty-match.rs95
-rw-r--r--tests/ui/pattern/usefulness/floats.rs19
-rw-r--r--tests/ui/pattern/usefulness/floats.stderr28
-rw-r--r--tests/ui/pattern/usefulness/guards.rs22
-rw-r--r--tests/ui/pattern/usefulness/guards.stderr16
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs101
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr149
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs59
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr89
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr17
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr170
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs50
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs18
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr33
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/reachability.rs113
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/reachability.stderr154
-rw-r--r--tests/ui/pattern/usefulness/irrefutable-let-patterns.rs11
-rw-r--r--tests/ui/pattern/usefulness/irrefutable-unit.rs6
-rw-r--r--tests/ui/pattern/usefulness/issue-12116.rs21
-rw-r--r--tests/ui/pattern/usefulness/issue-12116.stderr14
-rw-r--r--tests/ui/pattern/usefulness/issue-12369.rs11
-rw-r--r--tests/ui/pattern/usefulness/issue-12369.stderr14
-rw-r--r--tests/ui/pattern/usefulness/issue-13727.rs15
-rw-r--r--tests/ui/pattern/usefulness/issue-13727.stderr14
-rw-r--r--tests/ui/pattern/usefulness/issue-15129.rs17
-rw-r--r--tests/ui/pattern/usefulness/issue-15129.stderr16
-rw-r--r--tests/ui/pattern/usefulness/issue-2111.rs11
-rw-r--r--tests/ui/pattern/usefulness/issue-2111.stderr16
-rw-r--r--tests/ui/pattern/usefulness/issue-30240-b.rs15
-rw-r--r--tests/ui/pattern/usefulness/issue-30240-b.stderr14
-rw-r--r--tests/ui/pattern/usefulness/issue-30240-rpass.rs14
-rw-r--r--tests/ui/pattern/usefulness/issue-30240.rs10
-rw-r--r--tests/ui/pattern/usefulness/issue-30240.stderr29
-rw-r--r--tests/ui/pattern/usefulness/issue-3096-1.rs3
-rw-r--r--tests/ui/pattern/usefulness/issue-3096-1.stderr17
-rw-r--r--tests/ui/pattern/usefulness/issue-3096-2.rs6
-rw-r--r--tests/ui/pattern/usefulness/issue-3096-2.stderr17
-rw-r--r--tests/ui/pattern/usefulness/issue-31221.rs34
-rw-r--r--tests/ui/pattern/usefulness/issue-31221.stderr32
-rw-r--r--tests/ui/pattern/usefulness/issue-31561.rs11
-rw-r--r--tests/ui/pattern/usefulness/issue-31561.stderr27
-rw-r--r--tests/ui/pattern/usefulness/issue-35609.rs43
-rw-r--r--tests/ui/pattern/usefulness/issue-35609.stderr119
-rw-r--r--tests/ui/pattern/usefulness/issue-3601.rs34
-rw-r--r--tests/ui/pattern/usefulness/issue-3601.stderr18
-rw-r--r--tests/ui/pattern/usefulness/issue-39362.rs18
-rw-r--r--tests/ui/pattern/usefulness/issue-39362.stderr23
-rw-r--r--tests/ui/pattern/usefulness/issue-40221.rs16
-rw-r--r--tests/ui/pattern/usefulness/issue-40221.stderr23
-rw-r--r--tests/ui/pattern/usefulness/issue-4321.rs8
-rw-r--r--tests/ui/pattern/usefulness/issue-4321.stderr16
-rw-r--r--tests/ui/pattern/usefulness/issue-50900.rs19
-rw-r--r--tests/ui/pattern/usefulness/issue-50900.stderr21
-rw-r--r--tests/ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs11
-rw-r--r--tests/ui/pattern/usefulness/issue-56379.rs14
-rw-r--r--tests/ui/pattern/usefulness/issue-56379.stderr27
-rw-r--r--tests/ui/pattern/usefulness/issue-57472.rs35
-rw-r--r--tests/ui/pattern/usefulness/issue-57472.stderr20
-rw-r--r--tests/ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs15
-rw-r--r--tests/ui/pattern/usefulness/issue-66501.rs12
-rw-r--r--tests/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs22
-rw-r--r--tests/ui/pattern/usefulness/issue-72377.rs17
-rw-r--r--tests/ui/pattern/usefulness/issue-72377.stderr16
-rw-r--r--tests/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs56
-rw-r--r--tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs12
-rw-r--r--tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr23
-rw-r--r--tests/ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs25
-rw-r--r--tests/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs27
-rw-r--r--tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs6
-rw-r--r--tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr9
-rw-r--r--tests/ui/pattern/usefulness/issue-88747.rs14
-rw-r--r--tests/ui/pattern/usefulness/match-arm-statics-2.rs62
-rw-r--r--tests/ui/pattern/usefulness/match-arm-statics-2.stderr54
-rw-r--r--tests/ui/pattern/usefulness/match-arm-statics.rs69
-rw-r--r--tests/ui/pattern/usefulness/match-arm-statics.stderr26
-rw-r--r--tests/ui/pattern/usefulness/match-byte-array-patterns-2.rs13
-rw-r--r--tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr29
-rw-r--r--tests/ui/pattern/usefulness/match-byte-array-patterns.rs55
-rw-r--r--tests/ui/pattern/usefulness/match-byte-array-patterns.stderr56
-rw-r--r--tests/ui/pattern/usefulness/match-non-exhaustive.rs4
-rw-r--r--tests/ui/pattern/usefulness/match-non-exhaustive.stderr27
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.rs21
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.stderr21
-rw-r--r--tests/ui/pattern/usefulness/match-ref-ice.rs16
-rw-r--r--tests/ui/pattern/usefulness/match-ref-ice.stderr14
-rw-r--r--tests/ui/pattern/usefulness/match-slice-patterns.rs12
-rw-r--r--tests/ui/pattern/usefulness/match-slice-patterns.stderr16
-rw-r--r--tests/ui/pattern/usefulness/match-vec-fixed.rs18
-rw-r--r--tests/ui/pattern/usefulness/match-vec-fixed.stderr20
-rw-r--r--tests/ui/pattern/usefulness/match-vec-unreachable.rs29
-rw-r--r--tests/ui/pattern/usefulness/match-vec-unreachable.stderr26
-rw-r--r--tests/ui/pattern/usefulness/nested-exhaustive-match.rs14
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs107
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr194
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-match-nested.rs19
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr34
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-match.rs63
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-match.stderr121
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs89
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr129
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-errors.rs9
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-errors.stderr25
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs6
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr11
-rw-r--r--tests/ui/pattern/usefulness/slice-pattern-const-2.rs31
-rw-r--r--tests/ui/pattern/usefulness/slice-pattern-const-2.stderr32
-rw-r--r--tests/ui/pattern/usefulness/slice-pattern-const-3.rs31
-rw-r--r--tests/ui/pattern/usefulness/slice-pattern-const-3.stderr32
-rw-r--r--tests/ui/pattern/usefulness/slice-pattern-const.rs54
-rw-r--r--tests/ui/pattern/usefulness/slice-pattern-const.stderr62
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs129
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr263
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-irrefutable.rs26
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-reachability.rs25
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-reachability.stderr44
-rw-r--r--tests/ui/pattern/usefulness/stable-gated-fields.rs16
-rw-r--r--tests/ui/pattern/usefulness/stable-gated-fields.stderr29
-rw-r--r--tests/ui/pattern/usefulness/stable-gated-patterns.rs18
-rw-r--r--tests/ui/pattern/usefulness/stable-gated-patterns.stderr42
-rw-r--r--tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.rs12
-rw-r--r--tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr23
-rw-r--r--tests/ui/pattern/usefulness/struct-pattern-match-useless.rs15
-rw-r--r--tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr16
-rw-r--r--tests/ui/pattern/usefulness/top-level-alternation.rs57
-rw-r--r--tests/ui/pattern/usefulness/top-level-alternation.stderr74
-rw-r--r--tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.rs9
-rw-r--r--tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr21
-rw-r--r--tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs36
-rw-r--r--tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr29
-rw-r--r--tests/ui/pattern/usefulness/uninhabited.rs143
-rw-r--r--tests/ui/pattern/usefulness/unstable-gated-fields.rs18
-rw-r--r--tests/ui/pattern/usefulness/unstable-gated-fields.stderr33
-rw-r--r--tests/ui/pattern/usefulness/unstable-gated-patterns.rs22
-rw-r--r--tests/ui/pattern/usefulness/unstable-gated-patterns.stderr24
302 files changed, 14333 insertions, 0 deletions
diff --git a/tests/ui/pattern/auxiliary/declarations-for-tuple-field-count-errors.rs b/tests/ui/pattern/auxiliary/declarations-for-tuple-field-count-errors.rs
new file mode 100644
index 000000000..f7373c453
--- /dev/null
+++ b/tests/ui/pattern/auxiliary/declarations-for-tuple-field-count-errors.rs
@@ -0,0 +1,20 @@
+pub struct Z0;
+pub struct Z1();
+
+pub struct S(pub u8, pub u8, pub u8);
+pub struct M(
+ pub u8,
+ pub u8,
+ pub u8,
+);
+
+pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+
+pub enum E2 {
+ S(u8, u8, u8),
+ M(
+ u8,
+ u8,
+ u8,
+ ),
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs
new file mode 100644
index 000000000..2b349f0ed
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs
@@ -0,0 +1,47 @@
+// run-pass
+
+// Test copy
+
+struct A { a: i32, b: i32 }
+struct B { a: i32, b: C }
+struct D { a: i32, d: C }
+#[derive(Copy,Clone)]
+struct C { c: i32 }
+
+pub fn main() {
+ match (A {a: 10, b: 20}) {
+ x@A {a, b: 20} => { assert!(x.a == 10); assert!(a == 10); }
+ A {b: _b, ..} => { panic!(); }
+ }
+
+ let mut x@B {b, ..} = B {a: 10, b: C {c: 20}};
+ assert_eq!(x.a, 10);
+ x.b.c = 30;
+ assert_eq!(b.c, 20);
+ let mut y@D {d, ..} = D {a: 10, d: C {c: 20}};
+ assert_eq!(y.a, 10);
+ y.d.c = 30;
+ assert_eq!(d.c, 20);
+
+ let some_b = Some(B { a: 10, b: C { c: 20 } });
+
+ // in irrefutable pattern
+ if let Some(x @ B { b, .. }) = some_b {
+ assert_eq!(x.b.c, 20);
+ assert_eq!(b.c, 20);
+ } else {
+ unreachable!();
+ }
+
+ let some_b = Some(B { a: 10, b: C { c: 20 } });
+
+ if let Some(x @ B { b: mut b @ C { c }, .. }) = some_b {
+ assert_eq!(x.b.c, 20);
+ assert_eq!(b.c, 20);
+ b.c = 30;
+ assert_eq!(b.c, 30);
+ assert_eq!(c, 20);
+ } else {
+ unreachable!();
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
new file mode 100644
index 000000000..9d1f08d6e
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
@@ -0,0 +1,37 @@
+// This test is taken directly from #16053.
+// It checks that you cannot use an AND-pattern (`binding @ pat`)
+// where one side is by-ref and the other is by-move.
+
+struct X {
+ x: (),
+}
+
+fn main() {
+ let x = Some(X { x: () });
+ match x {
+ Some(ref _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ None => panic!(),
+ }
+
+ let x = Some(X { x: () });
+ match x {
+ Some(_z @ ref _y) => {}
+ //~^ ERROR borrow of moved value
+ None => panic!(),
+ }
+
+ let mut x = Some(X { x: () });
+ match x {
+ Some(ref mut _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ None => panic!(),
+ }
+
+ let mut x = Some(X { x: () });
+ match x {
+ Some(_z @ ref mut _y) => {}
+ //~^ ERROR borrow of moved value
+ None => panic!(),
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
new file mode 100644
index 000000000..c8b45fd24
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -0,0 +1,79 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
+ |
+LL | Some(ref _y @ _z) => {}
+ | ------^^^--
+ | | |
+ | | value moved into `_z` here
+ | value borrowed, by `_y`, here
+
+error: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14
+ |
+LL | Some(_z @ ref _y) => {}
+ | --^^^------
+ | | |
+ | | value borrowed here after move
+ | value moved into `_z` here
+ | move occurs because `_z` has type `X` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref _z @ ref _y) => {}
+ | +++
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
+ |
+LL | Some(ref mut _y @ _z) => {}
+ | ----------^^^--
+ | | |
+ | | value moved into `_z` here
+ | value borrowed, by `_y`, here
+
+error: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14
+ |
+LL | Some(_z @ ref mut _y) => {}
+ | --^^^----------
+ | | |
+ | | value borrowed here after move
+ | value moved into `_z` here
+ | move occurs because `_z` has type `X` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref _z @ ref mut _y) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
+ |
+LL | Some(ref _y @ _z) => {}
+ | ^^^^^^ -- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref _y @ ref _z) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
+ |
+LL | Some(ref mut _y @ _z) => {}
+ | ^^^^^^^^^^ -- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref mut _y @ ref _z) => {}
+ | +++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
new file mode 100644
index 000000000..1816a74a0
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
@@ -0,0 +1,11 @@
+// See issue #12534.
+
+fn main() {}
+
+struct A(Box<u8>);
+
+fn f(a @ A(u): A) -> Box<u8> {
+ //~^ ERROR use of partially moved value
+ drop(a);
+ u
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
new file mode 100644
index 000000000..a481ca468
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
@@ -0,0 +1,13 @@
+error[E0382]: use of partially moved value
+ --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6
+ |
+LL | fn f(a @ A(u): A) -> Box<u8> {
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `Box<u8>`, 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/pattern/bindings-after-at/borrowck-move-and-move.rs b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
new file mode 100644
index 000000000..a61d68215
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
@@ -0,0 +1,31 @@
+// Test that moving on both sides of an `@` pattern is not allowed.
+
+fn main() {
+ struct U; // Not copy!
+
+ // Prevent promotion:
+ fn u() -> U {
+ U
+ }
+
+ let a @ b = U; //~ ERROR use of moved value
+
+ let a @ (b, c) = (U, U); //~ ERROR use of partially moved value
+
+ let a @ (b, c) = (u(), u()); //~ ERROR use of partially moved value
+
+ match Ok(U) {
+ a @ Ok(b) | a @ Err(b) => {} //~ ERROR use of moved value
+ //~^ ERROR use of moved value
+ }
+
+ fn fun(a @ b: U) {} //~ ERROR use of moved value
+
+ match [u(), u(), u(), u()] {
+ xs @ [a, .., b] => {} //~ ERROR use of partially moved value
+ }
+
+ match [u(), u(), u(), u()] {
+ xs @ [_, ys @ .., _] => {} //~ ERROR use of partially moved value
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
new file mode 100644
index 000000000..324897151
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -0,0 +1,112 @@
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:11:9
+ |
+LL | let a @ b = U;
+ | ^ - - move occurs because value has type `U`, which does not implement the `Copy` trait
+ | | |
+ | | value moved here
+ | value used here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ ref b = U;
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:13:9
+ |
+LL | let a @ (b, c) = (U, U);
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (b, ref c) = (U, U);
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:15:9
+ |
+LL | let a @ (b, c) = (u(), u());
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (b, ref c) = (u(), u());
+ | +++ +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:18:16
+ |
+LL | match Ok(U) {
+ | ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
+LL | a @ Ok(b) | a @ Err(b) => {}
+ | - ^ value used here after move
+ | |
+ | value moved here
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Ok(b) | a @ Err(b) => {}
+ | +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:18:29
+ |
+LL | match Ok(U) {
+ | ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
+LL | a @ Ok(b) | a @ Err(b) => {}
+ | - ^ value used here after move
+ | |
+ | value moved here
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Ok(b) | ref a @ Err(b) => {}
+ | +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:25:9
+ |
+LL | xs @ [a, .., b] => {}
+ | ^^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref xs @ [a, .., ref b] => {}
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:29:9
+ |
+LL | xs @ [_, ys @ .., _] => {}
+ | ^^ -- value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref xs @ [_, ref ys @ .., _] => {}
+ | +++ +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:22:12
+ |
+LL | fn fun(a @ b: U) {}
+ | ^ - value moved here
+ | |
+ | value used here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
new file mode 100644
index 000000000..fbdefd9d3
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
@@ -0,0 +1,84 @@
+// check-pass
+
+// Test `@` patterns combined with `box` patterns.
+
+#![feature(box_patterns)]
+
+#[derive(Copy, Clone)]
+struct C;
+
+fn c() -> C { C }
+
+struct NC;
+
+fn nc() -> NC { NC }
+
+fn main() {
+ let ref a @ box b = Box::new(C); // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+
+ let ref a @ box b = Box::new(c()); // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+
+ fn f3(ref a @ box b: Box<C>) { // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+ }
+ match Box::new(c()) {
+ ref a @ box b => { // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+ }
+ }
+
+ let ref a @ box ref b = Box::new(NC); // OK.
+ drop(a);
+ drop(b);
+
+ fn f4(ref a @ box ref b: Box<NC>) { // OK.
+ drop(a);
+ drop(b)
+ }
+
+ match Box::new(nc()) {
+ ref a @ box ref b => { // OK.
+ drop(a);
+ drop(b);
+ }
+ }
+
+ match Box::new([Ok(c()), Err(nc()), Ok(c())]) {
+ box [Ok(a), ref xs @ .., Err(ref b)] => {
+ let _: C = a;
+ let _: &[Result<C, NC>; 1] = xs;
+ let _: &NC = b;
+ }
+ _ => {}
+ }
+
+ match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] {
+ [Ok(box a), ref xs @ .., Err(box ref b), Err(box ref c)] => {
+ let _: C = a;
+ let _: &[Result<Box<C>, Box<NC>>; 1] = xs;
+ let _: &NC = b;
+ let _: &NC = c;
+ }
+ _ => {}
+ }
+
+ match Box::new([Ok(c()), Err(nc()), Ok(c())]) {
+ box [Ok(a), ref xs @ .., Err(b)] => {}
+ _ => {}
+ }
+
+ match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] {
+ [Ok(box ref a), ref xs @ .., Err(box b), Err(box ref mut c)] => {}
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
new file mode 100644
index 000000000..45aa65e67
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
@@ -0,0 +1,69 @@
+// Test `@` patterns combined with `box` patterns.
+
+#![feature(box_patterns)]
+
+#[derive(Copy, Clone)]
+struct C;
+
+fn c() -> C {
+ C
+}
+
+struct NC;
+
+fn nc() -> NC {
+ NC
+}
+
+fn main() {
+ let a @ box &b = Box::new(&C);
+
+ let a @ box b = Box::new(C);
+
+ fn f1(a @ box &b: Box<&C>) {}
+
+ fn f2(a @ box b: Box<C>) {}
+
+ match Box::new(C) {
+ a @ box b => {}
+ }
+
+ let ref a @ box b = Box::new(NC); //~ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+
+ let ref a @ box ref mut b = Box::new(nc());
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref a @ box ref mut b = Box::new(NC);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref a @ box ref mut b = Box::new(NC);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = NC;
+ let ref a @ box ref mut b = Box::new(NC);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = NC;
+ drop(a);
+
+ let ref mut a @ box ref b = Box::new(NC);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = Box::new(NC);
+ drop(b);
+
+ fn f5(ref mut a @ box ref b: Box<NC>) {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = Box::new(NC);
+ drop(b);
+ }
+
+ match Box::new(nc()) {
+ ref mut a @ box ref b => {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = Box::new(NC);
+ drop(b);
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
new file mode 100644
index 000000000..f27df32cc
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -0,0 +1,145 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-at-and-box.rs:31:9
+ |
+LL | let ref a @ box b = Box::new(NC);
+ | -----^^^^^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:34:9
+ |
+LL | let ref a @ box ref mut b = Box::new(nc());
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:36:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:38:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:42:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:48:9
+ |
+LL | let ref mut a @ box ref b = Box::new(NC);
+ | ---------^^^^^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:62:9
+ |
+LL | ref mut a @ box ref b => {
+ | ---------^^^^^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:54:11
+ |
+LL | fn f5(ref mut a @ box ref b: Box<NC>) {
+ | ---------^^^^^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-at-and-box.rs:31:9
+ |
+LL | let ref a @ box b = Box::new(NC);
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `NC`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ box ref b = Box::new(NC);
+ | +++
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:38:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = NC;
+ | ------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:42:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = NC;
+ | ------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:48:9
+ |
+LL | let ref mut a @ box ref b = Box::new(NC);
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:62:9
+ |
+LL | ref mut a @ box ref b => {
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:54:11
+ |
+LL | fn f5(ref mut a @ box ref b: Box<NC>) {
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0382, E0502.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs
new file mode 100644
index 000000000..0108861cf
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs
@@ -0,0 +1,49 @@
+// check-pass
+
+// Test `Copy` bindings in the rhs of `@` patterns.
+
+#[derive(Copy, Clone)]
+struct C;
+
+fn mk_c() -> C { C }
+
+#[derive(Copy, Clone)]
+struct P<A, B>(A, B);
+
+enum E<A, B> { L(A), R(B) }
+
+fn main() {
+ let a @ b @ c @ d = C;
+ let a @ (b, c) = (C, mk_c());
+ let a @ P(b, P(c, d)) = P(mk_c(), P(C, C));
+ let a @ [b, c] = [C, C];
+ let a @ [b, .., c] = [C, mk_c(), C];
+ let a @ [b, mid @ .., c] = [C, mk_c(), C];
+ let a @ &(b, c) = &(C, C);
+ let a @ &(b, &P(c, d)) = &(mk_c(), &P(C, C));
+
+ fn foo(a @ [b, mid @ .., c]: [C; 3]) {}
+
+ use self::E::*;
+ match L(C) {
+ L(a) | R(a) => {
+ let a: C = a;
+ drop(a);
+ drop(a);
+ }
+ }
+ match R(&L(&mk_c())) {
+ L(L(&a)) | L(R(&a)) | R(L(&a)) | R(R(&a)) => {
+ let a: C = a;
+ drop(a);
+ drop(a);
+ }
+ }
+
+ match Ok(mk_c()) {
+ Ok(ref a @ b) | Err(b @ ref a) => {
+ let _: &C = a;
+ let _: C = b;
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
new file mode 100644
index 000000000..82f16fca6
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
@@ -0,0 +1,7 @@
+// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented even with promotion.
+// Currently this logic exists in THIR match checking as opposed to borrowck.
+
+fn main() {
+ struct U;
+ let a @ ref b = U; //~ ERROR borrow of moved value
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
new file mode 100644
index 000000000..d6474f1b4
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -0,0 +1,17 @@
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:6:9
+ |
+LL | let a @ ref b = U;
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ ref b = U;
+ | +++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
new file mode 100644
index 000000000..06dc6e1c4
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
@@ -0,0 +1,80 @@
+// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented.
+
+fn main() {
+ struct U;
+
+ // Prevent promotion.
+ fn u() -> U {
+ U
+ }
+
+ fn f1(a @ ref b: U) {}
+ //~^ ERROR borrow of moved value
+
+ fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of partially moved value
+ fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
+ //~^ ERROR borrow of moved value
+
+ let a @ ref b = U;
+ //~^ ERROR borrow of moved value
+ let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of partially moved value
+ let a @ [ref mut b, ref c] = [U, U];
+ //~^ ERROR borrow of moved value
+ let a @ ref b = u();
+ //~^ ERROR borrow of moved value
+ let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of partially moved value
+ let a @ [ref mut b, ref c] = [u(), u()];
+ //~^ ERROR borrow of moved value
+
+ match Some(U) {
+ a @ Some(ref b) => {}
+ //~^ ERROR borrow of moved value
+ None => {}
+ }
+ match Some((U, U)) {
+ a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of moved value
+ None => {}
+ }
+ match Some([U, U]) {
+ mut a @ Some([ref b, ref mut c]) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+ match Some(u()) {
+ a @ Some(ref b) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+ match Some((u(), u())) {
+ a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of moved value
+ None => {}
+ }
+ match Some([u(), u()]) {
+ mut a @ Some([ref b, ref mut c]) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
new file mode 100644
index 000000000..389e86e64
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -0,0 +1,487 @@
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:22:9
+ |
+LL | let a @ ref b = U;
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ ref b = U;
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | -^^^^^^^^^^^^---------^^^^^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (ref mut b @ ref mut c, d @ ref e) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
+ |
+LL | let a @ [ref mut b, ref c] = [U, U];
+ | -^^^^---------^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ [ref mut b, ref c] = [U, U];
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
+ |
+LL | let a @ ref b = u();
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ ref b = u();
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | -^^^^^^^^^^^^---------^^^^^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (ref mut b @ ref mut c, d @ ref e) = (u(), u());
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
+ |
+LL | let a @ [ref mut b, ref c] = [u(), u()];
+ | -^^^^---------^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ [ref mut b, ref c] = [u(), u()];
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9
+ |
+LL | a @ Some(ref b) => {}
+ | -^^^^^^^^-----^
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some(ref b) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
+ |
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | -----^^^^^^^^^-----^^---------^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref mut a @ Some([ref b, ref mut c]) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
+ |
+LL | a @ Some(ref b) => {}
+ | -^^^^^^^^-----^
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some(ref b) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9
+ |
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | -----^^^^^^^^^-----^^---------^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref mut a @ Some([ref b, ref mut c]) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11
+ |
+LL | fn f1(a @ ref b: U) {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f1(ref a @ ref b: U) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | -----^^^^^^^^-----^^^^^^^^^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f2(ref mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f2(mut a @ (ref b @ ref c, mut d @ ref e): (U, U)) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | -----^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f2(mut a @ (b @ ref c, ref mut d @ ref e): (U, U)) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11
+ |
+LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
+ | -^^^^---------^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f3(ref a @ [ref mut b, ref c]: [U; 2]) {}
+ | +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+ | +++ +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
+ |
+LL | match Some((U, U)) {
+ | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | - value moved here ^ value used here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
+ |
+LL | match Some([U, U]) {
+ | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | ----- ^^^^^^^^^ value borrowed here after move
+ | |
+ | value moved here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:18
+ |
+LL | match Some(u()) {
+ | --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
+LL | a @ Some(ref b) => {}
+ | - ^^^^^ value borrowed here after move
+ | |
+ | value moved here
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some(ref b) => {}
+ | +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
+ |
+LL | match Some((u(), u())) {
+ | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | - value moved here ^ value used here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
+ |
+LL | match Some([u(), u()]) {
+ | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | ----- ^^^^^^^^^ value borrowed here after move
+ | |
+ | value moved here
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | ^^^^^ ----- value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 33 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
new file mode 100644
index 000000000..0b0a78010
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
@@ -0,0 +1,82 @@
+// Test that `ref mut? @ pat_with_by_move_bindings` is prevented.
+
+fn main() {
+ struct U;
+
+ // Prevent promotion.
+ fn u() -> U {
+ U
+ }
+
+ fn f1(ref a @ b: U) {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of partially moved value
+
+ let ref a @ b = U;
+ //~^ ERROR cannot move out of value because it is borrowed
+ let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ let ref mut a @ [b, mut c] = [U, U];
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of partially moved value
+ let ref a @ b = u();
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ let ref mut a @ [b, mut c] = [u(), u()];
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of partially moved value
+
+ match Some(U) {
+ ref a @ Some(b) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some((U, U)) {
+ ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some([U, U]) {
+ ref mut a @ Some([b, mut c]) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some(u()) {
+ ref a @ Some(b) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some((u(), u())) {
+ ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+ match Some([u(), u()]) {
+ ref mut a @ Some([b, mut c]) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
new file mode 100644
index 000000000..770bb8953
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -0,0 +1,375 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9
+ |
+LL | let ref a @ b = U;
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ | -----^^^^^^^^^^^^-----^^^^^^^^^^-^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
+ |
+LL | let ref mut a @ [b, mut c] = [U, U];
+ | ---------^^^^-^^-----^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
+ |
+LL | let ref a @ b = u();
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | -----^^^^^^^^^^^^-----^^^^^^^^^^-^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
+ |
+LL | let ref mut a @ [b, mut c] = [u(), u()];
+ | ---------^^^^-^^-----^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9
+ |
+LL | ref a @ Some(b) => {}
+ | -----^^^^^^^^-^
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9
+ |
+LL | ref mut a @ Some([b, mut c]) => {}
+ | ---------^^^^^^^^^-^^-----^^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9
+ |
+LL | ref a @ Some(b) => {}
+ | -----^^^^^^^^-^
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9
+ |
+LL | ref mut a @ Some([b, mut c]) => {}
+ | ---------^^^^^^^^^-^^-----^^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
+ |
+LL | fn f1(ref a @ b: U) {}
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | -----^^^^^^^^^^^^-----^^^^^^^^^^-^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
+ |
+LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
+ | ---------^^^^-^^-----^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error[E0382]: borrow of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
+ |
+LL | let ref mut a @ [b, mut c] = [U, U];
+ | ^^^^^^^^^ ----- value partially moved here
+ | |
+ | value borrowed here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref mut a @ [b, ref mut c] = [U, U];
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
+ |
+LL | let ref a @ b = u();
+ | ^^^^^ - --- move occurs because value has type `U`, which does not implement the `Copy` trait
+ | | |
+ | | value moved here
+ | value borrowed here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ ref b = u();
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | ^^^^^ ----- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (ref b @ ref mut c, ref d @ e) = (u(), u());
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ ref e) = (u(), u());
+ | +++
+
+error[E0382]: borrow of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
+ |
+LL | let ref mut a @ [b, mut c] = [u(), u()];
+ | ^^^^^^^^^ ----- value partially moved here
+ | |
+ | value borrowed here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref mut a @ [b, ref mut c] = [u(), u()];
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | ^^^^^ ----- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((ref b @ ref mut c, ref d @ e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ ref e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
+ |
+LL | fn f1(ref a @ b: U) {}
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | ^^^^^ ----- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
+ |
+LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
+ | ^^^^^^^^^ ----- value partially moved here
+ | |
+ | value borrowed here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 36 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs
new file mode 100644
index 000000000..df213f688
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs
@@ -0,0 +1,45 @@
+// check-pass
+
+// Test that `ref` patterns may be used on both sides
+// of an `@` pattern according to NLL borrowck.
+
+fn main() {
+ struct U; // Not copy!
+
+ // Promotion:
+ let ref a @ ref b = U;
+ let _: &U = a;
+ let _: &U = b;
+
+ // Prevent promotion:
+ fn u() -> U { U }
+
+ let ref a @ ref b = u();
+ let _: &U = a;
+ let _: &U = b;
+
+ let ref a @ (ref b, [ref c, ref d]) = (u(), [u(), u()]);
+ let _: &(U, [U; 2]) = a;
+ let _: &U = b;
+ let _: &U = c;
+ let _: &U = d;
+
+ fn f1(ref a @ (ref b, [ref c, ref mid @ .., ref d]): (U, [U; 4])) {}
+
+ let a @ (b, [c, d]) = &(u(), [u(), u()]);
+ let _: &(U, [U; 2]) = a;
+ let _: &U = b;
+ let _: &U = c;
+ let _: &U = d;
+
+ let ref a @ &ref b = &u();
+ let _: &&U = a;
+ let _: &U = b;
+
+ match Ok(u()) {
+ ref a @ Ok(ref b) | ref a @ Err(ref b) => {
+ let _: &Result<U, U> = a;
+ let _: &U = b;
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
new file mode 100644
index 000000000..6bc0d346c
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
@@ -0,0 +1,136 @@
+enum Option<T> {
+ None,
+ Some(T),
+}
+
+fn main() {
+ match &mut Some(1) {
+ ref mut z @ &mut Some(ref a) => {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ **z = None;
+ println!("{}", *a);
+ }
+ _ => ()
+ }
+
+ struct U;
+
+ // Prevent promotion:
+ fn u() -> U { U }
+
+ fn f1(ref a @ ref mut b: U) {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ fn f2(ref mut a @ ref b: U) {}
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+
+ let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+
+ let ref a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref mut a @ ref b = U;
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref mut a @ (ref b, ref c) = (U, U);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+
+ let ref mut a @ ref b = u();
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = u();
+ drop(b);
+ let ref a @ ref mut b = u();
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = u();
+ drop(a);
+
+ let ref mut a @ ref b = U;
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *a = U;
+ drop(b);
+ let ref a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *b = U;
+ drop(a);
+
+ match Ok(U) {
+ ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *a = Err(U);
+ drop(b);
+ }
+ }
+
+ match Ok(U) {
+ ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *b = U;
+ drop(a);
+ }
+ }
+
+ match Ok(U) {
+ ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot assign to `*b`, as it is immutable for the pattern guard
+ _ => {}
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot assign to `*a`, as it is immutable for the pattern guard
+ _ => {}
+ }
+ match Ok(U) {
+ ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot move out of `b` in pattern guard
+ //~| ERROR cannot move out of `b` in pattern guard
+ _ => {}
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot move out of `a` in pattern guard
+ //~| ERROR cannot move out of `a` in pattern guard
+ _ => {}
+ }
+
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = U;
+ *c = U;
+
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = U;
+ drop(a);
+
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = U; //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *c = U;
+ drop(a);
+ let ref mut a @ (ref b, ref c) = (U, U);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
new file mode 100644
index 000000000..8546b4bb4
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -0,0 +1,445 @@
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:9
+ |
+LL | ref mut z @ &mut Some(ref a) => {
+ | ---------^^^^^^^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `a`, occurs here
+ | mutable borrow, by `z`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9
+ |
+LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
+ | ---------^^^^-----------------^
+ | | | |
+ | | | another mutable borrow, by `c`, occurs here
+ | | also borrowed as immutable, by `b`, here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22
+ |
+LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `c`, occurs here
+ | immutable borrow, by `b`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9
+ |
+LL | let ref a @ ref mut b = U;
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
+ |
+LL | let ref mut a @ ref b = U;
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
+ |
+LL | let ref mut a @ (ref b, ref c) = (U, U);
+ | ---------^^^^-----^^-----^
+ | | | |
+ | | | immutable borrow, by `c`, occurs here
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
+ |
+LL | let ref mut a @ ref b = u();
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
+ |
+LL | let ref a @ ref mut b = u();
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9
+ |
+LL | let ref mut a @ ref b = U;
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9
+ |
+LL | let ref a @ ref mut b = U;
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
+ | ---------^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
+ | ---------^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | -----^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | -----^^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ | -----^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ | -----^^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ | ---------^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ | ---------^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | -----^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | -----^^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ---------^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ---------^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9
+ |
+LL | let ref mut a @ (ref b, ref c) = (U, U);
+ | ---------^^^^-----^^-----^
+ | | | |
+ | | | immutable borrow, by `c`, occurs here
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11
+ |
+LL | fn f1(ref a @ ref mut b: U) {}
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
+ |
+LL | fn f2(ref mut a @ ref b: U) {}
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
+ |
+LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
+ | -----^^^^^^^^^^^----------------^^^^^^^^
+ | | |
+ | | mutable borrow, by `mid`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22
+ |
+LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ | -----^^^-------------
+ | | | |
+ | | | also moved into `c` here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
+ |
+LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ | ---------^^^-
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
+ |
+LL | ref mut z @ &mut Some(ref a) => {
+ | --------- ^^^^^ immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | **z = None;
+ | ---------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
+ |
+LL | let ref mut a @ ref b = u();
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
+ |
+LL | let ref a @ ref mut b = u();
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = u();
+ | -------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | ----- ^^^^^^^^^ mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | drop(a);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | ----- ^^^^^^^^^ mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | drop(a);
+ | - immutable borrow later used here
+
+error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:61
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ | ^^^^^^ cannot assign
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:61
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ | ^^^^^^^^^^^ cannot assign
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error[E0507]: cannot move out of `b` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `b` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `a` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ^ move occurs because `a` has type `&mut Result<U, U>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `a` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ^ move occurs because `a` has type `&mut Result<U, U>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = U;
+ | ------ mutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = U;
+ | ------ mutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+LL |
+LL | *b = U;
+ | ------ mutable borrow later used here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
+ |
+LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ | ----- ^^^^^^^^^ - value moved here
+ | | |
+ | | value borrowed here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 47 previous errors
+
+Some errors have detailed explanations: E0382, E0502, E0507, E0594.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
new file mode 100644
index 000000000..99739c7bc
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
@@ -0,0 +1,109 @@
+// Test that `ref mut x @ ref mut y` and varieties of that are not allowed.
+
+fn main() {
+ struct U;
+
+ fn u() -> U { U }
+
+ fn f1(ref mut a @ ref mut b: U) {}
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ fn f2(ref mut a @ ref mut b: U) {}
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ fn f3(
+ ref mut a @ [
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ [ref b @ .., _],
+ [_, ref mut mid @ ..],
+ ..,
+ [..],
+ ] : [[U; 4]; 5]
+ ) {}
+ fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ drop(a);
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ drop(b);
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ *a = U;
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ *b = U;
+
+ let ref mut a @ (
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ ref mut b,
+ [
+ ref mut c,
+ ref mut d,
+ ref e,
+ ]
+ ) = (U, [U, U, U]);
+
+ let ref mut a @ (
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ ref mut b,
+ [
+ ref mut c,
+ ref mut d,
+ ref e,
+ ]
+ ) = (u(), [u(), u(), u()]);
+
+ let a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR borrow of moved value
+ let mut val = (U, [U, U]);
+ let a @ (b, [c, d]) = &mut val; // Same as ^--
+ //~^ ERROR borrow of moved value
+
+ let a @ &mut ref mut b = &mut U;
+ //~^ ERROR borrow of moved value
+ let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+ //~^ ERROR borrow of moved value
+
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ }
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ *b = U;
+ }
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ *a = Err(U);
+
+ // FIXME: The binding name value used above makes for problematic diagnostics.
+ // Resolve that somehow...
+ }
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ drop(a);
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
new file mode 100644
index 000000000..ad4ce7952
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -0,0 +1,359 @@
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:26:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9
+ |
+LL | let ref mut a @ (
+ | ^--------
+ | |
+ | _________first mutable borrow, by `a`, occurs here
+ | |
+LL | |
+LL | | ref mut b,
+ | | --------- another mutable borrow, by `b`, occurs here
+LL | | [
+LL | | ref mut c,
+ | | --------- another mutable borrow, by `c`, occurs here
+LL | | ref mut d,
+ | | --------- another mutable borrow, by `d`, occurs here
+LL | | ref e,
+ | | ----- also borrowed as immutable, by `e`, here
+LL | | ]
+LL | | ) = (U, [U, U, U]);
+ | |_____^
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:54:9
+ |
+LL | let ref mut a @ (
+ | ^--------
+ | |
+ | _________first mutable borrow, by `a`, occurs here
+ | |
+LL | |
+LL | | ref mut b,
+ | | --------- another mutable borrow, by `b`, occurs here
+LL | | [
+LL | | ref mut c,
+ | | --------- another mutable borrow, by `c`, occurs here
+LL | | ref mut d,
+ | | --------- another mutable borrow, by `d`, occurs here
+LL | | ref e,
+ | | ----- also borrowed as immutable, by `e`, here
+LL | | ]
+LL | | ) = (u(), [u(), u(), u()]);
+ | |_________^
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:64:9
+ |
+LL | let a @ (ref mut b, ref mut c) = (U, U);
+ | -^^^^---------^^---------^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9
+ |
+LL | let a @ (b, [c, d]) = &mut val; // Same as ^--
+ | -^^^^-^^^-^^-^^
+ | | | | |
+ | | | | value borrowed here after move
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (b, [c, d]) = &mut val; // Same as ^--
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
+ |
+LL | let a @ &mut ref mut b = &mut U;
+ | -^^^^^^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ &mut ref mut b = &mut U;
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9
+ |
+LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+ | -^^^^^^^^^---------^^---------^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+ | +++
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11
+ |
+LL | fn f1(ref mut a @ ref mut b: U) {}
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
+ |
+LL | fn f2(ref mut a @ ref mut b: U) {}
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9
+ |
+LL | ref mut a @ [
+ | ^--------
+ | |
+ | _________first mutable borrow, by `a`, occurs here
+ | |
+LL | |
+LL | | [ref b @ .., _],
+ | | ---------- also borrowed as immutable, by `b`, here
+LL | | [_, ref mut mid @ ..],
+ | | ---------------- another mutable borrow, by `mid`, occurs here
+LL | | ..,
+LL | | [..],
+LL | | ] : [[U; 4]; 5]
+ | |_________^
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:22
+ |
+LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ | ---------^^^-------------
+ | | | |
+ | | | also moved into `c` here
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
+ |
+LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ | ---------^^^-
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ^^^^^^^^^ --------- first mutable borrow occurs here
+ | |
+ | second mutable borrow occurs here
+...
+LL | drop(b);
+ | - first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ^^^^^^^^^ --------- first mutable borrow occurs here
+ | |
+ | second mutable borrow occurs here
+...
+LL | *b = U;
+ | ------ first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | *a = Err(U);
+ | ----------- first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | *a = Err(U);
+ | ----------- first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | drop(a);
+ | - first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | drop(a);
+ | - first borrow later used here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
+ |
+LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ | --------- ^^^^^^^^^ - value moved here
+ | | |
+ | | value borrowed here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 31 previous errors
+
+Some errors have detailed explanations: E0382, E0499.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/box-patterns.rs b/tests/ui/pattern/bindings-after-at/box-patterns.rs
new file mode 100644
index 000000000..9db37253c
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/box-patterns.rs
@@ -0,0 +1,35 @@
+// Test bindings-after-at with box-patterns
+
+// run-pass
+
+#![feature(box_patterns)]
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+fn test(x: Option<Box<i32>>) -> MatchArm {
+ match x {
+ ref bar @ Some(box n) if n > 0 => {
+ // bar is a &Option<Box<i32>>
+ assert_eq!(bar, &x);
+
+ MatchArm::Arm(0)
+ },
+ Some(ref bar @ box n) if n < 0 => {
+ // bar is a &Box<i32> here
+ assert_eq!(**bar, n);
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ assert_eq!(test(Some(Box::new(2))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(-1))), MatchArm::Arm(1));
+ assert_eq!(test(Some(Box::new(0))), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
new file mode 100644
index 000000000..1e2c2968c
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
@@ -0,0 +1,14 @@
+// Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden.
+
+#[derive(Copy, Clone)]
+struct C;
+
+struct NC<A, B>(A, B);
+
+fn main() {
+ // this compiles
+ let a @ NC(b, c) = NC(C, C);
+
+ let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+ //~^ ERROR use of partially moved value
+}
diff --git a/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
new file mode 100644
index 000000000..e0e623fa5
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -0,0 +1,17 @@
+error[E0382]: use of partially moved value
+ --> $DIR/copy-and-move-mixed.rs:12:9
+ |
+LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ NC(b, ref c @ NC(d, e)) = NC(C, NC(C, C));
+ | +++ +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
new file mode 100644
index 000000000..dfd4d0285
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
@@ -0,0 +1,48 @@
+// Ensures the independence of each side in `binding @ subpat`
+// determine their binding modes independently of each other.
+//
+// That is, `binding` does not influence `subpat`.
+// This is important because we might want to allow `p1 @ p2`,
+// where both `p1` and `p2` are syntactically unrestricted patterns.
+// If `binding` is allowed to influence `subpat`,
+// this would create problems for the generalization aforementioned.
+
+
+fn main() {
+ struct NotCopy;
+
+ fn f1(a @ b: &NotCopy) { // OK
+ let _: &NotCopy = a;
+ }
+ fn f2(ref a @ b: &NotCopy) {
+ let _: &&NotCopy = a; // Ok
+ }
+
+ let a @ b = &NotCopy; // OK
+ let _: &NotCopy = a;
+ let ref a @ b = &NotCopy; // OK
+ let _: &&NotCopy = a;
+
+ let ref a @ b = NotCopy; //~ ERROR cannot move out of value because it is borrowed
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ let ref mut a @ b = NotCopy; //~ ERROR cannot move out of value because it is borrowed
+ //~^ ERROR borrow of moved value
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ match Ok(NotCopy) {
+ Ok(ref a @ b) | Err(b @ ref a) => {
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ }
+ }
+ match NotCopy {
+ ref a @ b => {
+ //~^ ERROR cannot move out of value because it is borrowed
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
new file mode 100644
index 000000000..638bdd6db
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -0,0 +1,68 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:26:9
+ |
+LL | let ref a @ b = NotCopy;
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
+ |
+LL | let ref mut a @ b = NotCopy;
+ | ---------^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:34:12
+ |
+LL | Ok(ref a @ b) | Err(b @ ref a) => {
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: borrow of moved value
+ --> $DIR/default-binding-modes-both-sides-independent.rs:34:29
+ |
+LL | Ok(ref a @ b) | Err(b @ ref a) => {
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Ok(ref a @ b) | Err(ref b @ ref a) => {
+ | +++
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:42:9
+ |
+LL | ref a @ b => {
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error[E0382]: borrow of moved value
+ --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
+ |
+LL | let ref mut a @ b = NotCopy;
+ | ^^^^^^^^^ - ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
+ | | |
+ | | value moved here
+ | value borrowed here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref mut a @ ref b = NotCopy;
+ | +++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs b/tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs
new file mode 100644
index 000000000..fe7d1eba1
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(unused_mut)]
+
+fn main() {
+ let mut is_mut @ not_mut = 42;
+ &mut is_mut;
+ &not_mut;
+ let not_mut @ mut is_mut = 42;
+ &mut is_mut;
+ &not_mut;
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs
new file mode 100644
index 000000000..e7d99534d
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs
@@ -0,0 +1,11 @@
+fn main() {
+ let mut is_mut @ not_mut = 42;
+ &mut is_mut;
+ &mut not_mut;
+ //~^ ERROR cannot borrow
+
+ let not_mut @ mut is_mut = 42;
+ &mut is_mut;
+ &mut not_mut;
+ //~^ ERROR cannot borrow
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
new file mode 100644
index 000000000..54118dc36
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
@@ -0,0 +1,25 @@
+error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
+ --> $DIR/nested-binding-modes-mut.rs:4:5
+ |
+LL | &mut not_mut;
+ | ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut is_mut @ mut not_mut = 42;
+ | +++
+
+error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
+ --> $DIR/nested-binding-modes-mut.rs:9:5
+ |
+LL | &mut not_mut;
+ | ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut not_mut @ mut is_mut = 42;
+ | +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs
new file mode 100644
index 000000000..adfb0387f
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs
@@ -0,0 +1,11 @@
+fn main() {
+ let ref is_ref @ is_val = 42;
+ *is_ref;
+ *is_val;
+ //~^ ERROR cannot be dereferenced
+
+ let is_val @ ref is_ref = 42;
+ *is_ref;
+ *is_val;
+ //~^ ERROR cannot be dereferenced
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr
new file mode 100644
index 000000000..b378fe356
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr
@@ -0,0 +1,15 @@
+error[E0614]: type `{integer}` cannot be dereferenced
+ --> $DIR/nested-binding-modes-ref.rs:4:5
+ |
+LL | *is_val;
+ | ^^^^^^^
+
+error[E0614]: type `{integer}` cannot be dereferenced
+ --> $DIR/nested-binding-modes-ref.rs:9:5
+ |
+LL | *is_val;
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0614`.
diff --git a/tests/ui/pattern/bindings-after-at/nested-patterns.rs b/tests/ui/pattern/bindings-after-at/nested-patterns.rs
new file mode 100644
index 000000000..f06563d56
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-patterns.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+
+struct A { a: u8, b: u8 }
+
+pub fn main() {
+ match (A { a: 10, b: 20 }) {
+ ref x @ A { ref a, b: 20 } => {
+ assert_eq!(x.a, 10);
+ assert_eq!(*a, 10);
+ }
+ A { b: ref _b, .. } => panic!(),
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs
new file mode 100644
index 000000000..a709e34b5
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs
@@ -0,0 +1,33 @@
+// Here we check that type ascription is syntactically invalid when
+// not in the top position of an ascribing `let` binding or function parameter.
+
+
+// This has no effect.
+// We include it to demonstrate that this is the case:
+#![feature(type_ascription)]
+
+fn main() {}
+
+fn _ok() {
+ let _a @ _b: u8 = 0; // OK.
+ fn _f(_a @ _b: u8) {} // OK.
+}
+
+#[cfg(FALSE)]
+fn case_1() {
+ let a: u8 @ b = 0;
+ //~^ ERROR expected one of `!`
+}
+
+#[cfg(FALSE)]
+fn case_2() {
+ let a @ (b: u8);
+ //~^ ERROR expected one of `!`
+ //~| ERROR expected one of `)`
+}
+
+#[cfg(FALSE)]
+fn case_3() {
+ let a: T1 @ Outer(b: T2);
+ //~^ ERROR expected one of `!`
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
new file mode 100644
index 000000000..27660ae40
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
@@ -0,0 +1,26 @@
+error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:18:15
+ |
+LL | let a: u8 @ b = 0;
+ | ^ expected one of 7 possible tokens
+
+error: expected one of `)`, `,`, `@`, or `|`, found `:`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:15
+ |
+LL | let a @ (b: u8);
+ | ^ expected one of `)`, `,`, `@`, or `|`
+
+error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `)`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:19
+ |
+LL | let a @ (b: u8);
+ | ^ expected one of 7 possible tokens
+
+error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:31:15
+ |
+LL | let a: T1 @ Outer(b: T2);
+ | ^ expected one of 7 possible tokens
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs b/tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs
new file mode 100644
index 000000000..383e377a5
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs
@@ -0,0 +1,43 @@
+// Test bindings-after-at with or-patterns and box-patterns
+
+// run-pass
+
+#![feature(box_patterns)]
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug, PartialEq)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(foo: Option<Box<Test>>) -> MatchArm {
+ match foo {
+ ref bar @ Some(box Test::Foo | box Test::Bar) => {
+ assert_eq!(bar, &foo);
+
+ MatchArm::Arm(0)
+ },
+ Some(ref bar @ box Test::Baz | ref bar @ box Test::Qux) => {
+ assert!(**bar == Test::Baz || **bar == Test::Qux);
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ assert_eq!(test(Some(Box::new(Test::Foo))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(Test::Bar))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(Test::Baz))), MatchArm::Arm(1));
+ assert_eq!(test(Some(Box::new(Test::Qux))), MatchArm::Arm(1));
+ assert_eq!(test(None), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs b/tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs
new file mode 100644
index 000000000..d315f7ee3
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs
@@ -0,0 +1,54 @@
+// Test bindings-after-at with or-patterns and slice-patterns
+
+// run-pass
+
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug, PartialEq)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(foo: &[Option<Test>]) -> MatchArm {
+ match foo {
+ bar @ [Some(Test::Foo), .., Some(Test::Qux | Test::Foo)] => {
+ assert_eq!(bar, foo);
+
+ MatchArm::Arm(0)
+ },
+ [.., bar @ Some(Test::Bar | Test::Qux), _] => {
+ assert!(bar == &Some(Test::Bar) || bar == &Some(Test::Qux));
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ let foo = vec![
+ Some(Test::Foo),
+ Some(Test::Bar),
+ Some(Test::Baz),
+ Some(Test::Qux),
+ ];
+
+ // path 1a
+ assert_eq!(test(&foo), MatchArm::Arm(0));
+ // path 1b
+ assert_eq!(test(&[Some(Test::Foo), Some(Test::Bar), Some(Test::Foo)]), MatchArm::Arm(0));
+ // path 2a
+ assert_eq!(test(&foo[..3]), MatchArm::Arm(1));
+ // path 2b
+ assert_eq!(test(&[Some(Test::Bar), Some(Test::Qux), Some(Test::Baz)]), MatchArm::Arm(1));
+ // path 3
+ assert_eq!(test(&foo[1..2]), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/or-patterns.rs b/tests/ui/pattern/bindings-after-at/or-patterns.rs
new file mode 100644
index 000000000..fcc361489
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/or-patterns.rs
@@ -0,0 +1,38 @@
+// Test bindings-after-at with or-patterns
+
+// run-pass
+
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(foo: Option<Test>) -> MatchArm {
+ match foo {
+ bar @ Some(Test::Foo | Test::Bar) => {
+ assert!(bar == Some(Test::Foo) || bar == Some(Test::Bar));
+
+ MatchArm::Arm(0)
+ },
+ Some(_) => MatchArm::Arm(1),
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ assert_eq!(test(Some(Test::Foo)), MatchArm::Arm(0));
+ assert_eq!(test(Some(Test::Bar)), MatchArm::Arm(0));
+ assert_eq!(test(Some(Test::Baz)), MatchArm::Arm(1));
+ assert_eq!(test(Some(Test::Qux)), MatchArm::Arm(1));
+ assert_eq!(test(None), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs
new file mode 100644
index 000000000..f167a3952
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs
@@ -0,0 +1,29 @@
+// Test that `binding @ subpat` acts as a product context with respect to duplicate binding names.
+// The code that is tested here lives in resolve (see `resolve_pattern_inner`).
+
+
+fn main() {
+ fn f(a @ a @ a: ()) {}
+ //~^ ERROR identifier `a` is bound more than once in this parameter list
+ //~| ERROR identifier `a` is bound more than once in this parameter list
+
+ match Ok(0) {
+ Ok(a @ b @ a)
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ | Err(a @ b @ a)
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ => {}
+ }
+
+ let a @ a @ a = ();
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+ let ref a @ ref a = ();
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ let ref mut a @ ref mut a = ();
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+
+ let a @ (Ok(a) | Err(a)) = Ok(());
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+}
diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
new file mode 100644
index 000000000..a165549f6
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
@@ -0,0 +1,64 @@
+error[E0415]: identifier `a` is bound more than once in this parameter list
+ --> $DIR/pat-at-same-name-both.rs:6:14
+ |
+LL | fn f(a @ a @ a: ()) {}
+ | ^ used as parameter more than once
+
+error[E0415]: identifier `a` is bound more than once in this parameter list
+ --> $DIR/pat-at-same-name-both.rs:6:18
+ |
+LL | fn f(a @ a @ a: ()) {}
+ | ^ used as parameter more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:11:20
+ |
+LL | Ok(a @ b @ a)
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:13:23
+ |
+LL | | Err(a @ b @ a)
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:18:13
+ |
+LL | let a @ a @ a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:18:17
+ |
+LL | let a @ a @ a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:21:21
+ |
+LL | let ref a @ ref a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:23:29
+ |
+LL | let ref mut a @ ref mut a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:26:17
+ |
+LL | let a @ (Ok(a) | Err(a)) = Ok(());
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:26:26
+ |
+LL | let a @ (Ok(a) | Err(a)) = Ok(());
+ | ^ used in a pattern more than once
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0415, E0416.
+For more information about an error, try `rustc --explain E0415`.
diff --git a/tests/ui/pattern/bindings-after-at/slice-patterns.rs b/tests/ui/pattern/bindings-after-at/slice-patterns.rs
new file mode 100644
index 000000000..4f4c96e45
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/slice-patterns.rs
@@ -0,0 +1,39 @@
+// Test bindings-after-at with slice-patterns
+
+// run-pass
+
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+fn test(foo: &[i32]) -> MatchArm {
+ match foo {
+ [bar @ .., n] if n == &5 => {
+ for i in bar {
+ assert!(i < &5);
+ }
+
+ MatchArm::Arm(0)
+ },
+ bar @ [x0, .., xn] => {
+ assert_eq!(x0, &1);
+ assert_eq!(x0, &1);
+ assert_eq!(xn, &4);
+ assert_eq!(bar, &[1, 2, 3, 4]);
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ let foo = vec![1, 2, 3, 4, 5];
+
+ assert_eq!(test(&foo), MatchArm::Arm(0));
+ assert_eq!(test(&foo[..4]), MatchArm::Arm(1));
+ assert_eq!(test(&foo[0..1]), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs
new file mode 100644
index 000000000..50ac0ef27
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs
@@ -0,0 +1,16 @@
+// Here we check that `_ @ sub` is syntactically invalid
+// and comes with a nice actionable suggestion.
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn wild_before_at_is_bad_syntax() {
+ let _ @ a = 0;
+ //~^ ERROR pattern on wrong side of `@`
+ let _ @ ref a = 0;
+ //~^ ERROR pattern on wrong side of `@`
+ let _ @ ref mut a = 0;
+ //~^ ERROR pattern on wrong side of `@`
+ let _ @ (a, .., b) = (0, 1, 2, 3);
+ //~^ ERROR left-hand side of `@` must be a binding
+}
diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr
new file mode 100644
index 000000000..2f4541584
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr
@@ -0,0 +1,43 @@
+error: pattern on wrong side of `@`
+ --> $DIR/wild-before-at-syntactically-rejected.rs:8:9
+ |
+LL | let _ @ a = 0;
+ | -^^^-
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `a @ _`
+
+error: pattern on wrong side of `@`
+ --> $DIR/wild-before-at-syntactically-rejected.rs:10:9
+ |
+LL | let _ @ ref a = 0;
+ | -^^^-----
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `ref a @ _`
+
+error: pattern on wrong side of `@`
+ --> $DIR/wild-before-at-syntactically-rejected.rs:12:9
+ |
+LL | let _ @ ref mut a = 0;
+ | -^^^---------
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `ref mut a @ _`
+
+error: left-hand side of `@` must be a binding
+ --> $DIR/wild-before-at-syntactically-rejected.rs:14:9
+ |
+LL | let _ @ (a, .., b) = (0, 1, 2, 3);
+ | -^^^----------
+ | | |
+ | | also a pattern
+ | interpreted as a pattern, not a binding
+ |
+ = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/pattern/for-loop-bad-item.rs b/tests/ui/pattern/for-loop-bad-item.rs
new file mode 100644
index 000000000..9a56a399b
--- /dev/null
+++ b/tests/ui/pattern/for-loop-bad-item.rs
@@ -0,0 +1,20 @@
+struct Qux(i32);
+
+fn bad() {
+ let mut map = std::collections::HashMap::new();
+ map.insert(('a', 'b'), ('c', 'd'));
+
+ for ((_, _), (&mut c, _)) in &mut map {
+ //~^ ERROR mismatched types
+ if c == 'e' {}
+ }
+}
+
+fn bad2() {
+ for Some(Qux(_)) | None in [Some(""), None] {
+ //~^ ERROR mismatched types
+ todo!();
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/for-loop-bad-item.stderr b/tests/ui/pattern/for-loop-bad-item.stderr
new file mode 100644
index 000000000..f064a25a9
--- /dev/null
+++ b/tests/ui/pattern/for-loop-bad-item.stderr
@@ -0,0 +1,32 @@
+error[E0308]: mismatched types
+ --> $DIR/for-loop-bad-item.rs:7:19
+ |
+LL | for ((_, _), (&mut c, _)) in &mut map {
+ | ^^^^^^ -------- this is an iterator with items of type `(&(char, char), &mut (char, char))`
+ | |
+ | expected `char`, found `&mut _`
+ |
+ = note: expected type `char`
+ found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut c`
+ --> $DIR/for-loop-bad-item.rs:7:19
+ |
+LL | for ((_, _), (&mut c, _)) in &mut map {
+ | ^^^^^^
+help: consider removing `&mut` from the pattern
+ |
+LL - for ((_, _), (&mut c, _)) in &mut map {
+LL + for ((_, _), (c, _)) in &mut map {
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/for-loop-bad-item.rs:14:14
+ |
+LL | for Some(Qux(_)) | None in [Some(""), None] {
+ | ^^^^^^ ---------------- this is an iterator with items of type `Option<&str>`
+ | |
+ | expected `str`, found struct `Qux`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/ignore-all-the-things.rs b/tests/ui/pattern/ignore-all-the-things.rs
new file mode 100644
index 000000000..5980e1a85
--- /dev/null
+++ b/tests/ui/pattern/ignore-all-the-things.rs
@@ -0,0 +1,44 @@
+// run-pass
+
+#![allow(non_shorthand_field_patterns)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo(isize, isize, isize, isize);
+struct Bar{a: isize, b: isize, c: isize, d: isize}
+
+pub fn main() {
+ let Foo(..) = Foo(5, 5, 5, 5);
+ let Foo(..) = Foo(5, 5, 5, 5);
+ let Bar{..} = Bar{a: 5, b: 5, c: 5, d: 5};
+ let (..) = (5, 5, 5, 5);
+ let Foo(a, b, ..) = Foo(5, 5, 5, 5);
+ let Foo(.., d) = Foo(5, 5, 5, 5);
+ let (a, b, ..) = (5, 5, 5, 5);
+ let (.., c, d) = (5, 5, 5, 5);
+ let Bar{b: b, ..} = Bar{a: 5, b: 5, c: 5, d: 5};
+ match [5, 5, 5, 5] {
+ [..] => { }
+ }
+ match [5, 5, 5, 5] {
+ [a, ..] => { }
+ }
+ match [5, 5, 5, 5] {
+ [.., b] => { }
+ }
+ match [5, 5, 5, 5] {
+ [a, .., b] => { }
+ }
+ match [5, 5, 5] {
+ [..] => { }
+ }
+ match [5, 5, 5] {
+ [a, ..] => { }
+ }
+ match [5, 5, 5] {
+ [.., a] => { }
+ }
+ match [5, 5, 5] {
+ [a, .., b] => { }
+ }
+}
diff --git a/tests/ui/pattern/integer-range-binding.rs b/tests/ui/pattern/integer-range-binding.rs
new file mode 100644
index 000000000..ff065882d
--- /dev/null
+++ b/tests/ui/pattern/integer-range-binding.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+fn main() {
+ let -2147483648..=2147483647 = 1;
+ let 0..=255 = 0u8;
+ let -128..=127 = 0i8;
+ let '\u{0000}'..='\u{10FFFF}' = 'v';
+}
diff --git a/tests/ui/pattern/issue-10392.rs b/tests/ui/pattern/issue-10392.rs
new file mode 100644
index 000000000..926fa9480
--- /dev/null
+++ b/tests/ui/pattern/issue-10392.rs
@@ -0,0 +1,30 @@
+// run-pass
+#![allow(unused_variables)]
+
+struct A { foo: isize }
+struct B { a: isize, b: isize, c: isize }
+
+fn mka() -> A { panic!() }
+fn mkb() -> B { panic!() }
+
+fn test() {
+ let A { foo, } = mka();
+ let A {
+ foo,
+ } = mka();
+
+ let B { a, b, c, } = mkb();
+
+ match mka() {
+ A { foo: _foo, } => {}
+ }
+
+ match Some(mka()) {
+ Some(A { foo: _foo, }) => {}
+ None => {}
+ }
+}
+
+pub fn main() {
+ if false { test() }
+}
diff --git a/tests/ui/pattern/issue-106552.rs b/tests/ui/pattern/issue-106552.rs
new file mode 100644
index 000000000..aa2c141e0
--- /dev/null
+++ b/tests/ui/pattern/issue-106552.rs
@@ -0,0 +1,7 @@
+fn main() {
+ let 5 = 6;
+ //~^ error refutable pattern in local binding [E0005]
+
+ let x @ 5 = 6;
+ //~^ error refutable pattern in local binding [E0005]
+}
diff --git a/tests/ui/pattern/issue-106552.stderr b/tests/ui/pattern/issue-106552.stderr
new file mode 100644
index 000000000..ed5d40c09
--- /dev/null
+++ b/tests/ui/pattern/issue-106552.stderr
@@ -0,0 +1,35 @@
+error[E0005]: refutable pattern in local binding
+ --> $DIR/issue-106552.rs:2:9
+ |
+LL | let 5 = 6;
+ | ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ = note: the matched value is of type `i32`
+help: you might want to use `if let` to ignore the variants that aren't matched
+ |
+LL | if let 5 = 6 { todo!() }
+ | ++ ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+ |
+LL | let _5 = 6;
+ | +
+
+error[E0005]: refutable pattern in local binding
+ --> $DIR/issue-106552.rs:5:9
+ |
+LL | let x @ 5 = 6;
+ | ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ = note: the matched value is of type `i32`
+help: you might want to use `let else` to handle the variants that aren't matched
+ |
+LL | let x @ 5 = 6 else { todo!() };
+ | ++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/pattern/issue-11577.rs b/tests/ui/pattern/issue-11577.rs
new file mode 100644
index 000000000..70177c5ed
--- /dev/null
+++ b/tests/ui/pattern/issue-11577.rs
@@ -0,0 +1,18 @@
+// run-pass
+// Destructuring struct variants would ICE where regular structs wouldn't
+
+enum Foo {
+ VBar { num: isize }
+}
+
+struct SBar { num: isize }
+
+pub fn main() {
+ let vbar = Foo::VBar { num: 1 };
+ let Foo::VBar { num } = vbar;
+ assert_eq!(num, 1);
+
+ let sbar = SBar { num: 2 };
+ let SBar { num } = sbar;
+ assert_eq!(num, 2);
+}
diff --git a/tests/ui/pattern/issue-12582.rs b/tests/ui/pattern/issue-12582.rs
new file mode 100644
index 000000000..f3366704e
--- /dev/null
+++ b/tests/ui/pattern/issue-12582.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+pub fn main() {
+ let x = 1;
+ let y = 2;
+
+ assert_eq!(3, match (x, y) {
+ (1, 1) => 1,
+ (2, 2) => 2,
+ (1..=2, 2) => 3,
+ _ => 4,
+ });
+
+ // nested tuple
+ assert_eq!(3, match ((x, y),) {
+ ((1, 1),) => 1,
+ ((2, 2),) => 2,
+ ((1..=2, 2),) => 3,
+ _ => 4,
+ });
+}
diff --git a/tests/ui/pattern/issue-14221.rs b/tests/ui/pattern/issue-14221.rs
new file mode 100644
index 000000000..13427d2c9
--- /dev/null
+++ b/tests/ui/pattern/issue-14221.rs
@@ -0,0 +1,21 @@
+#![deny(unreachable_patterns)]
+#![allow(unused_variables)]
+#![allow(non_snake_case)]
+
+pub enum E {
+ A,
+ B,
+}
+
+pub mod b {
+ pub fn key(e: ::E) -> &'static str {
+ match e {
+ A => "A",
+//~^ ERROR pattern binding `A` is named the same as one of the variants of the type `E`
+ B => "B", //~ ERROR: unreachable pattern
+//~^ ERROR pattern binding `B` is named the same as one of the variants of the type `E`
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/issue-14221.stderr b/tests/ui/pattern/issue-14221.stderr
new file mode 100644
index 000000000..7ea51b5f8
--- /dev/null
+++ b/tests/ui/pattern/issue-14221.stderr
@@ -0,0 +1,32 @@
+error[E0170]: pattern binding `A` is named the same as one of the variants of the type `E`
+ --> $DIR/issue-14221.rs:13:13
+ |
+LL | A => "A",
+ | ^ help: to match on the variant, qualify the path: `E::A`
+ |
+ = note: `#[deny(bindings_with_variant_name)]` on by default
+
+error[E0170]: pattern binding `B` is named the same as one of the variants of the type `E`
+ --> $DIR/issue-14221.rs:15:13
+ |
+LL | B => "B",
+ | ^ help: to match on the variant, qualify the path: `E::B`
+
+error: unreachable pattern
+ --> $DIR/issue-14221.rs:15:13
+ |
+LL | A => "A",
+ | - matches any value
+LL |
+LL | B => "B",
+ | ^ unreachable pattern
+ |
+note: the lint level is defined here
+ --> $DIR/issue-14221.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0170`.
diff --git a/tests/ui/pattern/issue-15080.rs b/tests/ui/pattern/issue-15080.rs
new file mode 100644
index 000000000..4dd6981d4
--- /dev/null
+++ b/tests/ui/pattern/issue-15080.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+fn main() {
+ let mut x: &[_] = &[1, 2, 3, 4];
+
+ let mut result = vec![];
+ loop {
+ x = match *x {
+ [1, n, 3, ref rest @ ..] => {
+ result.push(n);
+ rest
+ }
+ [n, ref rest @ ..] => {
+ result.push(n);
+ rest
+ }
+ [] =>
+ break
+ }
+ }
+ assert_eq!(result, [2, 4]);
+}
diff --git a/tests/ui/pattern/issue-17718-patterns.rs b/tests/ui/pattern/issue-17718-patterns.rs
new file mode 100644
index 000000000..2ca0f67f8
--- /dev/null
+++ b/tests/ui/pattern/issue-17718-patterns.rs
@@ -0,0 +1,12 @@
+static A1: usize = 1;
+static mut A2: usize = 1;
+const A3: usize = 1;
+
+fn main() {
+ match 1 {
+ A1 => {} //~ ERROR: match bindings cannot shadow statics
+ A2 => {} //~ ERROR: match bindings cannot shadow statics
+ A3 => {}
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/issue-17718-patterns.stderr b/tests/ui/pattern/issue-17718-patterns.stderr
new file mode 100644
index 000000000..109091c2a
--- /dev/null
+++ b/tests/ui/pattern/issue-17718-patterns.stderr
@@ -0,0 +1,21 @@
+error[E0530]: match bindings cannot shadow statics
+ --> $DIR/issue-17718-patterns.rs:7:9
+ |
+LL | static A1: usize = 1;
+ | --------------------- the static `A1` is defined here
+...
+LL | A1 => {}
+ | ^^ cannot be named the same as a static
+
+error[E0530]: match bindings cannot shadow statics
+ --> $DIR/issue-17718-patterns.rs:8:9
+ |
+LL | static mut A2: usize = 1;
+ | ------------------------- the static `A2` is defined here
+...
+LL | A2 => {}
+ | ^^ cannot be named the same as a static
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs
new file mode 100644
index 000000000..c26e457f9
--- /dev/null
+++ b/tests/ui/pattern/issue-22546.rs
@@ -0,0 +1,52 @@
+// run-pass
+#![allow(unused_variables)]
+// Parsing patterns with paths with type parameters (issue #22544)
+
+use std::default::Default;
+
+#[derive(Default)]
+pub struct Foo<T>(T, T);
+
+impl<T: ::std::fmt::Display> Foo<T> {
+ fn foo(&self) {
+ match *self {
+ Foo::<T>(ref x, ref y) => println!("Goodbye, World! {} {}", x, y)
+ }
+ }
+}
+
+trait Tr {
+ type U;
+}
+
+impl<T> Tr for Foo<T> {
+ type U = T;
+}
+
+struct Wrapper<T> {
+ value: T
+}
+
+fn main() {
+ let Foo::<i32>(a, b) = Default::default();
+
+ let f = Foo(2,3);
+ f.foo();
+
+ let w = Wrapper { value: Foo(10u8, 11u8) };
+ match w {
+ Wrapper::<Foo<u8>> { value: Foo(10, 11) } => {},
+ ::Wrapper::<<Foo<_> as Tr>::U> { value: Foo::<u8>(11, 16) } => { panic!() },
+ _ => { panic!() }
+ }
+
+ if let None::<u8> = Some(8) {
+ panic!();
+ }
+ if let None::<u8> { .. } = Some(8) {
+ panic!();
+ }
+ if let Option::None::<u8> { .. } = Some(8) {
+ panic!();
+ }
+}
diff --git a/tests/ui/pattern/issue-27320.rs b/tests/ui/pattern/issue-27320.rs
new file mode 100644
index 000000000..d1aa56b91
--- /dev/null
+++ b/tests/ui/pattern/issue-27320.rs
@@ -0,0 +1,15 @@
+// run-pass
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+macro_rules! piece(
+ ($piece:pat) => ($piece);
+);
+
+enum Piece {A, B}
+
+fn main() {
+ match Piece::A {
+ piece!(pt@ Piece::A) | piece!(pt@ Piece::B) => {}
+ }
+}
diff --git a/tests/ui/pattern/issue-52240.rs b/tests/ui/pattern/issue-52240.rs
new file mode 100644
index 000000000..5def55778
--- /dev/null
+++ b/tests/ui/pattern/issue-52240.rs
@@ -0,0 +1,16 @@
+// issue-52240: Can turn immutable into mut with `ref mut`
+
+enum Foo {
+ Bar(i32),
+}
+
+fn main() {
+ let arr = vec!(Foo::Bar(0));
+ if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
+ //~^ ERROR cannot borrow data in a `&` reference as mutable
+ *val = 9001;
+ }
+ match arr[0] {
+ Foo::Bar(ref s) => println!("{}", s)
+ }
+}
diff --git a/tests/ui/pattern/issue-52240.stderr b/tests/ui/pattern/issue-52240.stderr
new file mode 100644
index 000000000..69b663b17
--- /dev/null
+++ b/tests/ui/pattern/issue-52240.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/issue-52240.rs:9:27
+ |
+LL | if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) {
+ | ^^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/pattern/issue-6449.rs b/tests/ui/pattern/issue-6449.rs
new file mode 100644
index 000000000..bfd4c1232
--- /dev/null
+++ b/tests/ui/pattern/issue-6449.rs
@@ -0,0 +1,44 @@
+// run-pass
+#![allow(dead_code)]
+
+enum Foo {
+ Bar(isize),
+ Baz,
+}
+
+enum Other {
+ Other1(Foo),
+ Other2(Foo, Foo),
+}
+
+fn main() {
+ match Foo::Baz {
+ ::Foo::Bar(3) => panic!(),
+ ::Foo::Bar(_) if false => panic!(),
+ ::Foo::Bar(..) if false => panic!(),
+ ::Foo::Bar(_n) => panic!(),
+ ::Foo::Baz => {}
+ }
+ match Foo::Bar(3) {
+ ::Foo::Bar(3) => {}
+ ::Foo::Bar(_) if false => panic!(),
+ ::Foo::Bar(..) if false => panic!(),
+ ::Foo::Bar(_n) => panic!(),
+ ::Foo::Baz => panic!(),
+ }
+ match Foo::Bar(4) {
+ ::Foo::Bar(3) => panic!(),
+ ::Foo::Bar(_) if false => panic!(),
+ ::Foo::Bar(..) if false => panic!(),
+ ::Foo::Bar(n) => assert_eq!(n, 4),
+ ::Foo::Baz => panic!(),
+ }
+
+ match Other::Other1(Foo::Baz) {
+ ::Other::Other1(::Foo::Baz) => {}
+ ::Other::Other1(::Foo::Bar(_)) => {}
+ ::Other::Other2(::Foo::Baz, ::Foo::Bar(_)) => {}
+ ::Other::Other2(::Foo::Bar(..), ::Foo::Baz) => {}
+ ::Other::Other2(..) => {}
+ }
+}
diff --git a/tests/ui/pattern/issue-66270-pat-struct-parser-recovery.rs b/tests/ui/pattern/issue-66270-pat-struct-parser-recovery.rs
new file mode 100644
index 000000000..48a8e0482
--- /dev/null
+++ b/tests/ui/pattern/issue-66270-pat-struct-parser-recovery.rs
@@ -0,0 +1,14 @@
+// Regression test for #66270, fixed by #66246
+
+struct Bug {
+ incorrect_field: 0,
+ //~^ ERROR expected type
+}
+
+struct Empty {}
+
+fn main() {
+ let Bug {
+ any_field: Empty {},
+ } = Bug {};
+}
diff --git a/tests/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr b/tests/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr
new file mode 100644
index 000000000..f40642f30
--- /dev/null
+++ b/tests/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr
@@ -0,0 +1,10 @@
+error: expected type, found `0`
+ --> $DIR/issue-66270-pat-struct-parser-recovery.rs:4:22
+ |
+LL | struct Bug {
+ | --- while parsing this struct
+LL | incorrect_field: 0,
+ | ^ expected type
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs b/tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
new file mode 100644
index 000000000..ae28c1403
--- /dev/null
+++ b/tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
@@ -0,0 +1,21 @@
+// Regression test for #67037.
+//
+// In type checking patterns, E0023 occurs when the tuple pattern and the expected
+// tuple pattern have different number of fields. For example, as below, `P()`,
+// the tuple struct pattern, has 0 fields, but requires 1 field.
+//
+// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
+// the scrutinee was of type `Some((a, b, c))`, and suggest that parentheses be added.
+//
+// However, we did not account for the expected type being different than the tuple pattern type.
+// This caused an issue when the tuple pattern type (`P<T>`) was generic.
+// Specifically, we tried deriving the 0th field's type using the `substs` of the expected type.
+// When attempting to substitute `T`, there was no such substitution, so "out of range" occurred.
+
+struct U {} // 0 type parameters offered
+struct P<T>(T); // 1 type parameter wanted
+
+fn main() {
+ let P() = U {}; //~ ERROR mismatched types
+ //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 1 field
+}
diff --git a/tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
new file mode 100644
index 000000000..75a231f6b
--- /dev/null
+++ b/tests/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+ |
+LL | let P() = U {};
+ | ^^^ ---- this expression has type `U`
+ | |
+ | expected struct `U`, found struct `P`
+ |
+ = note: expected struct `U`
+ found struct `P<_>`
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 1 field
+ --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+ |
+LL | struct P<T>(T); // 1 type parameter wanted
+ | - tuple struct has 1 field
+...
+LL | let P() = U {};
+ | ^^^ expected 1 field, found 0
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | let P(_) = U {};
+ | +
+help: use `..` to ignore all fields
+ |
+LL | let P(..) = U {};
+ | ++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0023, E0308.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs
new file mode 100644
index 000000000..05d097eaf
--- /dev/null
+++ b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs
@@ -0,0 +1,40 @@
+// Test for issue #67776: binding named the same as enum variant
+// should report an error even when matching against a reference type
+
+#![allow(unused_variables)]
+#![allow(non_snake_case)]
+
+enum Foo {
+ Bar,
+ Baz,
+}
+
+
+fn fn1(e: Foo) {
+ match e {
+ Bar => {},
+ //~^ ERROR named the same as one of the variants of the type `Foo`
+ Baz => {},
+ //~^ ERROR named the same as one of the variants of the type `Foo`
+ }
+}
+
+fn fn2(e: &Foo) {
+ match e {
+ Bar => {},
+ //~^ ERROR named the same as one of the variants of the type `Foo`
+ Baz => {},
+ //~^ ERROR named the same as one of the variants of the type `Foo`
+ }
+}
+
+fn fn3(e: &mut &&mut Foo) {
+ match e {
+ Bar => {},
+ //~^ ERROR named the same as one of the variants of the type `Foo`
+ Baz => {},
+ //~^ ERROR named the same as one of the variants of the type `Foo`
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr
new file mode 100644
index 000000000..da580c7ac
--- /dev/null
+++ b/tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr
@@ -0,0 +1,41 @@
+error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+ --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:15:9
+ |
+LL | Bar => {},
+ | ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
+ |
+ = note: `#[deny(bindings_with_variant_name)]` on by default
+
+error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+ --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:17:9
+ |
+LL | Baz => {},
+ | ^^^ help: to match on the variant, qualify the path: `Foo::Baz`
+
+error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+ --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:24:9
+ |
+LL | Bar => {},
+ | ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
+
+error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+ --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:26:9
+ |
+LL | Baz => {},
+ | ^^^ help: to match on the variant, qualify the path: `Foo::Baz`
+
+error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+ --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:33:9
+ |
+LL | Bar => {},
+ | ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
+
+error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+ --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:35:9
+ |
+LL | Baz => {},
+ | ^^^ help: to match on the variant, qualify the path: `Foo::Baz`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0170`.
diff --git a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.rs b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.rs
new file mode 100644
index 000000000..95ead6b5d
--- /dev/null
+++ b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.rs
@@ -0,0 +1,26 @@
+pub enum EFoo {
+ A,
+}
+
+pub trait Foo {
+ const X: EFoo;
+}
+
+struct Abc;
+
+impl Foo for Abc {
+ const X: EFoo = EFoo::A;
+}
+
+struct Def;
+impl Foo for Def {
+ const X: EFoo = EFoo::A;
+}
+
+pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
+ //~^ ERROR associated consts cannot be referenced in patterns
+ let A::X = arg;
+ //~^ ERROR associated consts cannot be referenced in patterns
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr
new file mode 100644
index 000000000..54ecc2498
--- /dev/null
+++ b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr
@@ -0,0 +1,15 @@
+error[E0158]: associated consts cannot be referenced in patterns
+ --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40
+ |
+LL | pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
+ | ^^^^
+
+error[E0158]: associated consts cannot be referenced in patterns
+ --> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9
+ |
+LL | let A::X = arg;
+ | ^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0158`.
diff --git a/tests/ui/pattern/issue-72565.rs b/tests/ui/pattern/issue-72565.rs
new file mode 100644
index 000000000..1e262fd50
--- /dev/null
+++ b/tests/ui/pattern/issue-72565.rs
@@ -0,0 +1,8 @@
+const F: &'static dyn PartialEq<u32> = &7u32;
+
+fn main() {
+ let a: &dyn PartialEq<u32> = &7u32;
+ match a {
+ F => panic!(), //~ ERROR: `&dyn PartialEq<u32>` cannot be used in patterns
+ }
+}
diff --git a/tests/ui/pattern/issue-72565.stderr b/tests/ui/pattern/issue-72565.stderr
new file mode 100644
index 000000000..2f82616b2
--- /dev/null
+++ b/tests/ui/pattern/issue-72565.stderr
@@ -0,0 +1,8 @@
+error: `&dyn PartialEq<u32>` cannot be used in patterns
+ --> $DIR/issue-72565.rs:6:9
+ |
+LL | F => panic!(),
+ | ^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/issue-72574-1.rs b/tests/ui/pattern/issue-72574-1.rs
new file mode 100644
index 000000000..1b80a2179
--- /dev/null
+++ b/tests/ui/pattern/issue-72574-1.rs
@@ -0,0 +1,10 @@
+fn main() {
+ let x = (1, 2, 3);
+ match x {
+ (_a, _x @ ..) => {}
+ _ => {}
+ }
+}
+//~^^^^ ERROR `_x @` is not allowed in a tuple
+//~| ERROR: `..` patterns are not allowed here
+//~| ERROR: mismatched types
diff --git a/tests/ui/pattern/issue-72574-1.stderr b/tests/ui/pattern/issue-72574-1.stderr
new file mode 100644
index 000000000..653869a23
--- /dev/null
+++ b/tests/ui/pattern/issue-72574-1.stderr
@@ -0,0 +1,34 @@
+error: `_x @` is not allowed in a tuple
+ --> $DIR/issue-72574-1.rs:4:14
+ |
+LL | (_a, _x @ ..) => {}
+ | ^^^^^^^ this is only allowed in slice patterns
+ |
+ = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of _x, discard the tuple's remaining fields
+ |
+LL | (_a, ..) => {}
+ | ~~
+
+error: `..` patterns are not allowed here
+ --> $DIR/issue-72574-1.rs:4:19
+ |
+LL | (_a, _x @ ..) => {}
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0308]: mismatched types
+ --> $DIR/issue-72574-1.rs:4:9
+ |
+LL | match x {
+ | - this expression has type `({integer}, {integer}, {integer})`
+LL | (_a, _x @ ..) => {}
+ | ^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements
+ |
+ = note: expected tuple `({integer}, {integer}, {integer})`
+ found tuple `(_, _)`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/issue-72574-2.rs b/tests/ui/pattern/issue-72574-2.rs
new file mode 100644
index 000000000..0ad2db848
--- /dev/null
+++ b/tests/ui/pattern/issue-72574-2.rs
@@ -0,0 +1,12 @@
+struct Binder(i32, i32, i32);
+
+fn main() {
+ let x = Binder(1, 2, 3);
+ match x {
+ Binder(_a, _x @ ..) => {}
+ _ => {}
+ }
+}
+//~^^^^ ERROR `_x @` is not allowed in a tuple struct
+//~| ERROR: `..` patterns are not allowed here
+//~| ERROR: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
diff --git a/tests/ui/pattern/issue-72574-2.stderr b/tests/ui/pattern/issue-72574-2.stderr
new file mode 100644
index 000000000..05650f05c
--- /dev/null
+++ b/tests/ui/pattern/issue-72574-2.stderr
@@ -0,0 +1,37 @@
+error: `_x @` is not allowed in a tuple struct
+ --> $DIR/issue-72574-2.rs:6:20
+ |
+LL | Binder(_a, _x @ ..) => {}
+ | ^^^^^^^ this is only allowed in slice patterns
+ |
+ = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of _x, discard the tuple's remaining fields
+ |
+LL | Binder(_a, ..) => {}
+ | ~~
+
+error: `..` patterns are not allowed here
+ --> $DIR/issue-72574-2.rs:6:25
+ |
+LL | Binder(_a, _x @ ..) => {}
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/issue-72574-2.rs:6:16
+ |
+LL | struct Binder(i32, i32, i32);
+ | --- --- --- tuple struct has 3 fields
+...
+LL | Binder(_a, _x @ ..) => {}
+ | ^^ ^^^^^^^ expected 3 fields, found 2
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | Binder(_a, _x @ .., _) => {}
+ | +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0023`.
diff --git a/tests/ui/pattern/issue-74539.rs b/tests/ui/pattern/issue-74539.rs
new file mode 100644
index 000000000..0b25f87ec
--- /dev/null
+++ b/tests/ui/pattern/issue-74539.rs
@@ -0,0 +1,15 @@
+enum E {
+ A(u8, u8),
+}
+
+fn main() {
+ let e = E::A(2, 3);
+ match e {
+ E::A(x @ ..) => {
+ //~^ ERROR: `x @` is not allowed in a tuple struct
+ //~| ERROR: `..` patterns are not allowed here
+ //~| ERROR: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ x
+ }
+ };
+}
diff --git a/tests/ui/pattern/issue-74539.stderr b/tests/ui/pattern/issue-74539.stderr
new file mode 100644
index 000000000..7443946c0
--- /dev/null
+++ b/tests/ui/pattern/issue-74539.stderr
@@ -0,0 +1,37 @@
+error: `x @` is not allowed in a tuple struct
+ --> $DIR/issue-74539.rs:8:14
+ |
+LL | E::A(x @ ..) => {
+ | ^^^^^^ this is only allowed in slice patterns
+ |
+ = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of x, discard the tuple's remaining fields
+ |
+LL | E::A(..) => {
+ | ~~
+
+error: `..` patterns are not allowed here
+ --> $DIR/issue-74539.rs:8:18
+ |
+LL | E::A(x @ ..) => {
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ --> $DIR/issue-74539.rs:8:14
+ |
+LL | A(u8, u8),
+ | -- -- tuple variant has 2 fields
+...
+LL | E::A(x @ ..) => {
+ | ^^^^^^ expected 2 fields, found 1
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E::A(x @ .., _) => {
+ | +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0023`.
diff --git a/tests/ui/pattern/issue-74702.rs b/tests/ui/pattern/issue-74702.rs
new file mode 100644
index 000000000..0aeb3b217
--- /dev/null
+++ b/tests/ui/pattern/issue-74702.rs
@@ -0,0 +1,7 @@
+fn main() {
+ let (foo @ ..,) = (0, 0);
+ //~^ ERROR: `foo @` is not allowed in a tuple
+ //~| ERROR: `..` patterns are not allowed here
+ //~| ERROR: mismatched types
+ dbg!(foo);
+}
diff --git a/tests/ui/pattern/issue-74702.stderr b/tests/ui/pattern/issue-74702.stderr
new file mode 100644
index 000000000..f2e2c8f02
--- /dev/null
+++ b/tests/ui/pattern/issue-74702.stderr
@@ -0,0 +1,34 @@
+error: `foo @` is not allowed in a tuple
+ --> $DIR/issue-74702.rs:2:10
+ |
+LL | let (foo @ ..,) = (0, 0);
+ | ^^^^^^^^ this is only allowed in slice patterns
+ |
+ = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of foo, discard the tuple's remaining fields
+ |
+LL | let (..,) = (0, 0);
+ | ~~
+
+error: `..` patterns are not allowed here
+ --> $DIR/issue-74702.rs:2:16
+ |
+LL | let (foo @ ..,) = (0, 0);
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0308]: mismatched types
+ --> $DIR/issue-74702.rs:2:9
+ |
+LL | let (foo @ ..,) = (0, 0);
+ | ^^^^^^^^^^^ ------ this expression has type `({integer}, {integer})`
+ | |
+ | expected a tuple with 2 elements, found one with 1 element
+ |
+ = note: expected tuple `({integer}, {integer})`
+ found tuple `(_,)`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/issue-74954.rs b/tests/ui/pattern/issue-74954.rs
new file mode 100644
index 000000000..269ec3c7a
--- /dev/null
+++ b/tests/ui/pattern/issue-74954.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+fn main() {
+ if let Some([b'@', filename @ ..]) = Some(b"@abc123") {
+ println!("filename {:?}", filename);
+ }
+}
diff --git a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.rs b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.rs
new file mode 100644
index 000000000..a5e9b1db5
--- /dev/null
+++ b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.rs
@@ -0,0 +1,9 @@
+// Regression test for correct pretty-printing of an AST representing `&(mut x)` in help
+// suggestion diagnostic.
+
+fn main() {
+ let mut &x = &0;
+ //~^ ERROR `mut` must be attached to each individual binding
+ //~| HELP add `mut` to each binding
+ //~| SUGGESTION &(mut x)
+}
diff --git a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr
new file mode 100644
index 000000000..75b6c163b
--- /dev/null
+++ b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr
@@ -0,0 +1,10 @@
+error: `mut` must be attached to each individual binding
+ --> $DIR/issue-80186-mut-binding-help-suggestion.rs:5:9
+ |
+LL | let mut &x = &0;
+ | ^^^^^^ help: add `mut` to each binding: `&(mut x)`
+ |
+ = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/issue-8351-1.rs b/tests/ui/pattern/issue-8351-1.rs
new file mode 100644
index 000000000..139f027cb
--- /dev/null
+++ b/tests/ui/pattern/issue-8351-1.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![allow(dead_code)]
+
+enum E {
+ Foo{f: isize},
+ Bar,
+}
+
+pub fn main() {
+ let e = E::Foo{f: 0};
+ match e {
+ E::Foo{f: 1} => panic!(),
+ E::Foo{..} => (),
+ _ => panic!(),
+ }
+}
diff --git a/tests/ui/pattern/issue-8351-2.rs b/tests/ui/pattern/issue-8351-2.rs
new file mode 100644
index 000000000..bc66cbb77
--- /dev/null
+++ b/tests/ui/pattern/issue-8351-2.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![allow(dead_code)]
+
+enum E {
+ Foo{f: isize, b: bool},
+ Bar,
+}
+
+pub fn main() {
+ let e = E::Foo{f: 0, b: false};
+ match e {
+ E::Foo{f: 1, b: true} => panic!(),
+ E::Foo{b: false, f: 0} => (),
+ _ => panic!(),
+ }
+}
diff --git a/tests/ui/pattern/issue-88074-pat-range-type-inference-err.rs b/tests/ui/pattern/issue-88074-pat-range-type-inference-err.rs
new file mode 100644
index 000000000..16df272df
--- /dev/null
+++ b/tests/ui/pattern/issue-88074-pat-range-type-inference-err.rs
@@ -0,0 +1,28 @@
+trait Zero {
+ const ZERO: Self;
+}
+
+impl Zero for String {
+ const ZERO: Self = String::new();
+}
+
+fn foo() {
+ match String::new() {
+ Zero::ZERO ..= Zero::ZERO => {},
+ //~^ ERROR only `char` and numeric types are allowed in range patterns
+ _ => {},
+ }
+}
+
+fn bar() {
+ match Zero::ZERO {
+ Zero::ZERO ..= Zero::ZERO => {},
+ //~^ ERROR type annotations needed [E0282]
+ _ => {},
+ }
+}
+
+fn main() {
+ foo();
+ bar();
+}
diff --git a/tests/ui/pattern/issue-88074-pat-range-type-inference-err.stderr b/tests/ui/pattern/issue-88074-pat-range-type-inference-err.stderr
new file mode 100644
index 000000000..8e528f8c1
--- /dev/null
+++ b/tests/ui/pattern/issue-88074-pat-range-type-inference-err.stderr
@@ -0,0 +1,19 @@
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/issue-88074-pat-range-type-inference-err.rs:11:9
+ |
+LL | Zero::ZERO ..= Zero::ZERO => {},
+ | ----------^^^^^----------
+ | | |
+ | | this is of type `String` but it should be `char` or numeric
+ | this is of type `String` but it should be `char` or numeric
+
+error[E0282]: type annotations needed
+ --> $DIR/issue-88074-pat-range-type-inference-err.rs:19:9
+ |
+LL | Zero::ZERO ..= Zero::ZERO => {},
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0029, E0282.
+For more information about an error, try `rustc --explain E0029`.
diff --git a/tests/ui/pattern/issue-88074-pat-range-type-inference.rs b/tests/ui/pattern/issue-88074-pat-range-type-inference.rs
new file mode 100644
index 000000000..27db7d8c7
--- /dev/null
+++ b/tests/ui/pattern/issue-88074-pat-range-type-inference.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+trait Zero {
+ const ZERO: Self;
+}
+
+impl Zero for i32 {
+ const ZERO: Self = 0;
+}
+
+fn main() {
+ match 1 {
+ Zero::ZERO ..= 1 => {},
+ _ => {},
+ }
+}
diff --git a/tests/ui/pattern/issue-92074-macro-ice.rs b/tests/ui/pattern/issue-92074-macro-ice.rs
new file mode 100644
index 000000000..039d3b314
--- /dev/null
+++ b/tests/ui/pattern/issue-92074-macro-ice.rs
@@ -0,0 +1,36 @@
+pub enum En {
+ A(Vec<u8>)
+}
+
+fn get_usize() -> usize {
+ 0
+}
+
+macro_rules! force_expr {
+ ($e:expr) => { $e }
+}
+
+macro_rules! force_pat {
+ ($a:expr, $b:expr) => { $a..=$b }
+}
+
+macro_rules! make_vec {
+ () => { force_expr!(Vec::new()) } //~ ERROR arbitrary expressions aren't allowed
+}
+
+macro_rules! make_pat {
+ () => { force_pat!(get_usize(), get_usize()) }
+ //~^ ERROR arbitrary expressions aren't allowed
+ //~| ERROR arbitrary expressions aren't allowed
+}
+
+#[allow(unreachable_code)]
+fn f() -> Result<(), impl core::fmt::Debug> {
+ let x: En = loop {};
+
+ assert!(matches!(x, En::A(make_vec!())));
+ assert!(matches!(5, make_pat!()));
+ Ok::<(), &'static str>(())
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/issue-92074-macro-ice.stderr b/tests/ui/pattern/issue-92074-macro-ice.stderr
new file mode 100644
index 000000000..b340afff0
--- /dev/null
+++ b/tests/ui/pattern/issue-92074-macro-ice.stderr
@@ -0,0 +1,35 @@
+error: arbitrary expressions aren't allowed in patterns
+ --> $DIR/issue-92074-macro-ice.rs:18:25
+ |
+LL | () => { force_expr!(Vec::new()) }
+ | ^^^^^^^^^^
+...
+LL | assert!(matches!(x, En::A(make_vec!())));
+ | ----------- in this macro invocation
+ |
+ = note: this error originates in the macro `make_vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: arbitrary expressions aren't allowed in patterns
+ --> $DIR/issue-92074-macro-ice.rs:22:24
+ |
+LL | () => { force_pat!(get_usize(), get_usize()) }
+ | ^^^^^^^^^^^
+...
+LL | assert!(matches!(5, make_pat!()));
+ | ----------- in this macro invocation
+ |
+ = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: arbitrary expressions aren't allowed in patterns
+ --> $DIR/issue-92074-macro-ice.rs:22:37
+ |
+LL | () => { force_pat!(get_usize(), get_usize()) }
+ | ^^^^^^^^^^^
+...
+LL | assert!(matches!(5, make_pat!()));
+ | ----------- in this macro invocation
+ |
+ = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/pattern/issue-95878.rs b/tests/ui/pattern/issue-95878.rs
new file mode 100644
index 000000000..f59814468
--- /dev/null
+++ b/tests/ui/pattern/issue-95878.rs
@@ -0,0 +1,12 @@
+struct Foo<'a>(&'a ());
+
+impl<'a> Foo<'a> {
+ fn spam(&mut self, baz: &mut Vec<u32>) {
+ match 15 {
+ ref Self => (),
+ //~^ ERROR expected identifier, found keyword `Self`
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/issue-95878.stderr b/tests/ui/pattern/issue-95878.stderr
new file mode 100644
index 000000000..e0eea06e0
--- /dev/null
+++ b/tests/ui/pattern/issue-95878.stderr
@@ -0,0 +1,8 @@
+error: expected identifier, found keyword `Self`
+ --> $DIR/issue-95878.rs:6:17
+ |
+LL | ref Self => (),
+ | ^^^^ expected identifier, found keyword
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
new file mode 100644
index 000000000..5445696fd
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+fn main() {}
+
+struct U;
+
+fn slice() {
+ let mut arr = [U, U, U, U, U, U, U, U];
+ let [ref _x0, _x1, _, mut _x3, .., ref _x6, _x7] = arr;
+ _x3 = U;
+ let [ref mut _x0, _, ref _x2, _, _x4, ref mut _x5, _x6, _] = arr;
+ *_x5 = U;
+ let [_, _, _x2, _, _, _x5, _, _] = arr;
+ *_x0 = U;
+ let [ref _x0, ..] = arr;
+ let [_x0, ..] = arr;
+}
+
+fn tuple() {
+ let mut tup = (U, U, U, U, U);
+ let (ref _x0, mut _x1, ref _x2, ..) = tup;
+ _x1 = U;
+ let (ref mut _x0, _, _, ref _x3, _x4) = tup;
+ let (_, _, _, _x3, _) = tup;
+ *_x0 = U;
+ drop(_x2);
+ drop(tup.2);
+ let (_x0, _, _, ..) = tup;
+}
diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
new file mode 100644
index 000000000..a6144c949
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
@@ -0,0 +1,48 @@
+fn main() {}
+
+struct U;
+
+fn slice() {
+ let mut arr = [U, U, U, U, U];
+ let hold_all = &arr;
+ let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; //~ ERROR cannot move out of `arr[..]`
+ _x1 = U; //~ ERROR cannot assign twice to immutable variable `_x1`
+ drop(hold_all);
+ let [_x0, ..] = arr; //~ ERROR cannot move out of `arr[..]`
+ drop(_x0_hold);
+ let [_, _, ref mut _x2, _x3, mut _x4] = arr;
+ //~^ ERROR cannot borrow `arr[..]` as mutable
+ //~| ERROR cannot move out of `arr[..]` because it is borrowed
+ //~| ERROR cannot move out of `arr[..]` because it is borrowed
+ drop(xs_hold);
+}
+
+fn tuple() {
+ let mut tup = (U, U, U, U);
+ let (ref _x0, _x1, ref _x2, ..) = tup;
+ _x1 = U; //~ ERROR cannot assign twice to immutable variable
+ let _x0_hold = &mut tup.0; //~ ERROR cannot borrow `tup.0` as mutable because it is also
+ let (ref mut _x0_hold, ..) = tup; //~ ERROR cannot borrow `tup.0` as mutable because it is also
+ *_x0 = U; //~ ERROR cannot assign to `*_x0`, which is behind a `&` reference
+ *_x2 = U; //~ ERROR cannot assign to `*_x2`, which is behind a `&` reference
+ drop(tup.1); //~ ERROR use of moved value: `tup.1`
+ let _x1_hold = &tup.1; //~ ERROR borrow of moved value: `tup.1`
+ let (.., ref mut _x3) = tup;
+ let _x3_hold = &tup.3; //~ ERROR cannot borrow `tup.3` as immutable
+ let _x3_hold = &mut tup.3; //~ ERROR cannot borrow `tup.3` as mutable more
+ let (.., ref mut _x4_hold) = tup; //~ ERROR cannot borrow `tup.3` as mutable more
+ let (.., ref _x4_hold) = tup; //~ ERROR cannot borrow `tup.3` as immutable
+ drop(_x3);
+}
+
+fn closure() {
+ let mut tup = (U, U, U);
+ let c1 = || {
+ let (ref _x0, _x1, _) = tup;
+ };
+ let c2 = || {
+ //~^ ERROR use of moved value
+ let (ref mut _x0, _, _x2) = tup;
+ };
+ drop(c1);
+}
diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
new file mode 100644
index 000000000..1b93267b3
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -0,0 +1,216 @@
+error[E0505]: cannot move out of `arr[..]` because it is borrowed
+ --> $DIR/borrowck-move-ref-pattern.rs:8:24
+ |
+LL | let hold_all = &arr;
+ | ---- borrow of `arr` occurs here
+LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
+ | ^^^ move out of `arr[..]` occurs here
+LL | _x1 = U;
+LL | drop(hold_all);
+ | -------- borrow later used here
+
+error[E0384]: cannot assign twice to immutable variable `_x1`
+ --> $DIR/borrowck-move-ref-pattern.rs:9:5
+ |
+LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
+ | ---
+ | |
+ | first assignment to `_x1`
+ | help: consider making this binding mutable: `mut _x1`
+LL | _x1 = U;
+ | ^^^^^^^ cannot assign twice to immutable variable
+
+error[E0505]: cannot move out of `arr[..]` because it is borrowed
+ --> $DIR/borrowck-move-ref-pattern.rs:11:10
+ |
+LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
+ | ------------ borrow of `arr[..]` occurs here
+...
+LL | let [_x0, ..] = arr;
+ | ^^^ move out of `arr[..]` occurs here
+LL | drop(_x0_hold);
+ | -------- borrow later used here
+
+error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-move-ref-pattern.rs:13:16
+ |
+LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
+ | ----------- immutable borrow occurs here
+...
+LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr;
+ | ^^^^^^^^^^^ mutable borrow occurs here
+...
+LL | drop(xs_hold);
+ | ------- immutable borrow later used here
+
+error[E0505]: cannot move out of `arr[..]` because it is borrowed
+ --> $DIR/borrowck-move-ref-pattern.rs:13:29
+ |
+LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
+ | ----------- borrow of `arr[..]` occurs here
+...
+LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr;
+ | ^^^ move out of `arr[..]` occurs here
+...
+LL | drop(xs_hold);
+ | ------- borrow later used here
+
+error[E0505]: cannot move out of `arr[..]` because it is borrowed
+ --> $DIR/borrowck-move-ref-pattern.rs:13:34
+ |
+LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
+ | ----------- borrow of `arr[..]` occurs here
+...
+LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr;
+ | ^^^^^^^ move out of `arr[..]` occurs here
+...
+LL | drop(xs_hold);
+ | ------- borrow later used here
+
+error[E0384]: cannot assign twice to immutable variable `_x1`
+ --> $DIR/borrowck-move-ref-pattern.rs:23:5
+ |
+LL | let (ref _x0, _x1, ref _x2, ..) = tup;
+ | ---
+ | |
+ | first assignment to `_x1`
+ | help: consider making this binding mutable: `mut _x1`
+LL | _x1 = U;
+ | ^^^^^^^ cannot assign twice to immutable variable
+
+error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-move-ref-pattern.rs:24:20
+ |
+LL | let (ref _x0, _x1, ref _x2, ..) = tup;
+ | ------- immutable borrow occurs here
+LL | _x1 = U;
+LL | let _x0_hold = &mut tup.0;
+ | ^^^^^^^^^^ mutable borrow occurs here
+LL | let (ref mut _x0_hold, ..) = tup;
+LL | *_x0 = U;
+ | -------- immutable borrow later used here
+
+error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-move-ref-pattern.rs:25:10
+ |
+LL | let (ref _x0, _x1, ref _x2, ..) = tup;
+ | ------- immutable borrow occurs here
+...
+LL | let (ref mut _x0_hold, ..) = tup;
+ | ^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | *_x0 = U;
+ | -------- immutable borrow later used here
+
+error[E0594]: cannot assign to `*_x0`, which is behind a `&` reference
+ --> $DIR/borrowck-move-ref-pattern.rs:26:5
+ |
+LL | *_x0 = U;
+ | ^^^^^^^^ `_x0` 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 _x0, _x1, ref _x2, ..) = tup;
+ | ~~~~~~~~~~~
+
+error[E0594]: cannot assign to `*_x2`, which is behind a `&` reference
+ --> $DIR/borrowck-move-ref-pattern.rs:27:5
+ |
+LL | *_x2 = U;
+ | ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written
+ |
+help: consider changing this to be a mutable reference
+ |
+LL | let (ref _x0, _x1, ref mut _x2, ..) = tup;
+ | ~~~~~~~~~~~
+
+error[E0382]: use of moved value: `tup.1`
+ --> $DIR/borrowck-move-ref-pattern.rs:28:10
+ |
+LL | let (ref _x0, _x1, ref _x2, ..) = tup;
+ | --- value moved here
+...
+LL | drop(tup.1);
+ | ^^^^^ value used here after move
+ |
+ = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let (ref _x0, ref _x1, ref _x2, ..) = tup;
+ | +++
+
+error[E0382]: borrow of moved value: `tup.1`
+ --> $DIR/borrowck-move-ref-pattern.rs:29:20
+ |
+LL | drop(tup.1);
+ | ----- value moved here
+LL | let _x1_hold = &tup.1;
+ | ^^^^^^ value borrowed here after move
+ |
+ = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
+
+error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-move-ref-pattern.rs:31:20
+ |
+LL | let (.., ref mut _x3) = tup;
+ | ----------- mutable borrow occurs here
+LL | let _x3_hold = &tup.3;
+ | ^^^^^^ immutable borrow occurs here
+...
+LL | drop(_x3);
+ | --- mutable borrow later used here
+
+error[E0499]: cannot borrow `tup.3` as mutable more than once at a time
+ --> $DIR/borrowck-move-ref-pattern.rs:32:20
+ |
+LL | let (.., ref mut _x3) = tup;
+ | ----------- first mutable borrow occurs here
+LL | let _x3_hold = &tup.3;
+LL | let _x3_hold = &mut tup.3;
+ | ^^^^^^^^^^ second mutable borrow occurs here
+...
+LL | drop(_x3);
+ | --- first borrow later used here
+
+error[E0499]: cannot borrow `tup.3` as mutable more than once at a time
+ --> $DIR/borrowck-move-ref-pattern.rs:33:14
+ |
+LL | let (.., ref mut _x3) = tup;
+ | ----------- first mutable borrow occurs here
+...
+LL | let (.., ref mut _x4_hold) = tup;
+ | ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
+LL | let (.., ref _x4_hold) = tup;
+LL | drop(_x3);
+ | --- first borrow later used here
+
+error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-move-ref-pattern.rs:34:14
+ |
+LL | let (.., ref mut _x3) = tup;
+ | ----------- mutable borrow occurs here
+...
+LL | let (.., ref _x4_hold) = tup;
+ | ^^^^^^^^^^^^ immutable borrow occurs here
+LL | drop(_x3);
+ | --- mutable borrow later used here
+
+error[E0382]: use of moved value: `tup`
+ --> $DIR/borrowck-move-ref-pattern.rs:43:14
+ |
+LL | let mut tup = (U, U, U);
+ | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait
+LL | let c1 = || {
+ | -- value moved into closure here
+LL | let (ref _x0, _x1, _) = tup;
+ | --- variable moved due to use in closure
+LL | };
+LL | let c2 = || {
+ | ^^ value used here after move
+LL |
+LL | let (ref mut _x0, _, _x2) = tup;
+ | --- use occurs due to use in closure
+
+error: aborting due to 18 previous errors
+
+Some errors have detailed explanations: E0382, E0384, E0499, E0502, E0505, E0594.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
new file mode 100644
index 000000000..ff7b625a6
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
@@ -0,0 +1,12 @@
+// When conflicts between by-move bindings in `by_move_1 @ has_by_move` patterns
+// happen and that code is unreachable according to borrowck, we accept this code.
+// In particular, we want to ensure here that an ICE does not happen, which it did originally.
+
+// check-pass
+
+fn main() {
+ return;
+
+ struct S;
+ let a @ (b, c) = (S, S);
+}
diff --git a/tests/ui/pattern/move-ref-patterns/issue-53840.rs b/tests/ui/pattern/move-ref-patterns/issue-53840.rs
new file mode 100644
index 000000000..80effc497
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/issue-53840.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+enum E {
+ Foo(String, String, String),
+}
+
+struct Bar {
+ a: String,
+ b: String,
+}
+
+fn main() {
+ let bar = Bar { a: "1".to_string(), b: "2".to_string() };
+ match E::Foo("".into(), "".into(), "".into()) {
+ E::Foo(a, b, ref c) => {}
+ }
+ match bar {
+ Bar { a, ref b } => {}
+ }
+}
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
new file mode 100644
index 000000000..ebb1683af
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
@@ -0,0 +1,120 @@
+fn main() {
+ struct S; // Not `Copy`.
+
+ let mut tup0 = (S, S);
+ let mut tup1 = (S, S, S);
+ let tup2 = (S, S);
+ let tup3 = (S, S, S);
+ let tup4 = (S, S);
+ let mut arr0 = [S, S, S];
+ let mut arr1 = [S, S, S, S, S];
+ let arr2 = [S, S, S];
+ let arr3 = [S, S, S, S, S];
+
+ // The `mov` bindings require that we capture the scrutinees by-move.
+ let mut closure = || {
+ // Tuples...
+ let (ref mut borrow, mov) = tup0;
+ let (mov, _, ref mut borrow) = tup1;
+ let (ref borrow, mov) = tup2;
+ let (mov, _, ref borrow) = tup3;
+ let (ref borrow, mov) = tup4;
+ // Arrays...
+ let [mov @ .., ref borrow] = arr0;
+ let [_, ref mut borrow @ .., _, mov] = arr1;
+ let [mov @ .., ref borrow] = arr2;
+ let [_, ref borrow @ .., _, mov] = arr3;
+ };
+
+ // Now we try to borrow and move the captures, which should result in errors...
+ // ...for tuples:
+ drop(&tup0); //~ ERROR borrow of moved value: `tup0`
+ drop(&tup1); //~ ERROR borrow of moved value: `tup1`
+ drop(&tup2); //~ ERROR borrow of moved value: `tup2`
+ drop(&tup3); //~ ERROR borrow of moved value: `tup3`
+ // Ostensibly this should compile.
+ // However, because closures don't capture individual fields, which is changed in RFC 2229,
+ // this won't compile because the entire product is moved into the closure.
+ // The same applies to the array patterns below.
+ drop(&tup4.0); //~ ERROR borrow of moved value: `tup4`
+ // ...for arrays:
+ drop(&arr0); //~ ERROR borrow of moved value: `arr0`
+ let [_, mov1, mov2, mov3, _] = &arr1; //~ ERROR borrow of moved value: `arr1`
+ drop(&arr2); //~ ERROR borrow of moved value: `arr2`
+ let [_, mov1, mov2, mov3, _] = &arr3; //~ ERROR borrow of moved value: `arr3`
+
+ // Let's redo ^--- with a `match` + sum type:
+ macro_rules! m {
+ ($p:pat = $s:expr) => {
+ match $s {
+ Some($p) => {}
+ _ => {}
+ }
+ };
+ }
+ let mut tup0: Option<(S, S)> = None;
+ let mut tup1: Option<(S, S, S)> = None;
+ let tup2: Option<(S, S)> = None;
+ let tup3: Option<(S, S, S)> = None;
+ let tup4: Option<(S, S)> = None;
+ let mut arr0: Option<[S; 3]> = None;
+ let mut arr1: Option<[S; 5]> = None;
+ let arr2: Option<[S; 3]> = None;
+ let arr3: Option<[S; 5]> = None;
+ let mut closure = || {
+ m!((ref mut borrow, mov) = tup0);
+ m!((mov, _, ref mut borrow) = tup1);
+ m!((ref borrow, mov) = tup2);
+ m!((mov, _, ref borrow) = tup3);
+ m!((ref borrow, mov) = tup4);
+ m!([mov @ .., ref borrow] = arr0);
+ m!([_, ref mut borrow @ .., _, mov] = arr1);
+ m!([mov @ .., ref borrow] = arr2);
+ m!([_, ref borrow @ .., _, mov] = arr3);
+ };
+ drop(&tup0); //~ ERROR borrow of moved value: `tup0`
+ drop(&tup1); //~ ERROR borrow of moved value: `tup1`
+ drop(&tup2); //~ ERROR borrow of moved value: `tup2`
+ drop(&tup3); //~ ERROR borrow of moved value: `tup3`
+ m!((ref x, _) = &tup4); //~ ERROR borrow of moved value: `tup4`
+ drop(&arr0); //~ ERROR borrow of moved value: `arr0`
+ m!([_, mov1, mov2, mov3, _] = &arr1); //~ ERROR borrow of moved value: `arr1`
+ drop(&arr2); //~ ERROR borrow of moved value: `arr2`
+ m!([_, mov1, mov2, mov3, _] = &arr3); //~ ERROR borrow of moved value: `arr3`
+
+ // Let's redo ^--- with `if let` (which may diverge from `match` in the future):
+ macro_rules! m {
+ ($p:pat = $s:expr) => {
+ if let Some($p) = $s {}
+ };
+ }
+ let mut tup0: Option<(S, S)> = None;
+ let mut tup1: Option<(S, S, S)> = None;
+ let tup2: Option<(S, S)> = None;
+ let tup3: Option<(S, S, S)> = None;
+ let tup4: Option<(S, S)> = None;
+ let mut arr0: Option<[S; 3]> = None;
+ let mut arr1: Option<[S; 5]> = None;
+ let arr2: Option<[S; 3]> = None;
+ let arr3: Option<[S; 5]> = None;
+ let mut closure = || {
+ m!((ref mut borrow, mov) = tup0);
+ m!((mov, _, ref mut borrow) = tup1);
+ m!((ref borrow, mov) = tup2);
+ m!((mov, _, ref borrow) = tup3);
+ m!((ref borrow, mov) = tup4);
+ m!([mov @ .., ref borrow] = arr0);
+ m!([_, ref mut borrow @ .., _, mov] = arr1);
+ m!([mov @ .., ref borrow] = arr2);
+ m!([_, ref borrow @ .., _, mov] = arr3);
+ };
+ drop(&tup0); //~ ERROR borrow of moved value: `tup0`
+ drop(&tup1); //~ ERROR borrow of moved value: `tup1`
+ drop(&tup2); //~ ERROR borrow of moved value: `tup2`
+ drop(&tup3); //~ ERROR borrow of moved value: `tup3`
+ m!((ref x, _) = &tup4); //~ ERROR borrow of moved value: `tup4`
+ drop(&arr0); //~ ERROR borrow of moved value: `arr0`
+ m!([_, mov1, mov2, mov3, _] = &arr1); //~ ERROR borrow of moved value: `arr1`
+ drop(&arr2); //~ ERROR borrow of moved value: `arr2`
+ m!([_, mov1, mov2, mov3, _] = &arr3); //~ ERROR borrow of moved value: `arr3`
+}
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
new file mode 100644
index 000000000..f19fed089
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
@@ -0,0 +1,404 @@
+error[E0382]: borrow of moved value: `tup0`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10
+ |
+LL | let mut tup0 = (S, S);
+ | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+LL | // Tuples...
+LL | let (ref mut borrow, mov) = tup0;
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup0);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup1`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10
+ |
+LL | let mut tup1 = (S, S, S);
+ | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let (mov, _, ref mut borrow) = tup1;
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup1);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup2`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10
+ |
+LL | let tup2 = (S, S);
+ | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let (ref borrow, mov) = tup2;
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup2);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup3`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10
+ |
+LL | let tup3 = (S, S, S);
+ | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let (mov, _, ref borrow) = tup3;
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup3);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup4`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10
+ |
+LL | let tup4 = (S, S);
+ | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let (ref borrow, mov) = tup4;
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup4.0);
+ | ^^^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr0`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10
+ |
+LL | let mut arr0 = [S, S, S];
+ | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let [mov @ .., ref borrow] = arr0;
+ | ---- variable moved due to use in closure
+...
+LL | drop(&arr0);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr1`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36
+ |
+LL | let mut arr1 = [S, S, S, S, S];
+ | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let [_, ref mut borrow @ .., _, mov] = arr1;
+ | ---- variable moved due to use in closure
+...
+LL | let [_, mov1, mov2, mov3, _] = &arr1;
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr2`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10
+ |
+LL | let arr2 = [S, S, S];
+ | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let [mov @ .., ref borrow] = arr2;
+ | ---- variable moved due to use in closure
+...
+LL | drop(&arr2);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr3`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36
+ |
+LL | let arr3 = [S, S, S, S, S];
+ | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | let [_, ref borrow @ .., _, mov] = arr3;
+ | ---- variable moved due to use in closure
+...
+LL | let [_, mov1, mov2, mov3, _] = &arr3;
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup0`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10
+ |
+LL | let mut tup0: Option<(S, S)> = None;
+ | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+LL | m!((ref mut borrow, mov) = tup0);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup0);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup1`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10
+ |
+LL | let mut tup1: Option<(S, S, S)> = None;
+ | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+LL | m!((ref mut borrow, mov) = tup0);
+LL | m!((mov, _, ref mut borrow) = tup1);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup1);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup2`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10
+ |
+LL | let tup2: Option<(S, S)> = None;
+ | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!((ref borrow, mov) = tup2);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup2);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup3`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10
+ |
+LL | let tup3: Option<(S, S, S)> = None;
+ | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!((mov, _, ref borrow) = tup3);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup3);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup4`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21
+ |
+LL | let tup4: Option<(S, S)> = None;
+ | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!((ref borrow, mov) = tup4);
+ | ---- variable moved due to use in closure
+...
+LL | m!((ref x, _) = &tup4);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr0`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10
+ |
+LL | let mut arr0: Option<[S; 3]> = None;
+ | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([mov @ .., ref borrow] = arr0);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&arr0);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr1`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35
+ |
+LL | let mut arr1: Option<[S; 5]> = None;
+ | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([_, ref mut borrow @ .., _, mov] = arr1);
+ | ---- variable moved due to use in closure
+...
+LL | m!([_, mov1, mov2, mov3, _] = &arr1);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr2`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10
+ |
+LL | let arr2: Option<[S; 3]> = None;
+ | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
+LL | let arr3: Option<[S; 5]> = None;
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([mov @ .., ref borrow] = arr2);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&arr2);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr3`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35
+ |
+LL | let arr3: Option<[S; 5]> = None;
+ | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([_, ref borrow @ .., _, mov] = arr3);
+ | ---- variable moved due to use in closure
+...
+LL | m!([_, mov1, mov2, mov3, _] = &arr3);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup0`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10
+ |
+LL | let mut tup0: Option<(S, S)> = None;
+ | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+LL | m!((ref mut borrow, mov) = tup0);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup0);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup1`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10
+ |
+LL | let mut tup1: Option<(S, S, S)> = None;
+ | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+LL | m!((ref mut borrow, mov) = tup0);
+LL | m!((mov, _, ref mut borrow) = tup1);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup1);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup2`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10
+ |
+LL | let tup2: Option<(S, S)> = None;
+ | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!((ref borrow, mov) = tup2);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup2);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup3`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10
+ |
+LL | let tup3: Option<(S, S, S)> = None;
+ | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!((mov, _, ref borrow) = tup3);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&tup3);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `tup4`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21
+ |
+LL | let tup4: Option<(S, S)> = None;
+ | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!((ref borrow, mov) = tup4);
+ | ---- variable moved due to use in closure
+...
+LL | m!((ref x, _) = &tup4);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr0`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10
+ |
+LL | let mut arr0: Option<[S; 3]> = None;
+ | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([mov @ .., ref borrow] = arr0);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&arr0);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr1`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35
+ |
+LL | let mut arr1: Option<[S; 5]> = None;
+ | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
+...
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([_, ref mut borrow @ .., _, mov] = arr1);
+ | ---- variable moved due to use in closure
+...
+LL | m!([_, mov1, mov2, mov3, _] = &arr1);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr2`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10
+ |
+LL | let arr2: Option<[S; 3]> = None;
+ | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
+LL | let arr3: Option<[S; 5]> = None;
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([mov @ .., ref borrow] = arr2);
+ | ---- variable moved due to use in closure
+...
+LL | drop(&arr2);
+ | ^^^^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `arr3`
+ --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35
+ |
+LL | let arr3: Option<[S; 5]> = None;
+ | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
+LL | let mut closure = || {
+ | -- value moved into closure here
+...
+LL | m!([_, ref borrow @ .., _, mov] = arr3);
+ | ---- variable moved due to use in closure
+...
+LL | m!([_, mov1, mov2, mov3, _] = &arr3);
+ | ^^^^^ value borrowed here after move
+
+error: aborting due to 27 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
new file mode 100644
index 000000000..583f70f41
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
@@ -0,0 +1,28 @@
+// check-pass
+
+fn main() {
+ struct U;
+ fn accept_fn_once(_: impl FnOnce()) {}
+ fn accept_fn_mut(_: impl FnMut()) {}
+ fn accept_fn(_: impl Fn()) {}
+
+ let mut tup = (U, U, U);
+ let (ref _x0, _x1, ref mut _x2) = tup;
+ let c1 = || {
+ drop::<&U>(_x0);
+ drop::<U>(_x1);
+ drop::<&mut U>(_x2);
+ };
+ accept_fn_once(c1);
+
+ let c2 = || {
+ drop::<&U>(_x0);
+ drop::<&mut U>(_x2);
+ };
+ accept_fn_mut(c2);
+
+ let c3 = || {
+ drop::<&U>(_x0);
+ };
+ accept_fn(c3);
+}
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
new file mode 100644
index 000000000..cd619cc41
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
@@ -0,0 +1,32 @@
+fn main() {
+ struct U;
+ fn accept_fn_once(_: &impl FnOnce()) {}
+ fn accept_fn_mut(_: &impl FnMut()) {}
+ fn accept_fn(_: &impl Fn()) {}
+
+ let mut tup = (U, U, U);
+ let (ref _x0, _x1, ref mut _x2) = tup;
+ let c1 = || {
+ //~^ ERROR expected a closure that implements the `FnMut`
+ //~| ERROR expected a closure that implements the `Fn`
+ drop::<&U>(_x0);
+ drop::<U>(_x1);
+ drop::<&mut U>(_x2);
+ };
+ accept_fn_once(&c1);
+ accept_fn_mut(&c1);
+ accept_fn(&c1);
+
+ let c2 = || {
+ //~^ ERROR expected a closure that implements the `Fn`
+ drop::<&U>(_x0);
+ drop::<&mut U>(_x2);
+ };
+ accept_fn_mut(&c2);
+ accept_fn(&c2);
+
+ let c3 = || {
+ drop::<&U>(_x0);
+ };
+ accept_fn(&c3);
+}
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
new file mode 100644
index 000000000..eba65a618
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
@@ -0,0 +1,63 @@
+error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
+ --> $DIR/move-ref-patterns-closure-captures.rs:9:14
+ |
+LL | let c1 = || {
+ | ^^ this closure implements `FnOnce`, not `FnMut`
+...
+LL | drop::<U>(_x1);
+ | --- closure is `FnOnce` because it moves the variable `_x1` out of its environment
+...
+LL | accept_fn_mut(&c1);
+ | ------------- --- the requirement to implement `FnMut` derives from here
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `accept_fn_mut`
+ --> $DIR/move-ref-patterns-closure-captures.rs:4:31
+ |
+LL | fn accept_fn_mut(_: &impl FnMut()) {}
+ | ^^^^^^^ required by this bound in `accept_fn_mut`
+
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+ --> $DIR/move-ref-patterns-closure-captures.rs:9:14
+ |
+LL | let c1 = || {
+ | ^^ this closure implements `FnOnce`, not `Fn`
+...
+LL | drop::<U>(_x1);
+ | --- closure is `FnOnce` because it moves the variable `_x1` out of its environment
+...
+LL | accept_fn(&c1);
+ | --------- --- the requirement to implement `Fn` derives from here
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `accept_fn`
+ --> $DIR/move-ref-patterns-closure-captures.rs:5:27
+ |
+LL | fn accept_fn(_: &impl Fn()) {}
+ | ^^^^ required by this bound in `accept_fn`
+
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
+ --> $DIR/move-ref-patterns-closure-captures.rs:20:14
+ |
+LL | let c2 = || {
+ | ^^ this closure implements `FnMut`, not `Fn`
+...
+LL | drop::<&mut U>(_x2);
+ | --- closure is `FnMut` because it mutates the variable `_x2` here
+...
+LL | accept_fn(&c2);
+ | --------- --- the requirement to implement `Fn` derives from here
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `accept_fn`
+ --> $DIR/move-ref-patterns-closure-captures.rs:5:27
+ |
+LL | fn accept_fn(_: &impl Fn()) {}
+ | ^^^^ required by this bound in `accept_fn`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed
new file mode 100644
index 000000000..5f04fc83d
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed
@@ -0,0 +1,12 @@
+// run-rustfix
+#![allow(unused_variables)]
+fn main() {
+ struct U;
+
+ // A tuple is a "non-reference pattern".
+ // A `mut` binding pattern resets the binding mode to by-value.
+
+ let mut p = (U, U);
+ let (a, ref mut b) = &mut p;
+ //~^ ERROR cannot move out of a mutable reference
+}
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs
new file mode 100644
index 000000000..5dc1ae2fe
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs
@@ -0,0 +1,12 @@
+// run-rustfix
+#![allow(unused_variables)]
+fn main() {
+ struct U;
+
+ // A tuple is a "non-reference pattern".
+ // A `mut` binding pattern resets the binding mode to by-value.
+
+ let mut p = (U, U);
+ let (a, mut b) = &mut p;
+ //~^ ERROR cannot move out of a mutable reference
+}
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr
new file mode 100644
index 000000000..d3ab533e3
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr
@@ -0,0 +1,17 @@
+error[E0507]: cannot move out of a mutable reference
+ --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:10:22
+ |
+LL | let (a, mut b) = &mut p;
+ | ----- ^^^^^^
+ | |
+ | data moved here
+ | move occurs because `b` has type `U`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let (a, ref mut b) = &mut p;
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
new file mode 100644
index 000000000..6c913c245
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
@@ -0,0 +1,10 @@
+fn main() {
+ struct U;
+
+ // A tuple is a "non-reference pattern".
+ // A `mut` binding pattern resets the binding mode to by-value.
+
+ let p = (U, U);
+ let (a, mut b) = &p;
+ //~^ ERROR cannot move out of a shared reference
+}
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
new file mode 100644
index 000000000..65030b622
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
@@ -0,0 +1,17 @@
+error[E0507]: cannot move out of a shared reference
+ --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22
+ |
+LL | let (a, mut b) = &p;
+ | ----- ^^
+ | |
+ | data moved here
+ | move occurs because `b` has type `U`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let (a, ref mut b) = &p;
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
new file mode 100644
index 000000000..1d6d9acea
--- /dev/null
+++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
@@ -0,0 +1,79 @@
+// run-pass
+
+// This test checks the dynamic semantics and drop order of pattern matching
+// where a product pattern has both a by-move and by-ref binding.
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+struct X {
+ x: Box<usize>,
+ d: DropOrderListPtr,
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<usize>>>;
+
+impl Drop for X {
+ fn drop(&mut self) {
+ self.d.borrow_mut().push(*self.x);
+ }
+}
+
+enum DoubleOption<T, U> {
+ Some2(T, U),
+ _None2,
+}
+
+fn main() {
+ let d: DropOrderListPtr = <_>::default();
+ {
+ let mk = |v| X { x: Box::new(v), d: d.clone() };
+ let check = |a1: &X, a2, b1: &X, b2| {
+ assert_eq!(*a1.x, a2);
+ assert_eq!(*b1.x, b2);
+ };
+
+ let x = DoubleOption::Some2(mk(1), mk(2));
+ match x {
+ DoubleOption::Some2(ref a, b) => check(a, 1, &b, 2),
+ DoubleOption::_None2 => panic!(),
+ }
+ let x = DoubleOption::Some2(mk(3), mk(4));
+ match x {
+ DoubleOption::Some2(a, ref b) => check(&a, 3, b, 4),
+ DoubleOption::_None2 => panic!(),
+ }
+ match DoubleOption::Some2(mk(5), mk(6)) {
+ DoubleOption::Some2(ref a, b) => check(a, 5, &b, 6),
+ DoubleOption::_None2 => panic!(),
+ }
+ match DoubleOption::Some2(mk(7), mk(8)) {
+ DoubleOption::Some2(a, ref b) => check(&a, 7, b, 8),
+ DoubleOption::_None2 => panic!(),
+ }
+ {
+ let (a, ref b) = (mk(9), mk(10));
+ let (ref c, d) = (mk(11), mk(12));
+ check(&a, 9, b, 10);
+ check(c, 11, &d, 12);
+ }
+ fn fun([a, ref mut b, ref xs @ .., ref c, d]: [X; 6]) {
+ assert_eq!(*a.x, 13);
+ assert_eq!(*b.x, 14);
+ assert_eq!(&[*xs[0].x, *xs[1].x], &[15, 16]);
+ assert_eq!(*c.x, 17);
+ assert_eq!(*d.x, 18);
+ }
+ fun([mk(13), mk(14), mk(15), mk(16), mk(17), mk(18)]);
+
+ let lam = |(a, ref b, c, ref mut d): (X, X, X, X)| {
+ assert_eq!(*a.x, 19);
+ assert_eq!(*b.x, 20);
+ assert_eq!(*c.x, 21);
+ assert_eq!(*d.x, 22);
+ };
+ lam((mk(19), mk(20), mk(21), mk(22)));
+ }
+ let expected = [2, 3, 6, 5, 7, 8, 12, 11, 9, 10, 18, 13, 14, 15, 16, 17, 21, 19, 20, 22, 4, 1];
+ assert_eq!(&*d.borrow(), &expected);
+}
diff --git a/tests/ui/pattern/non-constant-in-const-path.rs b/tests/ui/pattern/non-constant-in-const-path.rs
new file mode 100644
index 000000000..3918485ba
--- /dev/null
+++ b/tests/ui/pattern/non-constant-in-const-path.rs
@@ -0,0 +1,18 @@
+// Checks if we emit `PatternError`s correctly.
+// This is also a regression test for #27895 and #68394.
+
+static FOO: u8 = 10;
+
+fn main() {
+ let x = 0;
+ let 0u8..=x = 0;
+ //~^ ERROR: runtime values cannot be referenced in patterns
+ let 0u8..=FOO = 0;
+ //~^ ERROR: statics cannot be referenced in patterns
+ match 1 {
+ 0 ..= x => {}
+ //~^ ERROR: runtime values cannot be referenced in patterns
+ 0 ..= FOO => {}
+ //~^ ERROR: statics cannot be referenced in patterns
+ };
+}
diff --git a/tests/ui/pattern/non-constant-in-const-path.stderr b/tests/ui/pattern/non-constant-in-const-path.stderr
new file mode 100644
index 000000000..53c3974f7
--- /dev/null
+++ b/tests/ui/pattern/non-constant-in-const-path.stderr
@@ -0,0 +1,28 @@
+error[E0080]: runtime values cannot be referenced in patterns
+ --> $DIR/non-constant-in-const-path.rs:8:15
+ |
+LL | let 0u8..=x = 0;
+ | ^
+
+error[E0158]: statics cannot be referenced in patterns
+ --> $DIR/non-constant-in-const-path.rs:10:15
+ |
+LL | let 0u8..=FOO = 0;
+ | ^^^
+
+error[E0080]: runtime values cannot be referenced in patterns
+ --> $DIR/non-constant-in-const-path.rs:13:15
+ |
+LL | 0 ..= x => {}
+ | ^
+
+error[E0158]: statics cannot be referenced in patterns
+ --> $DIR/non-constant-in-const-path.rs:15:15
+ |
+LL | 0 ..= FOO => {}
+ | ^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0080, E0158.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs
new file mode 100644
index 000000000..5c3315473
--- /dev/null
+++ b/tests/ui/pattern/non-structural-match-types.rs
@@ -0,0 +1,14 @@
+// edition:2021
+#![allow(incomplete_features)]
+#![allow(unreachable_code)]
+#![feature(const_async_blocks)]
+#![feature(inline_const_pat)]
+
+fn main() {
+ match loop {} {
+ const { || {} } => {}, //~ ERROR cannot be used in patterns
+ }
+ match loop {} {
+ const { async {} } => {}, //~ ERROR cannot be used in patterns
+ }
+}
diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr
new file mode 100644
index 000000000..dea7c4695
--- /dev/null
+++ b/tests/ui/pattern/non-structural-match-types.stderr
@@ -0,0 +1,14 @@
+error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:19]` cannot be used in patterns
+ --> $DIR/non-structural-match-types.rs:9:9
+ |
+LL | const { || {} } => {},
+ | ^^^^^^^^^^^^^^^
+
+error: `[async block@$DIR/non-structural-match-types.rs:12:17: 12:25]` cannot be used in patterns
+ --> $DIR/non-structural-match-types.rs:12:9
+ |
+LL | const { async {} } => {},
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/pattern/pat-shadow-in-nested-binding.rs b/tests/ui/pattern/pat-shadow-in-nested-binding.rs
new file mode 100644
index 000000000..7badbb6b9
--- /dev/null
+++ b/tests/ui/pattern/pat-shadow-in-nested-binding.rs
@@ -0,0 +1,6 @@
+#[allow(non_camel_case_types)]
+struct foo(usize);
+
+fn main() {
+ let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow tuple structs
+}
diff --git a/tests/ui/pattern/pat-shadow-in-nested-binding.stderr b/tests/ui/pattern/pat-shadow-in-nested-binding.stderr
new file mode 100644
index 000000000..0c5824be9
--- /dev/null
+++ b/tests/ui/pattern/pat-shadow-in-nested-binding.stderr
@@ -0,0 +1,12 @@
+error[E0530]: let bindings cannot shadow tuple structs
+ --> $DIR/pat-shadow-in-nested-binding.rs:5:10
+ |
+LL | struct foo(usize);
+ | ------------------ the tuple struct `foo` is defined here
+...
+LL | let (foo, _) = (2, 3);
+ | ^^^ cannot be named the same as a tuple struct
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0530`.
diff --git a/tests/ui/pattern/pat-struct-field-expr-has-type.rs b/tests/ui/pattern/pat-struct-field-expr-has-type.rs
new file mode 100644
index 000000000..1d18214de
--- /dev/null
+++ b/tests/ui/pattern/pat-struct-field-expr-has-type.rs
@@ -0,0 +1,9 @@
+struct S {
+ f: u8,
+}
+
+fn main() {
+ match (S { f: 42 }) {
+ S { f: Ok(_) } => {} //~ ERROR mismatched types
+ }
+}
diff --git a/tests/ui/pattern/pat-struct-field-expr-has-type.stderr b/tests/ui/pattern/pat-struct-field-expr-has-type.stderr
new file mode 100644
index 000000000..3a61d4293
--- /dev/null
+++ b/tests/ui/pattern/pat-struct-field-expr-has-type.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+ --> $DIR/pat-struct-field-expr-has-type.rs:7:16
+ |
+LL | match (S { f: 42 }) {
+ | ------------- this expression has type `S`
+LL | S { f: Ok(_) } => {}
+ | ^^^^^ expected `u8`, found enum `Result`
+ |
+ = note: expected type `u8`
+ found enum `Result<_, _>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/pat-tuple-bad-type.rs b/tests/ui/pattern/pat-tuple-bad-type.rs
new file mode 100644
index 000000000..98481167a
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-bad-type.rs
@@ -0,0 +1,15 @@
+fn main() {
+ let x; //~ ERROR type annotations needed
+
+ match x {
+ (..) => {}
+ _ => {}
+ }
+
+ match 0u8 {
+ (..) => {} //~ ERROR mismatched types
+ _ => {}
+ }
+
+ x = 10;
+}
diff --git a/tests/ui/pattern/pat-tuple-bad-type.stderr b/tests/ui/pattern/pat-tuple-bad-type.stderr
new file mode 100644
index 000000000..da369d333
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-bad-type.stderr
@@ -0,0 +1,26 @@
+error[E0282]: type annotations needed
+ --> $DIR/pat-tuple-bad-type.rs:2:9
+ |
+LL | let x;
+ | ^
+...
+LL | (..) => {}
+ | ---- type must be known at this point
+ |
+help: consider giving `x` an explicit type
+ |
+LL | let x: /* Type */;
+ | ++++++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/pat-tuple-bad-type.rs:10:9
+ |
+LL | match 0u8 {
+ | --- this expression has type `u8`
+LL | (..) => {}
+ | ^^^^ expected `u8`, found `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0308.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/pattern/pat-tuple-field-count-cross.rs b/tests/ui/pattern/pat-tuple-field-count-cross.rs
new file mode 100644
index 000000000..b63da4e15
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-field-count-cross.rs
@@ -0,0 +1,57 @@
+// aux-build:declarations-for-tuple-field-count-errors.rs
+
+extern crate declarations_for_tuple_field_count_errors;
+
+use declarations_for_tuple_field_count_errors::*;
+
+fn main() {
+ match Z0 {
+ Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0`
+ Z0(x) => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0`
+ }
+ match Z1() {
+ Z1 => {} //~ ERROR match bindings cannot shadow tuple structs
+ Z1(x) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 0 fields
+ }
+
+ match S(1, 2, 3) {
+ S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple struct has 3 fields
+ S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields
+ S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+ S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ }
+ match M(1, 2, 3) {
+ M() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple struct has 3 fields
+ M(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields
+ M(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+ M(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ }
+
+ match E1::Z0 {
+ E1::Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ E1::Z0(x) => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ }
+ match E1::Z1() {
+ E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1`
+ E1::Z1(x) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 0 fields
+ }
+ match E1::S(1, 2, 3) {
+ E1::S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields
+ E1::S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields
+ E1::S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields
+ E1::S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields
+ }
+
+ match E2::S(1, 2, 3) {
+ E2::S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields
+ E2::S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields
+ E2::S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields
+ E2::S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields
+ }
+ match E2::M(1, 2, 3) {
+ E2::M() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields
+ E2::M(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields
+ E2::M(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields
+ E2::M(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields
+ }
+}
diff --git a/tests/ui/pattern/pat-tuple-field-count-cross.stderr b/tests/ui/pattern/pat-tuple-field-count-cross.stderr
new file mode 100644
index 000000000..d92957461
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-field-count-cross.stderr
@@ -0,0 +1,531 @@
+error[E0530]: match bindings cannot shadow tuple structs
+ --> $DIR/pat-tuple-field-count-cross.rs:13:9
+ |
+LL | use declarations_for_tuple_field_count_errors::*;
+ | -------------------------------------------- the tuple struct `Z1` is imported here
+...
+LL | Z1 => {}
+ | ^^
+ | |
+ | cannot be named the same as a tuple struct
+ | help: try specify the pattern arguments: `Z1(..)`
+
+error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0`
+ --> $DIR/pat-tuple-field-count-cross.rs:9:9
+ |
+LL | Z0() => {}
+ | ^^^^
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:1:1
+ |
+LL | pub struct Z0;
+ | ------------- `Z0` defined here
+LL | pub struct Z1();
+ | ------------- similarly named tuple struct `Z1` defined here
+ |
+help: use this syntax instead
+ |
+LL | Z0 => {}
+ | ~~
+help: a tuple struct with a similar name exists
+ |
+LL | Z1() => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0`
+ --> $DIR/pat-tuple-field-count-cross.rs:10:9
+ |
+LL | Z0(x) => {}
+ | ^^^^^
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:1:1
+ |
+LL | pub struct Z0;
+ | ------------- `Z0` defined here
+LL | pub struct Z1();
+ | ------------- similarly named tuple struct `Z1` defined here
+ |
+help: use this syntax instead
+ |
+LL | Z0 => {}
+ | ~~
+help: a tuple struct with a similar name exists
+ |
+LL | Z1(x) => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ --> $DIR/pat-tuple-field-count-cross.rs:31:9
+ |
+LL | E1::Z0() => {}
+ | ^^^^^^^^
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- -- similarly named tuple variant `Z1` defined here
+ | |
+ | `E1::Z0` defined here
+ |
+help: use this syntax instead
+ |
+LL | E1::Z0 => {}
+ | ~~~~~~
+help: a tuple variant with a similar name exists
+ |
+LL | E1::Z1() => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ --> $DIR/pat-tuple-field-count-cross.rs:32:9
+ |
+LL | E1::Z0(x) => {}
+ | ^^^^^^^^^
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- -- similarly named tuple variant `Z1` defined here
+ | |
+ | `E1::Z0` defined here
+ |
+help: use this syntax instead
+ |
+LL | E1::Z0 => {}
+ | ~~~~~~
+help: a tuple variant with a similar name exists
+ |
+LL | E1::Z1(x) => {}
+ | ~~
+
+error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E1::Z1`
+ --> $DIR/pat-tuple-field-count-cross.rs:35:9
+ |
+LL | E1::Z1 => {}
+ | ^^^^^^
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- -- `E1::Z1` defined here
+ | |
+ | similarly named unit variant `Z0` defined here
+ |
+help: use the tuple variant pattern syntax instead
+ |
+LL | E1::Z1(/* fields */) => {}
+ | ~~~~~~~~~~~~~~~~~~~~
+help: a unit variant with a similar name exists
+ |
+LL | E1::Z0 => {}
+ | ~~
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 0 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:14:12
+ |
+LL | Z1(x) => {}
+ | ^ expected 0 fields, found 1
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:2:1
+ |
+LL | pub struct Z1();
+ | ------------- tuple struct has 0 fields
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:18:9
+ |
+LL | S() => {}
+ | ^^^ expected 3 fields, found 0
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14
+ |
+LL | pub struct S(pub u8, pub u8, pub u8);
+ | ------ ------ ------ tuple struct has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | S(_, _, _) => {}
+ | +++++++
+help: use `..` to ignore all fields
+ |
+LL | S(..) => {}
+ | ++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:19:11
+ |
+LL | S(1) => {}
+ | ^ expected 3 fields, found 1
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14
+ |
+LL | pub struct S(pub u8, pub u8, pub u8);
+ | ------ ------ ------ tuple struct has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | S(1, _, _) => {}
+ | ++++++
+help: use `..` to ignore the rest of the fields
+ |
+LL | S(1, ..) => {}
+ | ++++
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:20:11
+ |
+LL | S(xyz, abc) => {}
+ | ^^^ ^^^ expected 3 fields, found 2
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14
+ |
+LL | pub struct S(pub u8, pub u8, pub u8);
+ | ------ ------ ------ tuple struct has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | S(xyz, abc, _) => {}
+ | +++
+
+error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:21:11
+ |
+LL | S(1, 2, 3, 4) => {}
+ | ^ ^ ^ ^ expected 3 fields, found 4
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14
+ |
+LL | pub struct S(pub u8, pub u8, pub u8);
+ | ------ ------ ------ tuple struct has 3 fields
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:24:9
+ |
+LL | M() => {}
+ | ^^^ expected 3 fields, found 0
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
+ |
+LL | pub struct M(
+ | - tuple struct defined here
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------ tuple struct has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | M(_, _, _) => {}
+ | +++++++
+help: use `..` to ignore all fields
+ |
+LL | M(..) => {}
+ | ++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:25:11
+ |
+LL | M(1) => {}
+ | ^ expected 3 fields, found 1
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
+ |
+LL | pub struct M(
+ | - tuple struct defined here
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------ tuple struct has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | M(1, _, _) => {}
+ | ++++++
+help: use `..` to ignore the rest of the fields
+ |
+LL | M(1, ..) => {}
+ | ++++
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:26:11
+ |
+LL | M(xyz, abc) => {}
+ | ^^^ ^^^ expected 3 fields, found 2
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
+ |
+LL | pub struct M(
+ | - tuple struct defined here
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------ tuple struct has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | M(xyz, abc, _) => {}
+ | +++
+
+error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:27:11
+ |
+LL | M(1, 2, 3, 4) => {}
+ | ^ ^ ^ ^ expected 3 fields, found 4
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
+ |
+LL | pub struct M(
+ | - tuple struct defined here
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------
+LL | pub u8,
+ | ------ tuple struct has 3 fields
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 0 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:36:16
+ |
+LL | E1::Z1(x) => {}
+ | ^ expected 0 fields, found 1
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- tuple variant has 0 fields
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:39:9
+ |
+LL | E1::S() => {}
+ | ^^^^^^^ expected 3 fields, found 0
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- -- -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E1::S(_, _, _) => {}
+ | +++++++
+help: use `..` to ignore all fields
+ |
+LL | E1::S(..) => {}
+ | ++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:40:15
+ |
+LL | E1::S(1) => {}
+ | ^ expected 3 fields, found 1
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- -- -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E1::S(1, _, _) => {}
+ | ++++++
+help: use `..` to ignore the rest of the fields
+ |
+LL | E1::S(1, ..) => {}
+ | ++++
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:41:15
+ |
+LL | E1::S(xyz, abc) => {}
+ | ^^^ ^^^ expected 3 fields, found 2
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- -- -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E1::S(xyz, abc, _) => {}
+ | +++
+
+error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:42:15
+ |
+LL | E1::S(1, 2, 3, 4) => {}
+ | ^ ^ ^ ^ expected 3 fields, found 4
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27
+ |
+LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
+ | -- -- -- tuple variant has 3 fields
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:46:9
+ |
+LL | E2::S() => {}
+ | ^^^^^^^ expected 3 fields, found 0
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7
+ |
+LL | S(u8, u8, u8),
+ | -- -- -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E2::S(_, _, _) => {}
+ | +++++++
+help: use `..` to ignore all fields
+ |
+LL | E2::S(..) => {}
+ | ++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:47:15
+ |
+LL | E2::S(1) => {}
+ | ^ expected 3 fields, found 1
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7
+ |
+LL | S(u8, u8, u8),
+ | -- -- -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E2::S(1, _, _) => {}
+ | ++++++
+help: use `..` to ignore the rest of the fields
+ |
+LL | E2::S(1, ..) => {}
+ | ++++
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:48:15
+ |
+LL | E2::S(xyz, abc) => {}
+ | ^^^ ^^^ expected 3 fields, found 2
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7
+ |
+LL | S(u8, u8, u8),
+ | -- -- -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E2::S(xyz, abc, _) => {}
+ | +++
+
+error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:49:15
+ |
+LL | E2::S(1, 2, 3, 4) => {}
+ | ^ ^ ^ ^ expected 3 fields, found 4
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7
+ |
+LL | S(u8, u8, u8),
+ | -- -- -- tuple variant has 3 fields
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:52:9
+ |
+LL | E2::M() => {}
+ | ^^^^^^^ expected 3 fields, found 0
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
+ |
+LL | M(
+ | - tuple variant defined here
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E2::M(_, _, _) => {}
+ | +++++++
+help: use `..` to ignore all fields
+ |
+LL | E2::M(..) => {}
+ | ++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:53:15
+ |
+LL | E2::M(1) => {}
+ | ^ expected 3 fields, found 1
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
+ |
+LL | M(
+ | - tuple variant defined here
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E2::M(1, _, _) => {}
+ | ++++++
+help: use `..` to ignore the rest of the fields
+ |
+LL | E2::M(1, ..) => {}
+ | ++++
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:54:15
+ |
+LL | E2::M(xyz, abc) => {}
+ | ^^^ ^^^ expected 3 fields, found 2
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
+ |
+LL | M(
+ | - tuple variant defined here
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | -- tuple variant has 3 fields
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E2::M(xyz, abc, _) => {}
+ | +++
+
+error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields
+ --> $DIR/pat-tuple-field-count-cross.rs:55:15
+ |
+LL | E2::M(1, 2, 3, 4) => {}
+ | ^ ^ ^ ^ expected 3 fields, found 4
+ |
+ ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
+ |
+LL | M(
+ | - tuple variant defined here
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | -- tuple variant has 3 fields
+
+error: aborting due to 28 previous errors
+
+Some errors have detailed explanations: E0023, E0530, E0532.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/tests/ui/pattern/pat-tuple-overfield.rs b/tests/ui/pattern/pat-tuple-overfield.rs
new file mode 100644
index 000000000..c863c6575
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-overfield.rs
@@ -0,0 +1,74 @@
+struct S(u8, u8, u8);
+struct M(
+ u8,
+ u8,
+ u8,
+ u8,
+ u8,
+);
+
+struct Z0;
+struct Z1();
+enum E1 {
+ Z0,
+ Z1(),
+}
+
+fn main() {
+ match (1, 2, 3) {
+ (1, 2, 3, 4) => {} //~ ERROR mismatched types
+ (1, 2, .., 3, 4) => {} //~ ERROR mismatched types
+ _ => {}
+ }
+ match S(1, 2, 3) {
+ S(1, 2, 3, 4) => {}
+ //~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ S(1, 2, .., 3, 4) => {}
+ //~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ _ => {}
+ }
+ match M(1, 2, 3, 4, 5) {
+ M(1, 2, 3, 4, 5, 6) => {}
+ //~^ ERROR this pattern has 6 fields, but the corresponding tuple struct has 5 fields
+ M(1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6) => {}
+ //~^ ERROR this pattern has 6 fields, but the corresponding tuple struct has 5 fields
+ M(
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ ) => {}
+ //~^^ ERROR this pattern has 6 fields, but the corresponding tuple struct has 5 fields
+ }
+ match Z0 {
+ Z0 => {}
+ Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0`
+ Z0(_) => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0`
+ Z0(_, _) => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0`
+ }
+ match Z1() {
+ Z1 => {} //~ ERROR match bindings cannot shadow tuple structs
+ Z1() => {}
+ Z1(_) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 0 fields
+ Z1(_, _) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 0 fields
+ }
+ match E1::Z0 {
+ E1::Z0 => {}
+ E1::Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ E1::Z0(_) => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ E1::Z0(_, _) => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ }
+ match E1::Z1() {
+ E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1`
+ E1::Z1() => {}
+ E1::Z1(_) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 0 fields
+ E1::Z1(_, _) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 0 fields
+ }
+}
diff --git a/tests/ui/pattern/pat-tuple-overfield.stderr b/tests/ui/pattern/pat-tuple-overfield.stderr
new file mode 100644
index 000000000..54d89e031
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-overfield.stderr
@@ -0,0 +1,312 @@
+error[E0530]: match bindings cannot shadow tuple structs
+ --> $DIR/pat-tuple-overfield.rs:57:9
+ |
+LL | struct Z1();
+ | ------------ the tuple struct `Z1` is defined here
+...
+LL | Z1 => {}
+ | ^^
+ | |
+ | cannot be named the same as a tuple struct
+ | help: try specify the pattern arguments: `Z1(..)`
+
+error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0`
+ --> $DIR/pat-tuple-overfield.rs:52:9
+ |
+LL | struct Z0;
+ | ---------- `Z0` defined here
+LL | struct Z1();
+ | ------------ similarly named tuple struct `Z1` defined here
+...
+LL | Z0() => {}
+ | ^^^^
+ |
+help: use this syntax instead
+ |
+LL | Z0 => {}
+ | ~~
+help: a tuple struct with a similar name exists
+ |
+LL | Z1() => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0`
+ --> $DIR/pat-tuple-overfield.rs:53:9
+ |
+LL | struct Z0;
+ | ---------- `Z0` defined here
+LL | struct Z1();
+ | ------------ similarly named tuple struct `Z1` defined here
+...
+LL | Z0(_) => {}
+ | ^^^^^
+ |
+help: use this syntax instead
+ |
+LL | Z0 => {}
+ | ~~
+help: a tuple struct with a similar name exists
+ |
+LL | Z1(_) => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0`
+ --> $DIR/pat-tuple-overfield.rs:54:9
+ |
+LL | struct Z0;
+ | ---------- `Z0` defined here
+LL | struct Z1();
+ | ------------ similarly named tuple struct `Z1` defined here
+...
+LL | Z0(_, _) => {}
+ | ^^^^^^^^
+ |
+help: use this syntax instead
+ |
+LL | Z0 => {}
+ | ~~
+help: a tuple struct with a similar name exists
+ |
+LL | Z1(_, _) => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ --> $DIR/pat-tuple-overfield.rs:64:9
+ |
+LL | Z0,
+ | -- `E1::Z0` defined here
+LL | Z1(),
+ | ---- similarly named tuple variant `Z1` defined here
+...
+LL | E1::Z0() => {}
+ | ^^^^^^^^
+ |
+help: use this syntax instead
+ |
+LL | E1::Z0 => {}
+ | ~~~~~~
+help: a tuple variant with a similar name exists
+ |
+LL | E1::Z1() => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ --> $DIR/pat-tuple-overfield.rs:65:9
+ |
+LL | Z0,
+ | -- `E1::Z0` defined here
+LL | Z1(),
+ | ---- similarly named tuple variant `Z1` defined here
+...
+LL | E1::Z0(_) => {}
+ | ^^^^^^^^^
+ |
+help: use this syntax instead
+ |
+LL | E1::Z0 => {}
+ | ~~~~~~
+help: a tuple variant with a similar name exists
+ |
+LL | E1::Z1(_) => {}
+ | ~~
+
+error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0`
+ --> $DIR/pat-tuple-overfield.rs:66:9
+ |
+LL | Z0,
+ | -- `E1::Z0` defined here
+LL | Z1(),
+ | ---- similarly named tuple variant `Z1` defined here
+...
+LL | E1::Z0(_, _) => {}
+ | ^^^^^^^^^^^^
+ |
+help: use this syntax instead
+ |
+LL | E1::Z0 => {}
+ | ~~~~~~
+help: a tuple variant with a similar name exists
+ |
+LL | E1::Z1(_, _) => {}
+ | ~~
+
+error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E1::Z1`
+ --> $DIR/pat-tuple-overfield.rs:69:9
+ |
+LL | Z0,
+ | -- similarly named unit variant `Z0` defined here
+LL | Z1(),
+ | ---- `E1::Z1` defined here
+...
+LL | E1::Z1 => {}
+ | ^^^^^^
+ |
+help: use the tuple variant pattern syntax instead
+ |
+LL | E1::Z1() => {}
+ | ~~~~~~~~
+help: a unit variant with a similar name exists
+ |
+LL | E1::Z0 => {}
+ | ~~
+
+error[E0308]: mismatched types
+ --> $DIR/pat-tuple-overfield.rs:19:9
+ |
+LL | match (1, 2, 3) {
+ | --------- this expression has type `({integer}, {integer}, {integer})`
+LL | (1, 2, 3, 4) => {}
+ | ^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements
+ |
+ = note: expected tuple `({integer}, {integer}, {integer})`
+ found tuple `(_, _, _, _)`
+
+error[E0308]: mismatched types
+ --> $DIR/pat-tuple-overfield.rs:20:9
+ |
+LL | match (1, 2, 3) {
+ | --------- this expression has type `({integer}, {integer}, {integer})`
+LL | (1, 2, 3, 4) => {}
+LL | (1, 2, .., 3, 4) => {}
+ | ^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements
+ |
+ = note: expected tuple `({integer}, {integer}, {integer})`
+ found tuple `(_, _, _, _)`
+
+error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-overfield.rs:24:11
+ |
+LL | struct S(u8, u8, u8);
+ | -- -- -- tuple struct has 3 fields
+...
+LL | S(1, 2, 3, 4) => {}
+ | ^ ^ ^ ^ expected 3 fields, found 4
+
+error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/pat-tuple-overfield.rs:26:11
+ |
+LL | struct S(u8, u8, u8);
+ | -- -- -- tuple struct has 3 fields
+...
+LL | S(1, 2, .., 3, 4) => {}
+ | ^ ^ ^ ^ expected 3 fields, found 4
+
+error[E0023]: this pattern has 6 fields, but the corresponding tuple struct has 5 fields
+ --> $DIR/pat-tuple-overfield.rs:31:11
+ |
+LL | struct M(
+ | - tuple struct defined here
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | -- tuple struct has 5 fields
+...
+LL | M(1, 2, 3, 4, 5, 6) => {}
+ | ^ ^ ^ ^ ^ ^ expected 5 fields, found 6
+
+error[E0023]: this pattern has 6 fields, but the corresponding tuple struct has 5 fields
+ --> $DIR/pat-tuple-overfield.rs:33:11
+ |
+LL | struct M(
+ | - tuple struct defined here
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | -- tuple struct has 5 fields
+...
+LL | M(1,
+ | - ^
+LL | 2,
+ | ^
+LL | 3,
+ | ^
+LL | 4,
+ | ^
+LL | 5,
+ | ^
+LL | 6) => {}
+ | ^ expected 5 fields, found 6
+
+error[E0023]: this pattern has 6 fields, but the corresponding tuple struct has 5 fields
+ --> $DIR/pat-tuple-overfield.rs:41:13
+ |
+LL | struct M(
+ | - tuple struct defined here
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | --
+LL | u8,
+ | -- tuple struct has 5 fields
+...
+LL | M(
+ | -
+LL | 1,
+ | ^
+LL | 2,
+ | ^
+LL | 3,
+ | ^
+LL | 4,
+ | ^
+LL | 5,
+ | ^
+LL | 6,
+ | ^ expected 5 fields, found 6
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 0 fields
+ --> $DIR/pat-tuple-overfield.rs:59:12
+ |
+LL | struct Z1();
+ | --------- tuple struct has 0 fields
+...
+LL | Z1(_) => {}
+ | ^ expected 0 fields, found 1
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 0 fields
+ --> $DIR/pat-tuple-overfield.rs:60:12
+ |
+LL | struct Z1();
+ | --------- tuple struct has 0 fields
+...
+LL | Z1(_, _) => {}
+ | ^ ^ expected 0 fields, found 2
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 0 fields
+ --> $DIR/pat-tuple-overfield.rs:71:16
+ |
+LL | Z1(),
+ | -- tuple variant has 0 fields
+...
+LL | E1::Z1(_) => {}
+ | ^ expected 0 fields, found 1
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 0 fields
+ --> $DIR/pat-tuple-overfield.rs:72:16
+ |
+LL | Z1(),
+ | -- tuple variant has 0 fields
+...
+LL | E1::Z1(_, _) => {}
+ | ^ ^ expected 0 fields, found 2
+
+error: aborting due to 19 previous errors
+
+Some errors have detailed explanations: E0023, E0308, E0530, E0532.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/tests/ui/pattern/pat-tuple-underfield.rs b/tests/ui/pattern/pat-tuple-underfield.rs
new file mode 100644
index 000000000..dac60e3fa
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-underfield.rs
@@ -0,0 +1,67 @@
+struct S(i32, f32);
+enum E {
+ S(i32, f32),
+}
+struct Point4(i32, i32, i32, i32);
+
+fn main() {
+ match S(0, 1.0) {
+ S(x) => {}
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ }
+ match S(0, 1.0) {
+ S(_) => {}
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ //~| HELP use `..` to ignore all fields
+ }
+ match S(0, 1.0) {
+ S() => {}
+ //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ //~| HELP use `..` to ignore all fields
+
+ // Test non-standard formatting
+ S () => {}
+ //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ //~| HELP use `..` to ignore all fields
+ }
+
+ match E::S(0, 1.0) {
+ E::S(x) => {}
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ }
+ match E::S(0, 1.0) {
+ E::S(_) => {}
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ //~| HELP use `..` to ignore all fields
+ }
+ match E::S(0, 1.0) {
+ E::S() => {}
+ //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ //~| HELP use `..` to ignore all fields
+
+ // Test non-standard formatting
+ E::S () => {}
+ //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+ //~| HELP use `_` to explicitly ignore each field
+ //~| HELP use `..` to ignore all fields
+ }
+ match E::S(0, 1.0) {
+ E::S => {}
+ //~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S`
+ //~| HELP use the tuple variant pattern syntax instead
+ }
+
+ match Point4(0, 1, 2, 3) {
+ Point4( a , _ ) => {}
+ //~^ ERROR this pattern has 2 fields, but the corresponding tuple struct has 4 fields
+ //~| HELP use `_` to explicitly ignore each field
+ //~| HELP use `..` to ignore the rest of the fields
+ }
+}
diff --git a/tests/ui/pattern/pat-tuple-underfield.stderr b/tests/ui/pattern/pat-tuple-underfield.stderr
new file mode 100644
index 000000000..e75f9b38d
--- /dev/null
+++ b/tests/ui/pattern/pat-tuple-underfield.stderr
@@ -0,0 +1,167 @@
+error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S`
+ --> $DIR/pat-tuple-underfield.rs:56:9
+ |
+LL | S(i32, f32),
+ | ----------- `E::S` defined here
+...
+LL | E::S => {}
+ | ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)`
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:9:11
+ |
+LL | struct S(i32, f32);
+ | --- --- tuple struct has 2 fields
+...
+LL | S(x) => {}
+ | ^ expected 2 fields, found 1
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | S(x, _) => {}
+ | +++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:14:11
+ |
+LL | struct S(i32, f32);
+ | --- --- tuple struct has 2 fields
+...
+LL | S(_) => {}
+ | ^ expected 2 fields, found 1
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | S(_, _) => {}
+ | +++
+help: use `..` to ignore all fields
+ |
+LL | S(..) => {}
+ | ~~
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:20:9
+ |
+LL | struct S(i32, f32);
+ | --- --- tuple struct has 2 fields
+...
+LL | S() => {}
+ | ^^^ expected 2 fields, found 0
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | S(_, _) => {}
+ | ++++
+help: use `..` to ignore all fields
+ |
+LL | S(..) => {}
+ | ++
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:26:9
+ |
+LL | struct S(i32, f32);
+ | --- --- tuple struct has 2 fields
+...
+LL | S () => {}
+ | ^^^^ expected 2 fields, found 0
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | S (_, _) => {}
+ | ++++
+help: use `..` to ignore all fields
+ |
+LL | S (..) => {}
+ | ++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:33:14
+ |
+LL | S(i32, f32),
+ | --- --- tuple variant has 2 fields
+...
+LL | E::S(x) => {}
+ | ^ expected 2 fields, found 1
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E::S(x, _) => {}
+ | +++
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:38:14
+ |
+LL | S(i32, f32),
+ | --- --- tuple variant has 2 fields
+...
+LL | E::S(_) => {}
+ | ^ expected 2 fields, found 1
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E::S(_, _) => {}
+ | +++
+help: use `..` to ignore all fields
+ |
+LL | E::S(..) => {}
+ | ~~
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:44:9
+ |
+LL | S(i32, f32),
+ | --- --- tuple variant has 2 fields
+...
+LL | E::S() => {}
+ | ^^^^^^ expected 2 fields, found 0
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E::S(_, _) => {}
+ | ++++
+help: use `..` to ignore all fields
+ |
+LL | E::S(..) => {}
+ | ++
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+ --> $DIR/pat-tuple-underfield.rs:50:9
+ |
+LL | S(i32, f32),
+ | --- --- tuple variant has 2 fields
+...
+LL | E::S () => {}
+ | ^^^^^^^ expected 2 fields, found 0
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | E::S (_, _) => {}
+ | ++++
+help: use `..` to ignore all fields
+ |
+LL | E::S (..) => {}
+ | ++
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields
+ --> $DIR/pat-tuple-underfield.rs:62:19
+ |
+LL | struct Point4(i32, i32, i32, i32);
+ | --- --- --- --- tuple struct has 4 fields
+...
+LL | Point4( a , _ ) => {}
+ | ^ ^ expected 4 fields, found 2
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | Point4( a , _ , _, _) => {}
+ | ++++++
+help: use `..` to ignore the rest of the fields
+ |
+LL | Point4( a, ..) => {}
+ | ~~~~
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0023, E0532.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/tests/ui/pattern/pat-type-err-formal-param.rs b/tests/ui/pattern/pat-type-err-formal-param.rs
new file mode 100644
index 000000000..54336b349
--- /dev/null
+++ b/tests/ui/pattern/pat-type-err-formal-param.rs
@@ -0,0 +1,8 @@
+// Test the `.span_label(..)` to the type when there's a
+// type error in a pattern due to a the formal parameter.
+
+fn main() {}
+
+struct Tuple(u8);
+
+fn foo(Tuple(_): String) {} //~ ERROR mismatched types
diff --git a/tests/ui/pattern/pat-type-err-formal-param.stderr b/tests/ui/pattern/pat-type-err-formal-param.stderr
new file mode 100644
index 000000000..206713a4b
--- /dev/null
+++ b/tests/ui/pattern/pat-type-err-formal-param.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+ --> $DIR/pat-type-err-formal-param.rs:8:8
+ |
+LL | fn foo(Tuple(_): String) {}
+ | ^^^^^^^^ ------ expected due to this
+ | |
+ | expected struct `String`, found struct `Tuple`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/pat-type-err-let-stmt.rs b/tests/ui/pattern/pat-type-err-let-stmt.rs
new file mode 100644
index 000000000..6e9850b65
--- /dev/null
+++ b/tests/ui/pattern/pat-type-err-let-stmt.rs
@@ -0,0 +1,16 @@
+// Test the `.span_label` to the type / scrutinee
+// when there's a type error in checking a pattern.
+
+fn main() {
+ // We want to point at the `Option<u8>`.
+ let Ok(0): Option<u8> = 42u8;
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+
+ // We want to point at the `Option<u8>`.
+ let Ok(0): Option<u8>;
+ //~^ ERROR mismatched types
+
+ // We want to point at the scrutinee.
+ let Ok(0) = 42u8; //~ ERROR mismatched types
+}
diff --git a/tests/ui/pattern/pat-type-err-let-stmt.stderr b/tests/ui/pattern/pat-type-err-let-stmt.stderr
new file mode 100644
index 000000000..090bd6711
--- /dev/null
+++ b/tests/ui/pattern/pat-type-err-let-stmt.stderr
@@ -0,0 +1,51 @@
+error[E0308]: mismatched types
+ --> $DIR/pat-type-err-let-stmt.rs:6:29
+ |
+LL | let Ok(0): Option<u8> = 42u8;
+ | ---------- ^^^^ expected enum `Option`, found `u8`
+ | |
+ | expected due to this
+ |
+ = note: expected enum `Option<u8>`
+ found type `u8`
+help: try wrapping the expression in `Some`
+ |
+LL | let Ok(0): Option<u8> = Some(42u8);
+ | +++++ +
+
+error[E0308]: mismatched types
+ --> $DIR/pat-type-err-let-stmt.rs:6:9
+ |
+LL | let Ok(0): Option<u8> = 42u8;
+ | ^^^^^ ---------- expected due to this
+ | |
+ | expected enum `Option`, found enum `Result`
+ |
+ = note: expected enum `Option<u8>`
+ found enum `Result<_, _>`
+
+error[E0308]: mismatched types
+ --> $DIR/pat-type-err-let-stmt.rs:11:9
+ |
+LL | let Ok(0): Option<u8>;
+ | ^^^^^ ---------- expected due to this
+ | |
+ | expected enum `Option`, found enum `Result`
+ |
+ = note: expected enum `Option<u8>`
+ found enum `Result<_, _>`
+
+error[E0308]: mismatched types
+ --> $DIR/pat-type-err-let-stmt.rs:15:9
+ |
+LL | let Ok(0) = 42u8;
+ | ^^^^^ ---- this expression has type `u8`
+ | |
+ | expected `u8`, found enum `Result`
+ |
+ = note: expected type `u8`
+ found enum `Result<_, _>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/patkind-litrange-no-expr.rs b/tests/ui/pattern/patkind-litrange-no-expr.rs
new file mode 100644
index 000000000..7ef541cb5
--- /dev/null
+++ b/tests/ui/pattern/patkind-litrange-no-expr.rs
@@ -0,0 +1,24 @@
+macro_rules! enum_number {
+ ($name:ident { $($variant:ident = $value:expr, )* }) => {
+ enum $name {
+ $($variant = $value,)*
+ }
+
+ fn foo(value: i32) -> Option<$name> {
+ match value {
+ $( $value => Some($name::$variant), )* // PatKind::Lit
+ $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
+ _ => None
+ }
+ }
+ }
+}
+
+enum_number!(Change {
+ Pos = 1,
+ Neg = -1,
+ Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
+ //~| ERROR arbitrary expressions aren't allowed in patterns
+});
+
+fn main() {}
diff --git a/tests/ui/pattern/patkind-litrange-no-expr.stderr b/tests/ui/pattern/patkind-litrange-no-expr.stderr
new file mode 100644
index 000000000..eb1ee7e45
--- /dev/null
+++ b/tests/ui/pattern/patkind-litrange-no-expr.stderr
@@ -0,0 +1,14 @@
+error: arbitrary expressions aren't allowed in patterns
+ --> $DIR/patkind-litrange-no-expr.rs:20:13
+ |
+LL | Arith = 1 + 1,
+ | ^^^^^
+
+error: arbitrary expressions aren't allowed in patterns
+ --> $DIR/patkind-litrange-no-expr.rs:20:13
+ |
+LL | Arith = 1 + 1,
+ | ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/pattern/pattern-binding-disambiguation.rs b/tests/ui/pattern/pattern-binding-disambiguation.rs
new file mode 100644
index 000000000..ce1d8c6c0
--- /dev/null
+++ b/tests/ui/pattern/pattern-binding-disambiguation.rs
@@ -0,0 +1,57 @@
+struct UnitStruct;
+struct TupleStruct();
+struct BracedStruct{}
+
+enum E {
+ UnitVariant,
+ TupleVariant(),
+ BracedVariant{},
+}
+use E::*;
+
+const CONST: () = ();
+static STATIC: () = ();
+
+fn function() {}
+
+fn main() {
+ let doesnt_matter = 0;
+
+ match UnitStruct {
+ UnitStruct => {} // OK, `UnitStruct` is a unit struct pattern
+ }
+ match doesnt_matter {
+ TupleStruct => {} //~ ERROR match bindings cannot shadow tuple structs
+ }
+ match doesnt_matter {
+ BracedStruct => {} // OK, `BracedStruct` is a fresh binding
+ }
+ match UnitVariant {
+ UnitVariant => {} // OK, `UnitVariant` is a unit variant pattern
+ }
+ match doesnt_matter {
+ TupleVariant => {} //~ ERROR match bindings cannot shadow tuple variants
+ }
+ match doesnt_matter {
+ BracedVariant => {} // OK, `BracedVariant` is a fresh binding
+ }
+ match CONST {
+ CONST => {} // OK, `CONST` is a const pattern
+ }
+ match doesnt_matter {
+ STATIC => {} //~ ERROR match bindings cannot shadow statics
+ }
+ match doesnt_matter {
+ function => {} // OK, `function` is a fresh binding
+ }
+
+ let UnitStruct = UnitStruct; // OK, `UnitStruct` is a unit struct pattern
+ let TupleStruct = doesnt_matter; //~ ERROR let bindings cannot shadow tuple structs
+ let BracedStruct = doesnt_matter; // OK, `BracedStruct` is a fresh binding
+ let UnitVariant = UnitVariant; // OK, `UnitVariant` is a unit variant pattern
+ let TupleVariant = doesnt_matter; //~ ERROR let bindings cannot shadow tuple variants
+ let BracedVariant = doesnt_matter; // OK, `BracedVariant` is a fresh binding
+ let CONST = CONST; // OK, `CONST` is a const pattern
+ let STATIC = doesnt_matter; //~ ERROR let bindings cannot shadow statics
+ let function = doesnt_matter; // OK, `function` is a fresh binding
+}
diff --git a/tests/ui/pattern/pattern-binding-disambiguation.stderr b/tests/ui/pattern/pattern-binding-disambiguation.stderr
new file mode 100644
index 000000000..d54467b3c
--- /dev/null
+++ b/tests/ui/pattern/pattern-binding-disambiguation.stderr
@@ -0,0 +1,63 @@
+error[E0530]: match bindings cannot shadow tuple structs
+ --> $DIR/pattern-binding-disambiguation.rs:24:9
+ |
+LL | struct TupleStruct();
+ | --------------------- the tuple struct `TupleStruct` is defined here
+...
+LL | TupleStruct => {}
+ | ^^^^^^^^^^^
+ | |
+ | cannot be named the same as a tuple struct
+ | help: try specify the pattern arguments: `TupleStruct(..)`
+
+error[E0530]: match bindings cannot shadow tuple variants
+ --> $DIR/pattern-binding-disambiguation.rs:33:9
+ |
+LL | use E::*;
+ | ---- the tuple variant `TupleVariant` is imported here
+...
+LL | TupleVariant => {}
+ | ^^^^^^^^^^^^
+ | |
+ | cannot be named the same as a tuple variant
+ | help: try specify the pattern arguments: `TupleVariant(..)`
+
+error[E0530]: match bindings cannot shadow statics
+ --> $DIR/pattern-binding-disambiguation.rs:42:9
+ |
+LL | static STATIC: () = ();
+ | ----------------------- the static `STATIC` is defined here
+...
+LL | STATIC => {}
+ | ^^^^^^ cannot be named the same as a static
+
+error[E0530]: let bindings cannot shadow tuple structs
+ --> $DIR/pattern-binding-disambiguation.rs:49:9
+ |
+LL | struct TupleStruct();
+ | --------------------- the tuple struct `TupleStruct` is defined here
+...
+LL | let TupleStruct = doesnt_matter;
+ | ^^^^^^^^^^^ cannot be named the same as a tuple struct
+
+error[E0530]: let bindings cannot shadow tuple variants
+ --> $DIR/pattern-binding-disambiguation.rs:52:9
+ |
+LL | use E::*;
+ | ---- the tuple variant `TupleVariant` is imported here
+...
+LL | let TupleVariant = doesnt_matter;
+ | ^^^^^^^^^^^^ cannot be named the same as a tuple variant
+
+error[E0530]: let bindings cannot shadow statics
+ --> $DIR/pattern-binding-disambiguation.rs:55:9
+ |
+LL | static STATIC: () = ();
+ | ----------------------- the static `STATIC` is defined here
+...
+LL | let STATIC = doesnt_matter;
+ | ^^^^^^ cannot be named the same as a static
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
diff --git a/tests/ui/pattern/pattern-error-continue.rs b/tests/ui/pattern/pattern-error-continue.rs
new file mode 100644
index 000000000..0702a9986
--- /dev/null
+++ b/tests/ui/pattern/pattern-error-continue.rs
@@ -0,0 +1,35 @@
+// Test that certain pattern-match type errors are non-fatal
+
+enum A {
+ B(isize, isize),
+ C(isize, isize, isize),
+ D
+}
+
+struct S {
+ a: isize
+}
+
+fn f(_c: char) {}
+
+fn main() {
+ match A::B(1, 2) {
+ A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but
+ A::D(_) => (), //~ ERROR expected tuple struct or tuple variant, found unit variant `A::D`
+ _ => ()
+ }
+ match 'c' {
+ S { .. } => (),
+ //~^ ERROR mismatched types
+ //~| expected `char`, found struct `S`
+
+ _ => ()
+ }
+ f(true);
+ //~^ ERROR mismatched types
+ //~| expected `char`, found `bool`
+
+ match () {
+ E::V => {} //~ ERROR failed to resolve: use of undeclared type `E`
+ }
+}
diff --git a/tests/ui/pattern/pattern-error-continue.stderr b/tests/ui/pattern/pattern-error-continue.stderr
new file mode 100644
index 000000000..4c2eff63a
--- /dev/null
+++ b/tests/ui/pattern/pattern-error-continue.stderr
@@ -0,0 +1,62 @@
+error[E0433]: failed to resolve: use of undeclared type `E`
+ --> $DIR/pattern-error-continue.rs:33:9
+ |
+LL | E::V => {}
+ | ^ use of undeclared type `E`
+
+error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D`
+ --> $DIR/pattern-error-continue.rs:18:9
+ |
+LL | B(isize, isize),
+ | --------------- similarly named tuple variant `B` defined here
+LL | C(isize, isize, isize),
+LL | D
+ | - `A::D` defined here
+...
+LL | A::D(_) => (),
+ | ^^^^^^^
+ |
+help: use this syntax instead
+ |
+LL | A::D => (),
+ | ~~~~
+help: a tuple variant with a similar name exists
+ |
+LL | A::B(_) => (),
+ | ~
+
+error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
+ --> $DIR/pattern-error-continue.rs:17:14
+ |
+LL | B(isize, isize),
+ | ----- ----- tuple variant has 2 fields
+...
+LL | A::B(_, _, _) => (),
+ | ^ ^ ^ expected 2 fields, found 3
+
+error[E0308]: mismatched types
+ --> $DIR/pattern-error-continue.rs:22:9
+ |
+LL | match 'c' {
+ | --- this expression has type `char`
+LL | S { .. } => (),
+ | ^^^^^^^^ expected `char`, found struct `S`
+
+error[E0308]: mismatched types
+ --> $DIR/pattern-error-continue.rs:28:7
+ |
+LL | f(true);
+ | - ^^^^ expected `char`, found `bool`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/pattern-error-continue.rs:13:4
+ |
+LL | fn f(_c: char) {}
+ | ^ --------
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0023, E0308, E0433, E0532.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/tests/ui/pattern/pattern-ident-path-generics.rs b/tests/ui/pattern/pattern-ident-path-generics.rs
new file mode 100644
index 000000000..48c02623f
--- /dev/null
+++ b/tests/ui/pattern/pattern-ident-path-generics.rs
@@ -0,0 +1,6 @@
+fn main() {
+ match Some("foo") {
+ None::<isize> => {} //~ ERROR mismatched types
+ Some(_) => {}
+ }
+}
diff --git a/tests/ui/pattern/pattern-ident-path-generics.stderr b/tests/ui/pattern/pattern-ident-path-generics.stderr
new file mode 100644
index 000000000..01b082bd3
--- /dev/null
+++ b/tests/ui/pattern/pattern-ident-path-generics.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+ --> $DIR/pattern-ident-path-generics.rs:3:9
+ |
+LL | match Some("foo") {
+ | ----------- this expression has type `Option<&str>`
+LL | None::<isize> => {}
+ | ^^^^^^^^^^^^^ expected `&str`, found `isize`
+ |
+ = note: expected enum `Option<&str>`
+ found enum `Option<isize>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/pattern-tyvar-2.rs b/tests/ui/pattern/pattern-tyvar-2.rs
new file mode 100644
index 000000000..7647c766e
--- /dev/null
+++ b/tests/ui/pattern/pattern-tyvar-2.rs
@@ -0,0 +1,6 @@
+enum Bar { T1((), Option<Vec<isize>>), T2, }
+
+fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } }
+//~^ ERROR cannot multiply `Vec<isize>` by `{integer}`
+
+fn main() { }
diff --git a/tests/ui/pattern/pattern-tyvar-2.stderr b/tests/ui/pattern/pattern-tyvar-2.stderr
new file mode 100644
index 000000000..121817e70
--- /dev/null
+++ b/tests/ui/pattern/pattern-tyvar-2.stderr
@@ -0,0 +1,11 @@
+error[E0369]: cannot multiply `Vec<isize>` by `{integer}`
+ --> $DIR/pattern-tyvar-2.rs:3:71
+ |
+LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } }
+ | - ^ - {integer}
+ | |
+ | Vec<isize>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/pattern/pattern-tyvar.rs b/tests/ui/pattern/pattern-tyvar.rs
new file mode 100644
index 000000000..e2cbf0519
--- /dev/null
+++ b/tests/ui/pattern/pattern-tyvar.rs
@@ -0,0 +1,12 @@
+enum Bar { T1((), Option<Vec<isize>>), T2 }
+
+fn foo(t: Bar) {
+ match t {
+ Bar::T1(_, Some::<isize>(x)) => { //~ ERROR mismatched types
+ println!("{}", x);
+ }
+ _ => { panic!(); }
+ }
+}
+
+fn main() { }
diff --git a/tests/ui/pattern/pattern-tyvar.stderr b/tests/ui/pattern/pattern-tyvar.stderr
new file mode 100644
index 000000000..f1e2a9d72
--- /dev/null
+++ b/tests/ui/pattern/pattern-tyvar.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+ --> $DIR/pattern-tyvar.rs:5:18
+ |
+LL | match t {
+ | - this expression has type `Bar`
+LL | Bar::T1(_, Some::<isize>(x)) => {
+ | ^^^^^^^^^^^^^^^^ expected struct `Vec`, found `isize`
+ |
+ = note: expected enum `Option<Vec<isize>>`
+ found enum `Option<isize>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rest-pat-semantic-disallowed.rs b/tests/ui/pattern/rest-pat-semantic-disallowed.rs
new file mode 100644
index 000000000..156285e0f
--- /dev/null
+++ b/tests/ui/pattern/rest-pat-semantic-disallowed.rs
@@ -0,0 +1,83 @@
+// Here we test that rest patterns, i.e. `..`, are not allowed
+// outside of slice (+ ident patterns within those), tuple,
+// and tuple struct patterns and that duplicates are caught in these contexts.
+
+#![feature(box_patterns)]
+
+fn main() {}
+
+macro_rules! mk_pat {
+ () => { .. } //~ ERROR `..` patterns are not allowed here
+}
+
+fn rest_patterns() {
+ let mk_pat!();
+
+ // Top level:
+ fn foo(..: u8) {} //~ ERROR `..` patterns are not allowed here
+ let ..; //~ ERROR `..` patterns are not allowed here
+
+ // Box patterns:
+ let box ..; //~ ERROR `..` patterns are not allowed here
+
+ // In or-patterns:
+ match 1 {
+ 1 | .. => {} //~ ERROR `..` patterns are not allowed here
+ }
+
+ // Ref patterns:
+ let &..; //~ ERROR `..` patterns are not allowed here
+ let &mut ..; //~ ERROR `..` patterns are not allowed here
+
+ // Ident patterns:
+ let x @ ..; //~ ERROR `..` patterns are not allowed here
+ //~^ ERROR type annotations needed
+ let ref x @ ..; //~ ERROR `..` patterns are not allowed here
+ let ref mut x @ ..; //~ ERROR `..` patterns are not allowed here
+
+ // Tuple:
+ let (..): (u8,); // OK.
+ let (..,): (u8,); // OK.
+ let (
+ ..,
+ .., //~ ERROR `..` can only be used once per tuple pattern
+ .. //~ ERROR `..` can only be used once per tuple pattern
+ ): (u8, u8, u8);
+ let (
+ ..,
+ x,
+ .. //~ ERROR `..` can only be used once per tuple pattern
+ ): (u8, u8, u8);
+
+ struct A(u8, u8, u8);
+
+ // Tuple struct (same idea as for tuple patterns):
+ let A(..); // OK.
+ let A(..,); // OK.
+ let A(
+ ..,
+ .., //~ ERROR `..` can only be used once per tuple struct pattern
+ .. //~ ERROR `..` can only be used once per tuple struct pattern
+ );
+ let A(
+ ..,
+ x,
+ .. //~ ERROR `..` can only be used once per tuple struct pattern
+ );
+
+ // Array/Slice:
+ let [..]: &[u8]; // OK.
+ let [..,]: &[u8]; // OK.
+ let [
+ ..,
+ .., //~ ERROR `..` can only be used once per slice pattern
+ .. //~ ERROR `..` can only be used once per slice pattern
+ ]: &[u8];
+ let [
+ ..,
+ ref x @ .., //~ ERROR `..` can only be used once per slice pattern
+ ref mut y @ .., //~ ERROR `..` can only be used once per slice pattern
+ (ref z @ ..), //~ ERROR `..` patterns are not allowed here
+ .. //~ ERROR `..` can only be used once per slice pattern
+ ]: &[u8];
+}
diff --git a/tests/ui/pattern/rest-pat-semantic-disallowed.stderr b/tests/ui/pattern/rest-pat-semantic-disallowed.stderr
new file mode 100644
index 000000000..beba7def9
--- /dev/null
+++ b/tests/ui/pattern/rest-pat-semantic-disallowed.stderr
@@ -0,0 +1,201 @@
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:10:13
+ |
+LL | () => { .. }
+ | ^^
+...
+LL | let mk_pat!();
+ | --------- in this macro invocation
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+ = note: this error originates in the macro `mk_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:18:9
+ |
+LL | let ..;
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:21:13
+ |
+LL | let box ..;
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:25:13
+ |
+LL | 1 | .. => {}
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:29:10
+ |
+LL | let &..;
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:30:14
+ |
+LL | let &mut ..;
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:33:13
+ |
+LL | let x @ ..;
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:35:17
+ |
+LL | let ref x @ ..;
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:36:21
+ |
+LL | let ref mut x @ ..;
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` can only be used once per tuple pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:43:9
+ |
+LL | ..,
+ | -- previously used here
+LL | ..,
+ | ^^ can only be used once per tuple pattern
+
+error: `..` can only be used once per tuple pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:44:9
+ |
+LL | ..,
+ | -- previously used here
+LL | ..,
+LL | ..
+ | ^^ can only be used once per tuple pattern
+
+error: `..` can only be used once per tuple pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:49:9
+ |
+LL | ..,
+ | -- previously used here
+LL | x,
+LL | ..
+ | ^^ can only be used once per tuple pattern
+
+error: `..` can only be used once per tuple struct pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:59:9
+ |
+LL | ..,
+ | -- previously used here
+LL | ..,
+ | ^^ can only be used once per tuple struct pattern
+
+error: `..` can only be used once per tuple struct pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:60:9
+ |
+LL | ..,
+ | -- previously used here
+LL | ..,
+LL | ..
+ | ^^ can only be used once per tuple struct pattern
+
+error: `..` can only be used once per tuple struct pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:65:9
+ |
+LL | ..,
+ | -- previously used here
+LL | x,
+LL | ..
+ | ^^ can only be used once per tuple struct pattern
+
+error: `..` can only be used once per slice pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:73:9
+ |
+LL | ..,
+ | -- previously used here
+LL | ..,
+ | ^^ can only be used once per slice pattern
+
+error: `..` can only be used once per slice pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:74:9
+ |
+LL | ..,
+ | -- previously used here
+LL | ..,
+LL | ..
+ | ^^ can only be used once per slice pattern
+
+error: `..` can only be used once per slice pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:78:17
+ |
+LL | ..,
+ | -- previously used here
+LL | ref x @ ..,
+ | ^^ can only be used once per slice pattern
+
+error: `..` can only be used once per slice pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:79:21
+ |
+LL | ..,
+ | -- previously used here
+LL | ref x @ ..,
+LL | ref mut y @ ..,
+ | ^^ can only be used once per slice pattern
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:80:18
+ |
+LL | (ref z @ ..),
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: `..` can only be used once per slice pattern
+ --> $DIR/rest-pat-semantic-disallowed.rs:81:9
+ |
+LL | ..,
+ | -- previously used here
+...
+LL | ..
+ | ^^ can only be used once per slice pattern
+
+error: `..` patterns are not allowed here
+ --> $DIR/rest-pat-semantic-disallowed.rs:17:12
+ |
+LL | fn foo(..: u8) {}
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0282]: type annotations needed
+ --> $DIR/rest-pat-semantic-disallowed.rs:33:9
+ |
+LL | let x @ ..;
+ | ^^^^^^
+ |
+help: consider giving this pattern a type
+ |
+LL | let x @ ..: /* Type */;
+ | ++++++++++++
+
+error: aborting due to 23 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/pattern/rest-pat-syntactic.rs b/tests/ui/pattern/rest-pat-syntactic.rs
new file mode 100644
index 000000000..4da5a2db7
--- /dev/null
+++ b/tests/ui/pattern/rest-pat-syntactic.rs
@@ -0,0 +1,73 @@
+// Here we test that `..` is allowed in all pattern locations *syntactically*.
+// The semantic test is in `rest-pat-semantic-disallowed.rs`.
+
+// check-pass
+
+fn main() {}
+
+macro_rules! accept_pat {
+ ($p:pat) => {}
+}
+
+accept_pat!(..);
+
+#[cfg(FALSE)]
+fn rest_patterns() {
+ // Top level:
+ fn foo(..: u8) {}
+ let ..;
+
+ // Box patterns:
+ let box ..;
+ //~^ WARN box pattern syntax is experimental
+ //~| WARN unstable syntax
+
+ // In or-patterns:
+ match x {
+ .. | .. => {}
+ }
+
+ // Ref patterns:
+ let &..;
+ let &mut ..;
+
+ // Ident patterns:
+ let x @ ..;
+ let ref x @ ..;
+ let ref mut x @ ..;
+
+ // Tuple:
+ let (..); // This is interpreted as a tuple pattern, not a parenthesis one.
+ let (..,); // Allowing trailing comma.
+ let (.., .., ..); // Duplicates also.
+ let (.., P, ..); // Including with things in between.
+
+ // Tuple struct (same idea as for tuple patterns):
+ let A(..);
+ let A(..,);
+ let A(.., .., ..);
+ let A(.., P, ..);
+
+ // Array/Slice (like with tuple patterns):
+ let [..];
+ let [..,];
+ let [.., .., ..];
+ let [.., P, ..];
+
+ // Random walk to guard against special casing:
+ match x {
+ .. |
+ [
+ (
+ box .., //~ WARN box pattern syntax is experimental
+ &(..),
+ &mut ..,
+ x @ ..
+ ),
+ ref x @ ..,
+ ] |
+ ref mut x @ ..
+ => {}
+ }
+ //~| WARN unstable syntax
+}
diff --git a/tests/ui/pattern/rest-pat-syntactic.stderr b/tests/ui/pattern/rest-pat-syntactic.stderr
new file mode 100644
index 000000000..37019b7d5
--- /dev/null
+++ b/tests/ui/pattern/rest-pat-syntactic.stderr
@@ -0,0 +1,24 @@
+warning: box pattern syntax is experimental
+ --> $DIR/rest-pat-syntactic.rs:21:9
+ |
+LL | let box ..;
+ | ^^^^^^
+ |
+ = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+ = help: add `#![feature(box_patterns)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: box pattern syntax is experimental
+ --> $DIR/rest-pat-syntactic.rs:62:17
+ |
+LL | box ..,
+ | ^^^^^^
+ |
+ = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+ = help: add `#![feature(box_patterns)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/pattern/size-and-align.rs b/tests/ui/pattern/size-and-align.rs
new file mode 100644
index 000000000..a32b5de72
--- /dev/null
+++ b/tests/ui/pattern/size-and-align.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+#![allow(non_camel_case_types)]
+enum clam<T> { a(T, isize), b, }
+
+fn uhoh<T>(v: Vec<clam<T>> ) {
+ match v[1] {
+ clam::a::<T>(ref _t, ref u) => {
+ println!("incorrect");
+ println!("{}", u);
+ panic!();
+ }
+ clam::b::<T> => { println!("correct"); }
+ }
+}
+
+pub fn main() {
+ let v: Vec<clam<isize>> = vec![clam::b::<isize>, clam::b::<isize>, clam::a::<isize>(42, 17)];
+ uhoh::<isize>(v);
+}
diff --git a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed
new file mode 100644
index 000000000..b28dce881
--- /dev/null
+++ b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+
+fn main() {
+ match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
+ Some(1) => {}
+ // hello
+ Some(_) => {}
+ None => todo!()
+ }
+}
diff --git a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs
new file mode 100644
index 000000000..42493a632
--- /dev/null
+++ b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+fn main() {
+ match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
+ Some(1) => {}
+ // hello
+ Some(_) => {}
+ }
+}
diff --git a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr
new file mode 100644
index 000000000..2a016048f
--- /dev/null
+++ b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `None` not covered
+ --> $DIR/suggest-adding-appropriate-missing-pattern-excluding-comments.rs:4:11
+ |
+LL | match Some(1) {
+ | ^^^^^^^ pattern `None` not covered
+ |
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: not covered
+ = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Some(_) => {}
+LL + None => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs b/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
new file mode 100644
index 000000000..7d1cac8a4
--- /dev/null
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
@@ -0,0 +1,32 @@
+// The precise semantics of inhabitedness with respect to unions and references is currently
+// undecided. This test file currently checks a conservative choice.
+
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+
+#![allow(dead_code)]
+#![allow(unreachable_code)]
+
+pub union Foo {
+ foo: !,
+}
+
+fn uninhab_ref() -> &'static ! {
+ unimplemented!()
+}
+
+fn uninhab_union() -> Foo {
+ unimplemented!()
+}
+
+fn match_on_uninhab() {
+ match uninhab_ref() {
+ //~^ ERROR non-exhaustive patterns: type `&!` is non-empty
+ }
+
+ match uninhab_union() {
+ //~^ ERROR non-exhaustive patterns: type `Foo` is non-empty
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/tests/ui/pattern/usefulness/always-inhabited-union-ref.stderr
new file mode 100644
index 000000000..cd5c283f9
--- /dev/null
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.stderr
@@ -0,0 +1,37 @@
+error[E0004]: non-exhaustive patterns: type `&!` is non-empty
+ --> $DIR/always-inhabited-union-ref.rs:23:11
+ |
+LL | match uninhab_ref() {
+ | ^^^^^^^^^^^^^
+ |
+ = note: the matched value is of type `&!`
+ = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match uninhab_ref() {
+LL + _ => todo!(),
+LL + }
+ |
+
+error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
+ --> $DIR/always-inhabited-union-ref.rs:27:11
+ |
+LL | match uninhab_union() {
+ | ^^^^^^^^^^^^^^^
+ |
+note: `Foo` defined here
+ --> $DIR/always-inhabited-union-ref.rs:10:11
+ |
+LL | pub union Foo {
+ | ^^^
+ = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match uninhab_union() {
+LL + _ => todo!(),
+LL + }
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/auxiliary/empty.rs b/tests/ui/pattern/usefulness/auxiliary/empty.rs
new file mode 100644
index 000000000..29a03c9e8
--- /dev/null
+++ b/tests/ui/pattern/usefulness/auxiliary/empty.rs
@@ -0,0 +1,10 @@
+#![crate_type = "rlib"]
+pub enum EmptyForeignEnum {}
+
+pub struct VisiblyUninhabitedForeignStruct {
+ pub field: EmptyForeignEnum,
+}
+
+pub struct SecretlyUninhabitedForeignStruct {
+ _priv: EmptyForeignEnum,
+}
diff --git a/tests/ui/pattern/usefulness/auxiliary/hidden.rs b/tests/ui/pattern/usefulness/auxiliary/hidden.rs
new file mode 100644
index 000000000..364514ba1
--- /dev/null
+++ b/tests/ui/pattern/usefulness/auxiliary/hidden.rs
@@ -0,0 +1,14 @@
+pub enum HiddenEnum {
+ A,
+ B,
+ #[doc(hidden)]
+ C,
+}
+
+#[derive(Default)]
+pub struct HiddenStruct {
+ pub one: u8,
+ pub two: bool,
+ #[doc(hidden)]
+ pub hide: usize,
+}
diff --git a/tests/ui/pattern/usefulness/auxiliary/unstable.rs b/tests/ui/pattern/usefulness/auxiliary/unstable.rs
new file mode 100644
index 000000000..a06b3a6e4
--- /dev/null
+++ b/tests/ui/pattern/usefulness/auxiliary/unstable.rs
@@ -0,0 +1,23 @@
+#![feature(staged_api)]
+#![stable(feature = "stable_test_feature", since = "1.0.0")]
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub enum UnstableEnum {
+ #[stable(feature = "stable_test_feature", since = "1.0.0")]
+ Stable,
+ #[stable(feature = "stable_test_feature", since = "1.0.0")]
+ Stable2,
+ #[unstable(feature = "unstable_test_feature", issue = "none")]
+ Unstable,
+}
+
+#[derive(Default)]
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub struct UnstableStruct {
+ #[stable(feature = "stable_test_feature", since = "1.0.0")]
+ pub stable: bool,
+ #[stable(feature = "stable_test_feature", since = "1.0.0")]
+ pub stable2: usize,
+ #[unstable(feature = "unstable_test_feature", issue = "none")]
+ pub unstable: u8,
+}
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
new file mode 100644
index 000000000..02599d7c0
--- /dev/null
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
@@ -0,0 +1,18 @@
+#![allow(warnings)]
+
+struct MyType;
+
+impl PartialEq<usize> for MyType {
+ fn eq(&self, y: &usize) -> bool {
+ true
+ }
+}
+
+const CONSTANT: &&MyType = &&MyType;
+
+fn main() {
+ if let CONSTANT = &&MyType {
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ println!("did match!");
+ }
+}
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
new file mode 100644
index 000000000..358421cd6
--- /dev/null
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
@@ -0,0 +1,8 @@
+error: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/const-partial_eq-fallback-ice.rs:14:12
+ |
+LL | if let CONSTANT = &&MyType {
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/usefulness/const-pat-ice.rs b/tests/ui/pattern/usefulness/const-pat-ice.rs
new file mode 100644
index 000000000..abfacf393
--- /dev/null
+++ b/tests/ui/pattern/usefulness/const-pat-ice.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+const FOO: &&&u32 = &&&42;
+
+fn main() {
+ match unimplemented!() {
+ &&&42 => {},
+ FOO => {},
+ _ => {},
+ }
+}
diff --git a/tests/ui/pattern/usefulness/const-private-fields.rs b/tests/ui/pattern/usefulness/const-private-fields.rs
new file mode 100644
index 000000000..06c832ca4
--- /dev/null
+++ b/tests/ui/pattern/usefulness/const-private-fields.rs
@@ -0,0 +1,30 @@
+// check-pass
+//
+// Check that we don't ignore private fields in usefulness checking
+#![deny(unreachable_patterns)]
+
+mod inner {
+ #[derive(PartialEq, Eq)]
+ pub struct PrivateField {
+ pub x: bool,
+ y: bool,
+ }
+
+ pub const FOO: PrivateField = PrivateField { x: true, y: true };
+ pub const BAR: PrivateField = PrivateField { x: true, y: false };
+}
+use inner::*;
+
+fn main() {
+ match FOO {
+ FOO => {}
+ BAR => {}
+ _ => {}
+ }
+
+ match FOO {
+ FOO => {}
+ PrivateField { x: true, .. } => {}
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs
new file mode 100644
index 000000000..ca4fcd85b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/consts-opaque.rs
@@ -0,0 +1,145 @@
+// This file tests the exhaustiveness algorithm on opaque constants. Most of the examples give
+// unnecessary warnings because const_to_pat.rs converts a constant pattern to a wildcard when the
+// constant is not allowed as a pattern. This is an edge case so we may not care to fix it.
+// See also https://github.com/rust-lang/rust/issues/78057
+
+#![deny(unreachable_patterns)]
+
+#[derive(PartialEq)]
+struct Foo(i32);
+impl Eq for Foo {}
+const FOO: Foo = Foo(42);
+const FOO_REF: &Foo = &Foo(42);
+const FOO_REF_REF: &&Foo = &&Foo(42);
+
+#[derive(PartialEq)]
+struct Bar;
+impl Eq for Bar {}
+const BAR: Bar = Bar;
+
+#[derive(PartialEq)]
+enum Baz {
+ Baz1,
+ Baz2
+}
+impl Eq for Baz {}
+const BAZ: Baz = Baz::Baz1;
+
+fn main() {
+ match FOO {
+ FOO => {}
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ _ => {} // should not be emitting unreachable warning
+ //~^ ERROR unreachable pattern
+ }
+
+ match FOO_REF {
+ FOO_REF => {}
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ Foo(_) => {} // should not be emitting unreachable warning
+ //~^ ERROR unreachable pattern
+ }
+
+ // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
+ match FOO_REF_REF {
+ FOO_REF_REF => {}
+ //~^ WARNING must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARNING this was previously accepted by the compiler but is being phased out
+ Foo(_) => {}
+ }
+
+ match BAR {
+ Bar => {}
+ BAR => {} // should not be emitting unreachable warning
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| ERROR unreachable pattern
+ _ => {}
+ //~^ ERROR unreachable pattern
+ }
+
+ match BAR {
+ BAR => {}
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ Bar => {} // should not be emitting unreachable warning
+ //~^ ERROR unreachable pattern
+ _ => {}
+ //~^ ERROR unreachable pattern
+ }
+
+ match BAR {
+ BAR => {}
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ BAR => {} // should not be emitting unreachable warning
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| ERROR unreachable pattern
+ _ => {} // should not be emitting unreachable warning
+ //~^ ERROR unreachable pattern
+ }
+
+ match BAZ {
+ BAZ => {}
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ Baz::Baz1 => {} // should not be emitting unreachable warning
+ //~^ ERROR unreachable pattern
+ _ => {}
+ //~^ ERROR unreachable pattern
+ }
+
+ match BAZ {
+ Baz::Baz1 => {}
+ BAZ => {}
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ _ => {}
+ //~^ ERROR unreachable pattern
+ }
+
+ match BAZ {
+ BAZ => {}
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ Baz::Baz2 => {} // should not be emitting unreachable warning
+ //~^ ERROR unreachable pattern
+ _ => {} // should not be emitting unreachable warning
+ //~^ ERROR unreachable pattern
+ }
+
+ type Quux = fn(usize, usize) -> usize;
+ fn quux(a: usize, b: usize) -> usize { a + b }
+ const QUUX: Quux = quux;
+
+ match QUUX {
+ QUUX => {}
+ QUUX => {}
+ _ => {}
+ }
+
+ #[derive(PartialEq, Eq)]
+ struct Wrap<T>(T);
+ const WRAPQUUX: Wrap<Quux> = Wrap(quux);
+
+ match WRAPQUUX {
+ WRAPQUUX => {}
+ WRAPQUUX => {}
+ Wrap(_) => {}
+ }
+
+ match WRAPQUUX {
+ Wrap(_) => {}
+ WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer
+ //~^ ERROR unreachable pattern
+ }
+
+ #[derive(PartialEq, Eq)]
+ enum WhoKnows<T> {
+ Yay(T),
+ Nope,
+ };
+ const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);
+
+ match WHOKNOWSQUUX {
+ WHOKNOWSQUUX => {}
+ WhoKnows::Yay(_) => {}
+ WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer
+ //~^ ERROR unreachable pattern
+ WhoKnows::Nope => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
new file mode 100644
index 000000000..35396751a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -0,0 +1,202 @@
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:30:9
+ |
+LL | FOO => {}
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:32:9
+ |
+LL | FOO => {}
+ | --- matches any value
+LL |
+LL | _ => {} // should not be emitting unreachable warning
+ | ^ unreachable pattern
+ |
+note: the lint level is defined here
+ --> $DIR/consts-opaque.rs:6:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:37:9
+ |
+LL | FOO_REF => {}
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:39:9
+ |
+LL | FOO_REF => {}
+ | ------- matches any value
+LL |
+LL | Foo(_) => {} // should not be emitting unreachable warning
+ | ^^^^^^ unreachable pattern
+
+warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:45:9
+ |
+LL | FOO_REF_REF => {}
+ | ^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+ = note: `#[warn(indirect_structural_match)]` on by default
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:53:9
+ |
+LL | BAR => {} // should not be emitting unreachable warning
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:53:9
+ |
+LL | Bar => {}
+ | --- matches any value
+LL | BAR => {} // should not be emitting unreachable warning
+ | ^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:56:9
+ |
+LL | Bar => {}
+ | --- matches any value
+...
+LL | _ => {}
+ | ^ unreachable pattern
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:61:9
+ |
+LL | BAR => {}
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:63:9
+ |
+LL | BAR => {}
+ | --- matches any value
+LL |
+LL | Bar => {} // should not be emitting unreachable warning
+ | ^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:65:9
+ |
+LL | BAR => {}
+ | --- matches any value
+...
+LL | _ => {}
+ | ^ unreachable pattern
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:70:9
+ |
+LL | BAR => {}
+ | ^^^
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:72:9
+ |
+LL | BAR => {} // should not be emitting unreachable warning
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:72:9
+ |
+LL | BAR => {}
+ | --- matches any value
+LL |
+LL | BAR => {} // should not be emitting unreachable warning
+ | ^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:75:9
+ |
+LL | BAR => {}
+ | --- matches any value
+...
+LL | _ => {} // should not be emitting unreachable warning
+ | ^ unreachable pattern
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:80:9
+ |
+LL | BAZ => {}
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:82:9
+ |
+LL | BAZ => {}
+ | --- matches any value
+LL |
+LL | Baz::Baz1 => {} // should not be emitting unreachable warning
+ | ^^^^^^^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:84:9
+ |
+LL | BAZ => {}
+ | --- matches any value
+...
+LL | _ => {}
+ | ^ unreachable pattern
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:90:9
+ |
+LL | BAZ => {}
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:92:9
+ |
+LL | BAZ => {}
+ | --- matches any value
+LL |
+LL | _ => {}
+ | ^ unreachable pattern
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/consts-opaque.rs:97:9
+ |
+LL | BAZ => {}
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:99:9
+ |
+LL | BAZ => {}
+ | --- matches any value
+LL |
+LL | Baz::Baz2 => {} // should not be emitting unreachable warning
+ | ^^^^^^^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:101:9
+ |
+LL | BAZ => {}
+ | --- matches any value
+...
+LL | _ => {} // should not be emitting unreachable warning
+ | ^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:127:9
+ |
+LL | Wrap(_) => {}
+ | ------- matches any value
+LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer
+ | ^^^^^^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:141:9
+ |
+LL | WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer
+ | ^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors; 1 warning emitted
+
diff --git a/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs b/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs
new file mode 100644
index 000000000..c85af7f3b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs
@@ -0,0 +1,16 @@
+#![feature(if_let_guard)]
+
+#![deny(irrefutable_let_patterns)]
+
+fn main() {
+ if let _ = 5 {} //~ ERROR irrefutable `if let` pattern
+
+ while let _ = 5 { //~ ERROR irrefutable `while let` pattern
+ break;
+ }
+
+ match 5 {
+ _ if let _ = 2 => {} //~ ERROR irrefutable `if let` guard pattern
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr
new file mode 100644
index 000000000..cdb6b5c7a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr
@@ -0,0 +1,34 @@
+error: irrefutable `if let` pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:6:8
+ |
+LL | if let _ = 5 {}
+ | ^^^^^^^^^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+note: the lint level is defined here
+ --> $DIR/deny-irrefutable-let-patterns.rs:3:9
+ |
+LL | #![deny(irrefutable_let_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: irrefutable `while let` pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:8:11
+ |
+LL | while let _ = 5 {
+ | ^^^^^^^^^
+ |
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
+
+error: irrefutable `if let` guard pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:13:18
+ |
+LL | _ if let _ = 2 => {}
+ | ^
+ |
+ = note: this pattern will always match, so the guard is useless
+ = help: consider removing the guard and adding a `let` inside the match arm
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/pattern/usefulness/doc-hidden-fields.rs b/tests/ui/pattern/usefulness/doc-hidden-fields.rs
new file mode 100644
index 000000000..4163b87dc
--- /dev/null
+++ b/tests/ui/pattern/usefulness/doc-hidden-fields.rs
@@ -0,0 +1,26 @@
+// aux-build:hidden.rs
+
+extern crate hidden;
+
+use hidden::HiddenStruct;
+
+struct InCrate {
+ a: usize,
+ b: bool,
+ #[doc(hidden)]
+ im_hidden: u8
+}
+
+fn main() {
+ let HiddenStruct { one, two } = HiddenStruct::default();
+ //~^ pattern requires `..` due to inaccessible fields
+
+ let HiddenStruct { one } = HiddenStruct::default();
+ //~^ pattern does not mention field `two` and inaccessible fields
+
+ let HiddenStruct { one, hide } = HiddenStruct::default();
+ //~^ pattern does not mention field `two`
+
+ let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
+ //~^ pattern does not mention field `im_hidden`
+}
diff --git a/tests/ui/pattern/usefulness/doc-hidden-fields.stderr b/tests/ui/pattern/usefulness/doc-hidden-fields.stderr
new file mode 100644
index 000000000..f277bfbc8
--- /dev/null
+++ b/tests/ui/pattern/usefulness/doc-hidden-fields.stderr
@@ -0,0 +1,59 @@
+error: pattern requires `..` due to inaccessible fields
+ --> $DIR/doc-hidden-fields.rs:15:9
+ |
+LL | let HiddenStruct { one, two } = HiddenStruct::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: ignore the inaccessible and unused fields
+ |
+LL | let HiddenStruct { one, two, .. } = HiddenStruct::default();
+ | ++++
+
+error[E0027]: pattern does not mention field `two` and inaccessible fields
+ --> $DIR/doc-hidden-fields.rs:18:9
+ |
+LL | let HiddenStruct { one } = HiddenStruct::default();
+ | ^^^^^^^^^^^^^^^^^^^^ missing field `two` and inaccessible fields
+ |
+help: include the missing field in the pattern and ignore the inaccessible fields
+ |
+LL | let HiddenStruct { one, two, .. } = HiddenStruct::default();
+ | ~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | let HiddenStruct { one, .. } = HiddenStruct::default();
+ | ~~~~~~
+
+error[E0027]: pattern does not mention field `two`
+ --> $DIR/doc-hidden-fields.rs:21:9
+ |
+LL | let HiddenStruct { one, hide } = HiddenStruct::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `two`
+ |
+help: include the missing field in the pattern
+ |
+LL | let HiddenStruct { one, hide, two } = HiddenStruct::default();
+ | ~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | let HiddenStruct { one, hide, .. } = HiddenStruct::default();
+ | ~~~~~~
+
+error[E0027]: pattern does not mention field `im_hidden`
+ --> $DIR/doc-hidden-fields.rs:24:9
+ |
+LL | let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
+ | ^^^^^^^^^^^^^^^^ missing field `im_hidden`
+ |
+help: include the missing field in the pattern
+ |
+LL | let InCrate { a, b, im_hidden } = InCrate { a: 0, b: false, im_hidden: 0 };
+ | ~~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | let InCrate { a, b, .. } = InCrate { a: 0, b: false, im_hidden: 0 };
+ | ~~~~~~
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
new file mode 100644
index 000000000..5d4181a30
--- /dev/null
+++ b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
@@ -0,0 +1,43 @@
+// aux-build:hidden.rs
+
+extern crate hidden;
+
+use hidden::HiddenEnum;
+
+enum InCrate {
+ A,
+ B,
+ #[doc(hidden)]
+ C,
+}
+
+fn main() {
+ match HiddenEnum::A {
+ HiddenEnum::A => {}
+ HiddenEnum::B => {}
+ }
+ //~^^^^ non-exhaustive patterns: `_` not covered
+
+ match HiddenEnum::A {
+ HiddenEnum::A => {}
+ HiddenEnum::C => {}
+ }
+ //~^^^^ non-exhaustive patterns: `HiddenEnum::B` not covered
+
+ match HiddenEnum::A {
+ HiddenEnum::A => {}
+ }
+ //~^^^ non-exhaustive patterns: `HiddenEnum::B` and `_` not covered
+
+ match None {
+ None => {}
+ Some(HiddenEnum::A) => {}
+ }
+ //~^^^^ non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered
+
+ match InCrate::A {
+ InCrate::A => {}
+ InCrate::B => {}
+ }
+ //~^^^^ non-exhaustive patterns: `InCrate::C` not covered
+}
diff --git a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
new file mode 100644
index 000000000..17e1a2304
--- /dev/null
+++ b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
@@ -0,0 +1,102 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/doc-hidden-non-exhaustive.rs:15:11
+ |
+LL | match HiddenEnum::A {
+ | ^^^^^^^^^^^^^ pattern `_` not covered
+ |
+note: `HiddenEnum` defined here
+ --> $DIR/auxiliary/hidden.rs:1:1
+ |
+LL | pub enum HiddenEnum {
+ | ^^^^^^^^^^^^^^^^^^^
+ = note: the matched value is of type `HiddenEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ HiddenEnum::B => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `HiddenEnum::B` not covered
+ --> $DIR/doc-hidden-non-exhaustive.rs:21:11
+ |
+LL | match HiddenEnum::A {
+ | ^^^^^^^^^^^^^ pattern `HiddenEnum::B` not covered
+ |
+note: `HiddenEnum` defined here
+ --> $DIR/auxiliary/hidden.rs:3:5
+ |
+LL | pub enum HiddenEnum {
+ | -------------------
+LL | A,
+LL | B,
+ | ^ not covered
+ = note: the matched value is of type `HiddenEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ HiddenEnum::C => {}
+LL + HiddenEnum::B => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `HiddenEnum::B` and `_` not covered
+ --> $DIR/doc-hidden-non-exhaustive.rs:27:11
+ |
+LL | match HiddenEnum::A {
+ | ^^^^^^^^^^^^^ patterns `HiddenEnum::B` and `_` not covered
+ |
+note: `HiddenEnum` defined here
+ --> $DIR/auxiliary/hidden.rs:3:5
+ |
+LL | pub enum HiddenEnum {
+ | -------------------
+LL | A,
+LL | B,
+ | ^ not covered
+ = note: the matched value is of type `HiddenEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ HiddenEnum::A => {}
+LL + HiddenEnum::B | _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered
+ --> $DIR/doc-hidden-non-exhaustive.rs:32:11
+ |
+LL | match None {
+ | ^^^^ patterns `Some(HiddenEnum::B)` and `Some(_)` not covered
+ |
+note: `Option<HiddenEnum>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: not covered
+ = note: the matched value is of type `Option<HiddenEnum>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Some(HiddenEnum::A) => {}
+LL + Some(HiddenEnum::B) | Some(_) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `InCrate::C` not covered
+ --> $DIR/doc-hidden-non-exhaustive.rs:38:11
+ |
+LL | match InCrate::A {
+ | ^^^^^^^^^^ pattern `InCrate::C` not covered
+ |
+note: `InCrate` defined here
+ --> $DIR/doc-hidden-non-exhaustive.rs:11:5
+ |
+LL | enum InCrate {
+ | -------
+...
+LL | C,
+ | ^ not covered
+ = note: the matched value is of type `InCrate`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ InCrate::B => {}
+LL + InCrate::C => todo!()
+ |
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
new file mode 100644
index 000000000..5e12bc1d2
--- /dev/null
+++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -0,0 +1,303 @@
+error: unreachable pattern
+ --> $DIR/empty-match.rs:37:9
+ |
+LL | _ => {},
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/empty-match.rs:8:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:40:9
+ |
+LL | _ if false => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:47:9
+ |
+LL | _ => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:50:9
+ |
+LL | _ if false => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:57:9
+ |
+LL | _ => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:60:9
+ |
+LL | _ if false => {},
+ | ^
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+ --> $DIR/empty-match.rs:78:20
+ |
+LL | match_no_arms!(0u8);
+ | ^^^
+ |
+ = note: the matched value is of type `u8`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
+ --> $DIR/empty-match.rs:79:20
+ |
+LL | match_no_arms!(NonEmptyStruct1);
+ | ^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
+ --> $DIR/empty-match.rs:80:20
+ |
+LL | match_no_arms!(NonEmptyStruct2(true));
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+ --> $DIR/empty-match.rs:81:20
+ |
+LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
+ |
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+ --> $DIR/empty-match.rs:82:20
+ |
+LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
+ |
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
+ --> $DIR/empty-match.rs:83:20
+ |
+LL | match_no_arms!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
+ |
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ --> $DIR/empty-match.rs:84:20
+ |
+LL | match_no_arms!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ --> $DIR/empty-match.rs:85:20
+ |
+LL | match_no_arms!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
+ |
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyEnum5`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/empty-match.rs:87:24
+ |
+LL | match_guarded_arm!(0u8);
+ | ^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
+ --> $DIR/empty-match.rs:88:24
+ |
+LL | match_guarded_arm!(NonEmptyStruct1);
+ | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
+ |
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct1 => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
+ --> $DIR/empty-match.rs:89:24
+ |
+LL | match_guarded_arm!(NonEmptyStruct2(true));
+ | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
+ |
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct2(_) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+ --> $DIR/empty-match.rs:90:24
+ |
+LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
+ |
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion1 { .. } => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+ --> $DIR/empty-match.rs:91:24
+ |
+LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
+ |
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion2 { .. } => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
+ --> $DIR/empty-match.rs:92:24
+ |
+LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
+ |
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyEnum1::Foo(_) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ --> $DIR/empty-match.rs:93:24
+ |
+LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ --> $DIR/empty-match.rs:94:24
+ |
+LL | match_guarded_arm!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
+ |
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
+
+error: aborting due to 22 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr
new file mode 100644
index 000000000..5e12bc1d2
--- /dev/null
+++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr
@@ -0,0 +1,303 @@
+error: unreachable pattern
+ --> $DIR/empty-match.rs:37:9
+ |
+LL | _ => {},
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/empty-match.rs:8:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:40:9
+ |
+LL | _ if false => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:47:9
+ |
+LL | _ => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:50:9
+ |
+LL | _ if false => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:57:9
+ |
+LL | _ => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/empty-match.rs:60:9
+ |
+LL | _ if false => {},
+ | ^
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+ --> $DIR/empty-match.rs:78:20
+ |
+LL | match_no_arms!(0u8);
+ | ^^^
+ |
+ = note: the matched value is of type `u8`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
+ --> $DIR/empty-match.rs:79:20
+ |
+LL | match_no_arms!(NonEmptyStruct1);
+ | ^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
+ --> $DIR/empty-match.rs:80:20
+ |
+LL | match_no_arms!(NonEmptyStruct2(true));
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+ --> $DIR/empty-match.rs:81:20
+ |
+LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
+ |
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+ --> $DIR/empty-match.rs:82:20
+ |
+LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
+ |
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
+ --> $DIR/empty-match.rs:83:20
+ |
+LL | match_no_arms!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
+ |
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ --> $DIR/empty-match.rs:84:20
+ |
+LL | match_no_arms!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ --> $DIR/empty-match.rs:85:20
+ |
+LL | match_no_arms!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
+ |
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyEnum5`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/empty-match.rs:87:24
+ |
+LL | match_guarded_arm!(0u8);
+ | ^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
+ --> $DIR/empty-match.rs:88:24
+ |
+LL | match_guarded_arm!(NonEmptyStruct1);
+ | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
+ |
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct1 => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
+ --> $DIR/empty-match.rs:89:24
+ |
+LL | match_guarded_arm!(NonEmptyStruct2(true));
+ | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
+ |
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct2(_) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+ --> $DIR/empty-match.rs:90:24
+ |
+LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
+ |
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion1 { .. } => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+ --> $DIR/empty-match.rs:91:24
+ |
+LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
+ |
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion2 { .. } => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
+ --> $DIR/empty-match.rs:92:24
+ |
+LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
+ |
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyEnum1::Foo(_) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ --> $DIR/empty-match.rs:93:24
+ |
+LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
+ = note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ --> $DIR/empty-match.rs:94:24
+ |
+LL | match_guarded_arm!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
+ |
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
+ = note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
+
+error: aborting due to 22 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.rs b/tests/ui/pattern/usefulness/empty-match.rs
new file mode 100644
index 000000000..9cdc0413b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/empty-match.rs
@@ -0,0 +1,95 @@
+// aux-build:empty.rs
+// revisions: normal exhaustive_patterns
+//
+// This tests a match with no arms on various types.
+#![feature(never_type)]
+#![feature(never_type_fallback)]
+#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
+#![deny(unreachable_patterns)]
+
+extern crate empty;
+
+enum EmptyEnum {}
+
+struct NonEmptyStruct1;
+struct NonEmptyStruct2(bool);
+union NonEmptyUnion1 {
+ foo: (),
+}
+union NonEmptyUnion2 {
+ foo: (),
+ bar: (),
+}
+enum NonEmptyEnum1 {
+ Foo(bool),
+}
+enum NonEmptyEnum2 {
+ Foo(bool),
+ Bar,
+}
+enum NonEmptyEnum5 {
+ V1, V2, V3, V4, V5,
+}
+
+fn empty_enum(x: EmptyEnum) {
+ match x {} // ok
+ match x {
+ _ => {}, //~ ERROR unreachable pattern
+ }
+ match x {
+ _ if false => {}, //~ ERROR unreachable pattern
+ }
+}
+
+fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
+ match x {} // ok
+ match x {
+ _ => {}, //~ ERROR unreachable pattern
+ }
+ match x {
+ _ if false => {}, //~ ERROR unreachable pattern
+ }
+}
+
+fn never(x: !) {
+ match x {} // ok
+ match x {
+ _ => {}, //~ ERROR unreachable pattern
+ }
+ match x {
+ _ if false => {}, //~ ERROR unreachable pattern
+ }
+}
+
+macro_rules! match_no_arms {
+ ($e:expr) => {
+ match $e {}
+ };
+}
+macro_rules! match_guarded_arm {
+ ($e:expr) => {
+ match $e {
+ _ if false => {}
+ }
+ };
+}
+
+fn main() {
+ match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
+ match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty
+ match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty
+ match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty
+ match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty
+ match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
+ match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+
+ match_guarded_arm!(0u8); //~ ERROR `_` not covered
+ match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered
+ match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered
+ match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered
+ match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered
+ match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
+ match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+ match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+}
diff --git a/tests/ui/pattern/usefulness/floats.rs b/tests/ui/pattern/usefulness/floats.rs
new file mode 100644
index 000000000..095f5ac9a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/floats.rs
@@ -0,0 +1,19 @@
+#![allow(illegal_floating_point_literal_pattern)]
+#![deny(unreachable_patterns)]
+
+fn main() {
+ match 0.0 {
+ 0.0..=1.0 => {}
+ _ => {} // ok
+ }
+
+ match 0.0 { //~ ERROR non-exhaustive patterns
+ 0.0..=1.0 => {}
+ }
+
+ match 1.0f64 {
+ 0.01f64 ..= 6.5f64 => {}
+ 0.02f64 => {} //~ ERROR unreachable pattern
+ _ => {}
+ };
+}
diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr
new file mode 100644
index 000000000..c926e50b3
--- /dev/null
+++ b/tests/ui/pattern/usefulness/floats.stderr
@@ -0,0 +1,28 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/floats.rs:10:11
+ |
+LL | match 0.0 {
+ | ^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `f64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0.0..=1.0 => {}
+LL + _ => todo!()
+ |
+
+error: unreachable pattern
+ --> $DIR/floats.rs:16:7
+ |
+LL | 0.02f64 => {}
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/floats.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/guards.rs b/tests/ui/pattern/usefulness/guards.rs
new file mode 100644
index 000000000..b15440cf6
--- /dev/null
+++ b/tests/ui/pattern/usefulness/guards.rs
@@ -0,0 +1,22 @@
+#![feature(exclusive_range_pattern)]
+#![deny(unreachable_patterns)]
+
+enum Q { R(Option<usize>) }
+
+pub fn main() {
+ match Q::R(None) {
+ Q::R(S) if S.is_some() => {}
+ _ => {}
+ }
+
+ match 0u8 { //~ ERROR non-exhaustive patterns
+ 0 .. 128 => {}
+ 128 ..= 255 if true => {}
+ }
+
+ match 0u8 {
+ 0 .. 128 => {}
+ 128 ..= 255 if false => {}
+ 128 ..= 255 => {} // ok, because previous arm was guarded
+ }
+}
diff --git a/tests/ui/pattern/usefulness/guards.stderr b/tests/ui/pattern/usefulness/guards.stderr
new file mode 100644
index 000000000..0c1563c16
--- /dev/null
+++ b/tests/ui/pattern/usefulness/guards.stderr
@@ -0,0 +1,16 @@
+error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
+ --> $DIR/guards.rs:12:11
+ |
+LL | match 0u8 {
+ | ^^^ pattern `128_u8..=u8::MAX` not covered
+ |
+ = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 128 ..= 255 if true => {}
+LL + 128_u8..=u8::MAX => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs
new file mode 100644
index 000000000..0f5f49c4c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs
@@ -0,0 +1,101 @@
+#![feature(exclusive_range_pattern)]
+#![allow(overlapping_range_endpoints)]
+#![deny(unreachable_patterns)]
+
+macro_rules! m {
+ ($s:expr, $($t:tt)+) => {
+ match $s { $($t)+ => {} }
+ }
+}
+
+macro_rules! test_int {
+ ($s:expr, $min:path, $max:path) => {
+ m!($s, $min..=$max);
+ m!($s, $min..5 | 5..=$max);
+ m!($s, $min..=4 | 5..=$max);
+ m!($s, $min..$max | $max);
+ m!(($s, true), ($min..5, true) | (5..=$max, true) | ($min..=$max, false));
+ }
+}
+
+fn main() {
+ test_int!(0u8, u8::MIN, u8::MAX);
+ test_int!(0u16, u16::MIN, u16::MAX);
+ test_int!(0u32, u32::MIN, u32::MAX);
+ test_int!(0u64, u64::MIN, u64::MAX);
+ test_int!(0u128, u128::MIN, u128::MAX);
+
+ test_int!(0i8, i8::MIN, i8::MAX);
+ test_int!(0i16, i16::MIN, i16::MAX);
+ test_int!(0i32, i32::MIN, i32::MAX);
+ test_int!(0i64, i64::MIN, i64::MAX);
+ test_int!(0i128, i128::MIN, i128::MAX);
+
+ m!('a', '\u{0}'..=char::MAX);
+ m!('a', '\u{0}'..='\u{10_FFFF}');
+ // We can get away with just covering the following two ranges, which correspond to all valid
+ // Unicode Scalar Values.
+ m!('a', '\u{0}'..='\u{D7FF}' | '\u{E000}'..=char::MAX);
+ m!('a', '\u{0}'..'\u{D7FF}' | '\u{D7FF}' | '\u{E000}'..=char::MAX);
+
+ let 0..=255 = 0u8;
+ let -128..=127 = 0i8;
+ let -2147483648..=2147483647 = 0i32;
+ let '\u{0000}'..='\u{10FFFF}' = 'v';
+
+ // Almost exhaustive
+ m!(0u8, 0..255); //~ ERROR non-exhaustive patterns
+ m!(0u8, 0..=254); //~ ERROR non-exhaustive patterns
+ m!(0u8, 1..=255); //~ ERROR non-exhaustive patterns
+ m!(0u8, 0..42 | 43..=255); //~ ERROR non-exhaustive patterns
+ m!(0i8, -128..127); //~ ERROR non-exhaustive patterns
+ m!(0i8, -128..=126); //~ ERROR non-exhaustive patterns
+ m!(0i8, -127..=127); //~ ERROR non-exhaustive patterns
+ match 0i8 { //~ ERROR non-exhaustive patterns
+ i8::MIN ..= -1 => {}
+ 1 ..= i8::MAX => {}
+ }
+ const ALMOST_MAX: u128 = u128::MAX - 1;
+ m!(0u128, 0..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+ m!(0u128, 0..=4); //~ ERROR non-exhaustive patterns
+ m!(0u128, 1..=u128::MAX); //~ ERROR non-exhaustive patterns
+
+ // More complicatedly (non-)exhaustive
+ match 0u8 {
+ 0 ..= 30 => {}
+ 20 ..= 70 => {}
+ 50 ..= 255 => {}
+ }
+ match (0u8, true) { //~ ERROR non-exhaustive patterns
+ (0 ..= 125, false) => {}
+ (128 ..= 255, false) => {}
+ (0 ..= 255, true) => {}
+ }
+ match (0u8, true) { // ok
+ (0 ..= 125, false) => {}
+ (128 ..= 255, false) => {}
+ (0 ..= 255, true) => {}
+ (125 .. 128, false) => {}
+ }
+ match (true, 0u8) {
+ (true, 0 ..= 255) => {}
+ (false, 0 ..= 125) => {}
+ (false, 128 ..= 255) => {}
+ (false, 125 .. 128) => {}
+ }
+ match Some(0u8) {
+ None => {}
+ Some(0 ..= 125) => {}
+ Some(128 ..= 255) => {}
+ Some(125 .. 128) => {}
+ }
+ const FOO: u8 = 41;
+ const BAR: &u8 = &42;
+ match &0u8 {
+ 0..41 => {}
+ &FOO => {}
+ BAR => {}
+ 43..=255 => {}
+ }
+
+}
diff --git a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
new file mode 100644
index 000000000..f30ba05df
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
@@ -0,0 +1,149 @@
+error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:47:8
+ |
+LL | m!(0u8, 0..255);
+ | ^^^ pattern `u8::MAX` not covered
+ |
+ = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, u8::MAX => todo!() }
+ | ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:48:8
+ |
+LL | m!(0u8, 0..=254);
+ | ^^^ pattern `u8::MAX` not covered
+ |
+ = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, u8::MAX => todo!() }
+ | ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_u8` not covered
+ --> $DIR/exhaustiveness.rs:49:8
+ |
+LL | m!(0u8, 1..=255);
+ | ^^^ pattern `0_u8` not covered
+ |
+ = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, 0_u8 => todo!() }
+ | +++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `42_u8` not covered
+ --> $DIR/exhaustiveness.rs:50:8
+ |
+LL | m!(0u8, 0..42 | 43..=255);
+ | ^^^ pattern `42_u8` not covered
+ |
+ = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, 42_u8 => todo!() }
+ | ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:51:8
+ |
+LL | m!(0i8, -128..127);
+ | ^^^ pattern `i8::MAX` not covered
+ |
+ = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, i8::MAX => todo!() }
+ | ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:52:8
+ |
+LL | m!(0i8, -128..=126);
+ | ^^^ pattern `i8::MAX` not covered
+ |
+ = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, i8::MAX => todo!() }
+ | ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
+ --> $DIR/exhaustiveness.rs:53:8
+ |
+LL | m!(0i8, -127..=127);
+ | ^^^ pattern `i8::MIN` not covered
+ |
+ = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, i8::MIN => todo!() }
+ | ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_i8` not covered
+ --> $DIR/exhaustiveness.rs:54:11
+ |
+LL | match 0i8 {
+ | ^^^ pattern `0_i8` not covered
+ |
+ = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 1 ..= i8::MAX => {}
+LL + 0_i8 => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
+ --> $DIR/exhaustiveness.rs:59:8
+ |
+LL | m!(0u128, 0..=ALMOST_MAX);
+ | ^^^^^ pattern `u128::MAX` not covered
+ |
+ = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, u128::MAX => todo!() }
+ | ++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
+ --> $DIR/exhaustiveness.rs:60:8
+ |
+LL | m!(0u128, 0..=4);
+ | ^^^^^ pattern `5_u128..=u128::MAX` not covered
+ |
+ = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, 5_u128..=u128::MAX => todo!() }
+ | +++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_u128` not covered
+ --> $DIR/exhaustiveness.rs:61:8
+ |
+LL | m!(0u128, 1..=u128::MAX);
+ | ^^^^^ pattern `0_u128` not covered
+ |
+ = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, 0_u128 => todo!() }
+ | +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
+ --> $DIR/exhaustiveness.rs:69:11
+ |
+LL | match (0u8, true) {
+ | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
+ |
+ = note: the matched value is of type `(u8, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (0 ..= 255, true) => {}
+LL + (126_u8..=127_u8, false) => todo!()
+ |
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs
new file mode 100644
index 000000000..5ea92b070
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs
@@ -0,0 +1,59 @@
+#![feature(exclusive_range_pattern)]
+#![deny(overlapping_range_endpoints)]
+
+macro_rules! m {
+ ($s:expr, $t1:pat, $t2:pat) => {
+ match $s {
+ $t1 => {}
+ $t2 => {}
+ _ => {}
+ }
+ }
+}
+
+fn main() {
+ m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns overlap on their endpoints
+ m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns overlap on their endpoints
+ m!(0u8, 20..=30, 31..=40);
+ m!(0u8, 20..=30, 29..=40);
+ m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints
+ m!(0u8, 20.. 30, 28..=40);
+ m!(0u8, 20.. 30, 30..=40);
+ m!(0u8, 20..=30, 30..=30);
+ m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns overlap on their endpoints
+ m!(0u8, 20..=30, 29..=30);
+ m!(0u8, 20..=30, 20..=20);
+ m!(0u8, 20..=30, 20..=21);
+ m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns overlap on their endpoints
+ m!(0u8, 20..=30, 20);
+ m!(0u8, 20..=30, 25);
+ m!(0u8, 20..=30, 30);
+ m!(0u8, 20.. 30, 29);
+ m!(0u8, 20, 20..=30);
+ m!(0u8, 25, 20..=30);
+ m!(0u8, 30, 20..=30);
+
+ match 0u8 {
+ 0..=10 => {}
+ 20..=30 => {}
+ 10..=20 => {} //~ ERROR multiple patterns overlap on their endpoints
+ _ => {}
+ }
+ match (0u8, true) {
+ (0..=10, true) => {}
+ (10..20, true) => {} // not detected
+ (10..20, false) => {}
+ _ => {}
+ }
+ match (true, 0u8) {
+ (true, 0..=10) => {}
+ (true, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints
+ (false, 10..20) => {}
+ _ => {}
+ }
+ match Some(0u8) {
+ Some(0..=10) => {}
+ Some(10..20) => {} //~ ERROR multiple patterns overlap on their endpoints
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr
new file mode 100644
index 000000000..ea0e8f6e4
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr
@@ -0,0 +1,89 @@
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:15:22
+ |
+LL | m!(0u8, 20..=30, 30..=40);
+ | ------- ^^^^^^^ ... with this range
+ | |
+ | this range overlaps on `30_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
+note: the lint level is defined here
+ --> $DIR/overlapping_range_endpoints.rs:2:9
+ |
+LL | #![deny(overlapping_range_endpoints)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:16:22
+ |
+LL | m!(0u8, 30..=40, 20..=30);
+ | ------- ^^^^^^^ ... with this range
+ | |
+ | this range overlaps on `30_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
+
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:19:22
+ |
+LL | m!(0u8, 20.. 30, 29..=40);
+ | ------- ^^^^^^^ ... with this range
+ | |
+ | this range overlaps on `29_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
+
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:23:22
+ |
+LL | m!(0u8, 20..=30, 30..=31);
+ | ------- ^^^^^^^ ... with this range
+ | |
+ | this range overlaps on `30_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
+
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:27:22
+ |
+LL | m!(0u8, 20..=30, 19..=20);
+ | ------- ^^^^^^^ ... with this range
+ | |
+ | this range overlaps on `20_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
+
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:39:9
+ |
+LL | 0..=10 => {}
+ | ------ this range overlaps on `10_u8`...
+LL | 20..=30 => {}
+ | ------- this range overlaps on `20_u8`...
+LL | 10..=20 => {}
+ | ^^^^^^^ ... with this range
+ |
+ = note: you likely meant to write mutually exclusive ranges
+
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:50:16
+ |
+LL | (true, 0..=10) => {}
+ | ------ this range overlaps on `10_u8`...
+LL | (true, 10..20) => {}
+ | ^^^^^^ ... with this range
+ |
+ = note: you likely meant to write mutually exclusive ranges
+
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:56:14
+ |
+LL | Some(0..=10) => {}
+ | ------ this range overlaps on `10_u8`...
+LL | Some(10..20) => {}
+ | ^^^^^^ ... with this range
+ |
+ = note: you likely meant to write mutually exclusive ranges
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
new file mode 100644
index 000000000..9f277fa1e
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
@@ -0,0 +1,17 @@
+error[E0004]: non-exhaustive patterns: type `usize` is non-empty
+ --> $DIR/pointer-sized-int.rs:48:11
+ |
+LL | match 7usize {}
+ | ^^^^^^
+ |
+ = note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match 7usize {
+LL + _ => todo!(),
+LL + }
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
new file mode 100644
index 000000000..e3eb98ccd
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
@@ -0,0 +1,170 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:12:11
+ |
+LL | match 0usize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0 ..= usize::MAX => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:17:11
+ |
+LL | match 0isize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN ..= isize::MAX => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:22:8
+ |
+LL | m!(0usize, 0..=usize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, _ => todo!() }
+ | ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:24:8
+ |
+LL | m!(0usize, 0..5 | 5..=usize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, _ => todo!() }
+ | ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:26:8
+ |
+LL | m!(0usize, 0..usize::MAX | usize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, _ => todo!() }
+ | ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+ --> $DIR/pointer-sized-int.rs:28:8
+ |
+LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
+ | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+ |
+ = note: the matched value is of type `(usize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, (_, _) => todo!() }
+ | +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:31:8
+ |
+LL | m!(0isize, isize::MIN..=isize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, _ => todo!() }
+ | ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:33:8
+ |
+LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, _ => todo!() }
+ | ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:35:8
+ |
+LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, _ => todo!() }
+ | ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+ --> $DIR/pointer-sized-int.rs:37:8
+ |
+LL | m!((0isize, true), (isize::MIN..5, true)
+ | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+ |
+ = note: the matched value is of type `(isize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match $s { $($t)+ => {}, (_, _) => todo!() }
+ | +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int.rs:41:11
+ |
+LL | match 0isize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 1 ..= isize::MAX => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: type `usize` is non-empty
+ --> $DIR/pointer-sized-int.rs:48:11
+ |
+LL | match 7usize {}
+ | ^^^^^^
+ |
+ = note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match 7usize {
+LL + _ => todo!(),
+LL + }
+ |
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
new file mode 100644
index 000000000..1ed18c267
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
@@ -0,0 +1,50 @@
+// revisions: allow deny
+#![feature(exclusive_range_pattern)]
+#![cfg_attr(allow, feature(precise_pointer_size_matching))]
+
+macro_rules! m {
+ ($s:expr, $($t:tt)+) => {
+ match $s { $($t)+ => {} }
+ }
+}
+
+fn main() {
+ match 0usize {
+ //[deny]~^ ERROR non-exhaustive patterns
+ 0 ..= usize::MAX => {}
+ }
+
+ match 0isize {
+ //[deny]~^ ERROR non-exhaustive patterns
+ isize::MIN ..= isize::MAX => {}
+ }
+
+ m!(0usize, 0..=usize::MAX);
+ //[deny]~^ ERROR non-exhaustive patterns
+ m!(0usize, 0..5 | 5..=usize::MAX);
+ //[deny]~^ ERROR non-exhaustive patterns
+ m!(0usize, 0..usize::MAX | usize::MAX);
+ //[deny]~^ ERROR non-exhaustive patterns
+ m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
+ //[deny]~^ ERROR non-exhaustive patterns
+
+ m!(0isize, isize::MIN..=isize::MAX);
+ //[deny]~^ ERROR non-exhaustive patterns
+ m!(0isize, isize::MIN..5 | 5..=isize::MAX);
+ //[deny]~^ ERROR non-exhaustive patterns
+ m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+ //[deny]~^ ERROR non-exhaustive patterns
+ m!((0isize, true), (isize::MIN..5, true)
+ | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
+ //[deny]~^^ ERROR non-exhaustive patterns
+
+ match 0isize {
+ //[deny]~^ ERROR non-exhaustive patterns
+ isize::MIN ..= -1 => {}
+ 0 => {}
+ 1 ..= isize::MAX => {}
+ }
+
+ match 7usize {}
+ //~^ ERROR non-exhaustive patterns
+}
diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs
new file mode 100644
index 000000000..a2aa655ca
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs
@@ -0,0 +1,18 @@
+// This tests that the lint message explains the reason for the error.
+fn main() {
+ match 0usize {
+ //~^ ERROR non-exhaustive patterns: `_` not covered
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `usize`
+ //~| NOTE `usize` does not have a fixed maximum value
+ 0..=usize::MAX => {}
+ }
+
+ match 0isize {
+ //~^ ERROR non-exhaustive patterns: `_` not covered
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `isize`
+ //~| NOTE `isize` does not have a fixed maximum value
+ isize::MIN..=isize::MAX => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
new file mode 100644
index 000000000..30492c982
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
@@ -0,0 +1,33 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/precise_pointer_matching-message.rs:3:11
+ |
+LL | match 0usize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0..=usize::MAX => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/precise_pointer_matching-message.rs:11:11
+ |
+LL | match 0isize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN..=isize::MAX => {}
+LL + _ => todo!()
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.rs b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs
new file mode 100644
index 000000000..fb4d59b05
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs
@@ -0,0 +1,113 @@
+#![feature(exclusive_range_pattern)]
+#![allow(overlapping_range_endpoints)]
+#![deny(unreachable_patterns)]
+
+macro_rules! m {
+ ($s:expr, $t1:pat, $t2:pat) => {
+ match $s {
+ $t1 => {}
+ $t2 => {}
+ _ => {}
+ }
+ }
+}
+
+fn main() {
+ m!(0u8, 42, 41);
+ m!(0u8, 42, 42); //~ ERROR unreachable pattern
+ m!(0u8, 42, 43);
+
+ m!(0u8, 20..=30, 19);
+ m!(0u8, 20..=30, 20); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 21); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 25); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 29); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 31);
+ m!(0u8, 20..30, 19);
+ m!(0u8, 20..30, 20); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 21); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 25); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 29); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 30);
+ m!(0u8, 20..30, 31);
+
+ m!(0u8, 20..=30, 20..=30); //~ ERROR unreachable pattern
+ m!(0u8, 20.. 30, 20.. 30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 20.. 30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 19..=30);
+ m!(0u8, 20..=30, 21..=30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 20..=29); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 20..=31);
+ m!('a', 'A'..='z', 'a'..='z'); //~ ERROR unreachable pattern
+
+ match 0u8 {
+ 5 => {},
+ 6 => {},
+ 7 => {},
+ 8 => {},
+ 5..=8 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0u8 {
+ 0..10 => {},
+ 10..20 => {},
+ 5..15 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0u8 {
+ 0..10 => {},
+ 10..20 => {},
+ 20..30 => {},
+ 5..25 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0u8 {
+ 0..10 => {},
+ 10 => {},
+ 11..=23 => {},
+ 19..30 => {},
+ 5..25 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0usize {
+ 0..10 => {},
+ 10..20 => {},
+ 5..15 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ // Chars between '\u{D7FF}' and '\u{E000}' are invalid even though ranges that contain them are
+ // allowed.
+ match 'a' {
+ _ => {},
+ '\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern
+ }
+ match 'a' {
+ '\u{0}'..='\u{D7FF}' => {},
+ '\u{E000}'..='\u{10_FFFF}' => {},
+ '\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable
+ }
+
+ match (0u8, true) {
+ (0..=255, false) => {}
+ (0..=255, true) => {} // ok
+ }
+ match (true, 0u8) {
+ (false, 0..=255) => {}
+ (true, 0..=255) => {} // ok
+ }
+
+ const FOO: i32 = 42;
+ const BAR: &i32 = &42;
+ match &0 {
+ &42 => {}
+ &FOO => {} //~ ERROR unreachable pattern
+ BAR => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+ // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933
+ match &0 {
+ BAR => {} // ok
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr
new file mode 100644
index 000000000..0ffb0ffd8
--- /dev/null
+++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr
@@ -0,0 +1,154 @@
+error: unreachable pattern
+ --> $DIR/reachability.rs:17:17
+ |
+LL | m!(0u8, 42, 42);
+ | ^^
+ |
+note: the lint level is defined here
+ --> $DIR/reachability.rs:3:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:21:22
+ |
+LL | m!(0u8, 20..=30, 20);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:22:22
+ |
+LL | m!(0u8, 20..=30, 21);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:23:22
+ |
+LL | m!(0u8, 20..=30, 25);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:24:22
+ |
+LL | m!(0u8, 20..=30, 29);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:25:22
+ |
+LL | m!(0u8, 20..=30, 30);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:28:21
+ |
+LL | m!(0u8, 20..30, 20);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:29:21
+ |
+LL | m!(0u8, 20..30, 21);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:30:21
+ |
+LL | m!(0u8, 20..30, 25);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:31:21
+ |
+LL | m!(0u8, 20..30, 29);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:35:22
+ |
+LL | m!(0u8, 20..=30, 20..=30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:36:22
+ |
+LL | m!(0u8, 20.. 30, 20.. 30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:37:22
+ |
+LL | m!(0u8, 20..=30, 20.. 30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:39:22
+ |
+LL | m!(0u8, 20..=30, 21..=30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:40:22
+ |
+LL | m!(0u8, 20..=30, 20..=29);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:42:24
+ |
+LL | m!('a', 'A'..='z', 'a'..='z');
+ | ^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:49:9
+ |
+LL | 5..=8 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:55:9
+ |
+LL | 5..15 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:62:9
+ |
+LL | 5..25 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:70:9
+ |
+LL | 5..25 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:76:9
+ |
+LL | 5..15 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:83:9
+ |
+LL | _ => {},
+ | - matches any value
+LL | '\u{D7FF}'..='\u{E000}' => {},
+ | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:104:9
+ |
+LL | &FOO => {}
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:105:9
+ |
+LL | BAR => {}
+ | ^^^
+
+error: aborting due to 24 previous errors
+
diff --git a/tests/ui/pattern/usefulness/irrefutable-let-patterns.rs b/tests/ui/pattern/usefulness/irrefutable-let-patterns.rs
new file mode 100644
index 000000000..d400ef0bb
--- /dev/null
+++ b/tests/ui/pattern/usefulness/irrefutable-let-patterns.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+#![allow(irrefutable_let_patterns)]
+
+fn main() {
+ if let _ = 5 {}
+
+ while let _ = 5 {
+ break;
+ }
+}
diff --git a/tests/ui/pattern/usefulness/irrefutable-unit.rs b/tests/ui/pattern/usefulness/irrefutable-unit.rs
new file mode 100644
index 000000000..dd8f03b6d
--- /dev/null
+++ b/tests/ui/pattern/usefulness/irrefutable-unit.rs
@@ -0,0 +1,6 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+pub fn main() {
+ let ((),()) = ((),());
+}
diff --git a/tests/ui/pattern/usefulness/issue-12116.rs b/tests/ui/pattern/usefulness/issue-12116.rs
new file mode 100644
index 000000000..3cb92a540
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-12116.rs
@@ -0,0 +1,21 @@
+#![feature(box_patterns)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![deny(unreachable_patterns)]
+
+
+enum IntList {
+ Cons(isize, Box<IntList>),
+ Nil
+}
+
+fn tail(source_list: &IntList) -> IntList {
+ match source_list {
+ &IntList::Cons(val, box ref next_list) => tail(next_list),
+ &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)),
+ //~^ ERROR unreachable pattern
+ _ => panic!(),
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/issue-12116.stderr b/tests/ui/pattern/usefulness/issue-12116.stderr
new file mode 100644
index 000000000..7f15c4703
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-12116.stderr
@@ -0,0 +1,14 @@
+error: unreachable pattern
+ --> $DIR/issue-12116.rs:15:9
+ |
+LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-12116.rs:4:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/usefulness/issue-12369.rs b/tests/ui/pattern/usefulness/issue-12369.rs
new file mode 100644
index 000000000..0481c1fd9
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-12369.rs
@@ -0,0 +1,11 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let sl = vec![1,2,3];
+ let v: isize = match &*sl {
+ &[] => 0,
+ &[a,b,c] => 3,
+ &[a, ref rest @ ..] => a,
+ &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern
+ };
+}
diff --git a/tests/ui/pattern/usefulness/issue-12369.stderr b/tests/ui/pattern/usefulness/issue-12369.stderr
new file mode 100644
index 000000000..aab2be78c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-12369.stderr
@@ -0,0 +1,14 @@
+error: unreachable pattern
+ --> $DIR/issue-12369.rs:9:9
+ |
+LL | &[10,a, ref rest @ ..] => 10
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-12369.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/usefulness/issue-13727.rs b/tests/ui/pattern/usefulness/issue-13727.rs
new file mode 100644
index 000000000..7fb565ef3
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-13727.rs
@@ -0,0 +1,15 @@
+#![allow(overflowing_literals)]
+#![deny(unreachable_patterns)]
+
+fn test(val: u8) {
+ match val {
+ 256 => print!("0b1110\n"),
+ 512 => print!("0b1111\n"),
+ //~^ ERROR: unreachable pattern
+ _ => print!("fail\n"),
+ }
+}
+
+fn main() {
+ test(1);
+}
diff --git a/tests/ui/pattern/usefulness/issue-13727.stderr b/tests/ui/pattern/usefulness/issue-13727.stderr
new file mode 100644
index 000000000..07ca56a56
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-13727.stderr
@@ -0,0 +1,14 @@
+error: unreachable pattern
+ --> $DIR/issue-13727.rs:7:5
+ |
+LL | 512 => print!("0b1111\n"),
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-13727.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/usefulness/issue-15129.rs b/tests/ui/pattern/usefulness/issue-15129.rs
new file mode 100644
index 000000000..f02e5c0c6
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-15129.rs
@@ -0,0 +1,17 @@
+pub enum T {
+ T1(()),
+ T2(()),
+}
+
+pub enum V {
+ V1(isize),
+ V2(bool),
+}
+
+fn main() {
+ match (T::T1(()), V::V2(true)) {
+ //~^ ERROR non-exhaustive patterns: `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered
+ (T::T1(()), V::V1(i)) => (),
+ (T::T2(()), V::V2(b)) => (),
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-15129.stderr b/tests/ui/pattern/usefulness/issue-15129.stderr
new file mode 100644
index 000000000..ee8410b76
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-15129.stderr
@@ -0,0 +1,16 @@
+error[E0004]: non-exhaustive patterns: `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered
+ --> $DIR/issue-15129.rs:12:11
+ |
+LL | match (T::T1(()), V::V2(true)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered
+ |
+ = note: the matched value is of type `(T, V)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (T::T2(()), V::V2(b)) => (),
+LL ~ (T::T1(()), V::V2(_)) | (T::T2(()), V::V1(_)) => todo!(),
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-2111.rs b/tests/ui/pattern/usefulness/issue-2111.rs
new file mode 100644
index 000000000..d27beaeff
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-2111.rs
@@ -0,0 +1,11 @@
+fn foo(a: Option<usize>, b: Option<usize>) {
+ match (a, b) {
+ //~^ ERROR: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered
+ (Some(a), Some(b)) if a == b => {}
+ (Some(_), None) | (None, Some(_)) => {}
+ }
+}
+
+fn main() {
+ foo(None, None);
+}
diff --git a/tests/ui/pattern/usefulness/issue-2111.stderr b/tests/ui/pattern/usefulness/issue-2111.stderr
new file mode 100644
index 000000000..01890b73c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-2111.stderr
@@ -0,0 +1,16 @@
+error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered
+ --> $DIR/issue-2111.rs:2:11
+ |
+LL | match (a, b) {
+ | ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
+ |
+ = note: the matched value is of type `(Option<usize>, Option<usize>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (Some(_), None) | (None, Some(_)) => {}
+LL + (None, None) | (Some(_), Some(_)) => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-30240-b.rs b/tests/ui/pattern/usefulness/issue-30240-b.rs
new file mode 100644
index 000000000..01a6e7d8c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-30240-b.rs
@@ -0,0 +1,15 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ match "world" {
+ "hello" => {}
+ _ => {},
+ }
+
+ match "world" {
+ ref _x if false => {}
+ "hello" => {}
+ "hello" => {} //~ ERROR unreachable pattern
+ _ => {},
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-30240-b.stderr b/tests/ui/pattern/usefulness/issue-30240-b.stderr
new file mode 100644
index 000000000..59d64bc25
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-30240-b.stderr
@@ -0,0 +1,14 @@
+error: unreachable pattern
+ --> $DIR/issue-30240-b.rs:12:9
+ |
+LL | "hello" => {}
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-30240-b.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/usefulness/issue-30240-rpass.rs b/tests/ui/pattern/usefulness/issue-30240-rpass.rs
new file mode 100644
index 000000000..ab16614fd
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-30240-rpass.rs
@@ -0,0 +1,14 @@
+// run-pass
+fn main() {
+ let &ref a = &[0i32] as &[_];
+ assert_eq!(a, &[0i32] as &[_]);
+
+ let &ref a = "hello";
+ assert_eq!(a, "hello");
+
+ match "foo" {
+ "fool" => unreachable!(),
+ "foo" => {},
+ ref _x => unreachable!()
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-30240.rs b/tests/ui/pattern/usefulness/issue-30240.rs
new file mode 100644
index 000000000..a0c0d1626
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-30240.rs
@@ -0,0 +1,10 @@
+fn main() {
+ match "world" { //~ ERROR non-exhaustive patterns: `&_`
+ "hello" => {}
+ }
+
+ match "world" { //~ ERROR non-exhaustive patterns: `&_`
+ ref _x if false => {}
+ "hello" => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-30240.stderr b/tests/ui/pattern/usefulness/issue-30240.stderr
new file mode 100644
index 000000000..759fdeafe
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-30240.stderr
@@ -0,0 +1,29 @@
+error[E0004]: non-exhaustive patterns: `&_` not covered
+ --> $DIR/issue-30240.rs:2:11
+ |
+LL | match "world" {
+ | ^^^^^^^ pattern `&_` not covered
+ |
+ = note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ "hello" => {}
+LL + &_ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&_` not covered
+ --> $DIR/issue-30240.rs:6:11
+ |
+LL | match "world" {
+ | ^^^^^^^ pattern `&_` not covered
+ |
+ = note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ "hello" => {}
+LL + &_ => todo!()
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-3096-1.rs b/tests/ui/pattern/usefulness/issue-3096-1.rs
new file mode 100644
index 000000000..edc3b3223
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-3096-1.rs
@@ -0,0 +1,3 @@
+fn main() {
+ match () { } //~ ERROR non-exhaustive
+}
diff --git a/tests/ui/pattern/usefulness/issue-3096-1.stderr b/tests/ui/pattern/usefulness/issue-3096-1.stderr
new file mode 100644
index 000000000..d8884394f
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-3096-1.stderr
@@ -0,0 +1,17 @@
+error[E0004]: non-exhaustive patterns: type `()` is non-empty
+ --> $DIR/issue-3096-1.rs:2:11
+ |
+LL | match () { }
+ | ^^
+ |
+ = note: the matched value is of type `()`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match () {
+LL + _ => todo!(),
+LL ~ }
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-3096-2.rs b/tests/ui/pattern/usefulness/issue-3096-2.rs
new file mode 100644
index 000000000..a26e42580
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-3096-2.rs
@@ -0,0 +1,6 @@
+enum Bottom { }
+
+fn main() {
+ let x = &() as *const () as *const Bottom;
+ match x { } //~ ERROR non-exhaustive patterns
+}
diff --git a/tests/ui/pattern/usefulness/issue-3096-2.stderr b/tests/ui/pattern/usefulness/issue-3096-2.stderr
new file mode 100644
index 000000000..2df8911ba
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-3096-2.stderr
@@ -0,0 +1,17 @@
+error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty
+ --> $DIR/issue-3096-2.rs:5:11
+ |
+LL | match x { }
+ | ^
+ |
+ = note: the matched value is of type `*const Bottom`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-31221.rs b/tests/ui/pattern/usefulness/issue-31221.rs
new file mode 100644
index 000000000..e03f1ec5b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-31221.rs
@@ -0,0 +1,34 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(non_snake_case)]
+#![deny(unreachable_patterns)]
+
+#[derive(Clone, Copy)]
+enum Enum {
+ Var1,
+ Var2,
+}
+
+fn main() {
+ use Enum::*;
+ let s = Var1;
+ match s {
+ Var1 => (),
+ Var3 => (),
+ Var2 => (),
+ //~^ ERROR unreachable pattern
+ };
+ match &s {
+ &Var1 => (),
+ &Var3 => (),
+ &Var2 => (),
+ //~^ ERROR unreachable pattern
+ };
+ let t = (Var1, Var1);
+ match t {
+ (Var1, b) => (),
+ (c, d) => (),
+ anything => ()
+ //~^ ERROR unreachable pattern
+ };
+}
diff --git a/tests/ui/pattern/usefulness/issue-31221.stderr b/tests/ui/pattern/usefulness/issue-31221.stderr
new file mode 100644
index 000000000..7d3491444
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-31221.stderr
@@ -0,0 +1,32 @@
+error: unreachable pattern
+ --> $DIR/issue-31221.rs:18:9
+ |
+LL | Var3 => (),
+ | ---- matches any value
+LL | Var2 => (),
+ | ^^^^ unreachable pattern
+ |
+note: the lint level is defined here
+ --> $DIR/issue-31221.rs:4:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/issue-31221.rs:24:9
+ |
+LL | &Var3 => (),
+ | ----- matches any value
+LL | &Var2 => (),
+ | ^^^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/issue-31221.rs:31:9
+ |
+LL | (c, d) => (),
+ | ------ matches any value
+LL | anything => ()
+ | ^^^^^^^^ unreachable pattern
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/pattern/usefulness/issue-31561.rs b/tests/ui/pattern/usefulness/issue-31561.rs
new file mode 100644
index 000000000..82414f041
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-31561.rs
@@ -0,0 +1,11 @@
+enum Thing {
+ Foo(u8),
+ Bar,
+ Baz
+}
+
+fn main() {
+ let Thing::Foo(y) = Thing::Foo(1);
+ //~^ ERROR refutable pattern in local binding
+ //~| `Thing::Bar` and `Thing::Baz` not covered
+}
diff --git a/tests/ui/pattern/usefulness/issue-31561.stderr b/tests/ui/pattern/usefulness/issue-31561.stderr
new file mode 100644
index 000000000..5367de5e5
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-31561.stderr
@@ -0,0 +1,27 @@
+error[E0005]: refutable pattern in local binding
+ --> $DIR/issue-31561.rs:8:9
+ |
+LL | let Thing::Foo(y) = Thing::Foo(1);
+ | ^^^^^^^^^^^^^ patterns `Thing::Bar` and `Thing::Baz` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Thing` defined here
+ --> $DIR/issue-31561.rs:1:6
+ |
+LL | enum Thing {
+ | ^^^^^
+LL | Foo(u8),
+LL | Bar,
+ | --- not covered
+LL | Baz
+ | --- not covered
+ = note: the matched value is of type `Thing`
+help: you might want to use `let else` to handle the variants that aren't matched
+ |
+LL | let Thing::Foo(y) = Thing::Foo(1) else { todo!() };
+ | ++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/pattern/usefulness/issue-35609.rs b/tests/ui/pattern/usefulness/issue-35609.rs
new file mode 100644
index 000000000..8ef75e351
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-35609.rs
@@ -0,0 +1,43 @@
+enum Enum {
+ A, B, C, D, E, F
+}
+use Enum::*;
+
+struct S(Enum, ());
+struct Sd { x: Enum, y: () }
+
+fn main() {
+ match (A, ()) { //~ ERROR non-exhaustive
+ (A, _) => {}
+ }
+
+ match (A, A) { //~ ERROR non-exhaustive
+ (_, A) => {}
+ }
+
+ match ((A, ()), ()) { //~ ERROR non-exhaustive
+ ((A, ()), _) => {}
+ }
+
+ match ((A, ()), A) { //~ ERROR non-exhaustive
+ ((A, ()), _) => {}
+ }
+
+ match ((A, ()), ()) { //~ ERROR non-exhaustive
+ ((A, _), _) => {}
+ }
+
+
+ match S(A, ()) { //~ ERROR non-exhaustive
+ S(A, _) => {}
+ }
+
+ match (Sd { x: A, y: () }) { //~ ERROR non-exhaustive
+ Sd { x: A, y: _ } => {}
+ }
+
+ match Some(A) { //~ ERROR non-exhaustive
+ Some(A) => (),
+ None => ()
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-35609.stderr b/tests/ui/pattern/usefulness/issue-35609.stderr
new file mode 100644
index 000000000..12113957d
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-35609.stderr
@@ -0,0 +1,119 @@
+error[E0004]: non-exhaustive patterns: `(Enum::B, _)`, `(Enum::C, _)`, `(Enum::D, _)` and 2 more not covered
+ --> $DIR/issue-35609.rs:10:11
+ |
+LL | match (A, ()) {
+ | ^^^^^^^ patterns `(Enum::B, _)`, `(Enum::C, _)`, `(Enum::D, _)` and 2 more not covered
+ |
+ = note: the matched value is of type `(Enum, ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (A, _) => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `(_, Enum::B)`, `(_, Enum::C)`, `(_, Enum::D)` and 2 more not covered
+ --> $DIR/issue-35609.rs:14:11
+ |
+LL | match (A, A) {
+ | ^^^^^^ patterns `(_, Enum::B)`, `(_, Enum::C)`, `(_, Enum::D)` and 2 more not covered
+ |
+ = note: the matched value is of type `(Enum, Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (_, A) => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
+ --> $DIR/issue-35609.rs:18:11
+ |
+LL | match ((A, ()), ()) {
+ | ^^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
+ |
+ = note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, ()), _) => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
+ --> $DIR/issue-35609.rs:22:11
+ |
+LL | match ((A, ()), A) {
+ | ^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
+ |
+ = note: the matched value is of type `((Enum, ()), Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, ()), _) => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
+ --> $DIR/issue-35609.rs:26:11
+ |
+LL | match ((A, ()), ()) {
+ | ^^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
+ |
+ = note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, _), _) => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `S(Enum::B, _)`, `S(Enum::C, _)`, `S(Enum::D, _)` and 2 more not covered
+ --> $DIR/issue-35609.rs:31:11
+ |
+LL | match S(A, ()) {
+ | ^^^^^^^^ patterns `S(Enum::B, _)`, `S(Enum::C, _)`, `S(Enum::D, _)` and 2 more not covered
+ |
+note: `S` defined here
+ --> $DIR/issue-35609.rs:6:8
+ |
+LL | struct S(Enum, ());
+ | ^
+ = note: the matched value is of type `S`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ S(A, _) => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Sd { x: Enum::B, .. }`, `Sd { x: Enum::C, .. }`, `Sd { x: Enum::D, .. }` and 2 more not covered
+ --> $DIR/issue-35609.rs:35:11
+ |
+LL | match (Sd { x: A, y: () }) {
+ | ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: Enum::B, .. }`, `Sd { x: Enum::C, .. }`, `Sd { x: Enum::D, .. }` and 2 more not covered
+ |
+note: `Sd` defined here
+ --> $DIR/issue-35609.rs:7:8
+ |
+LL | struct Sd { x: Enum, y: () }
+ | ^^
+ = note: the matched value is of type `Sd`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ Sd { x: A, y: _ } => {}
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Some(Enum::B)`, `Some(Enum::C)`, `Some(Enum::D)` and 2 more not covered
+ --> $DIR/issue-35609.rs:39:11
+ |
+LL | match Some(A) {
+ | ^^^^^^^ patterns `Some(Enum::B)`, `Some(Enum::C)`, `Some(Enum::D)` and 2 more not covered
+ |
+note: `Option<Enum>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ = note: the matched value is of type `Option<Enum>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ None => (),
+LL + _ => todo!()
+ |
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-3601.rs b/tests/ui/pattern/usefulness/issue-3601.rs
new file mode 100644
index 000000000..6215a2398
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-3601.rs
@@ -0,0 +1,34 @@
+#![feature(box_patterns)]
+
+struct HTMLImageData {
+ image: Option<String>
+}
+
+struct ElementData {
+ kind: Box<ElementKind>
+}
+
+enum ElementKind {
+ HTMLImageElement(HTMLImageData)
+}
+
+enum NodeKind {
+ Element(ElementData)
+}
+
+struct NodeData {
+ kind: Box<NodeKind>,
+}
+
+fn main() {
+ let mut id = HTMLImageData { image: None };
+ let ed = ElementData { kind: Box::new(ElementKind::HTMLImageElement(id)) };
+ let n = NodeData { kind: Box::new(NodeKind::Element(ed)) };
+
+ // n.b. span could be better
+ match n.kind {
+ box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
+ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+ },
+ };
+}
diff --git a/tests/ui/pattern/usefulness/issue-3601.stderr b/tests/ui/pattern/usefulness/issue-3601.stderr
new file mode 100644
index 000000000..59d7bcd4b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-3601.stderr
@@ -0,0 +1,18 @@
+error[E0004]: non-exhaustive patterns: `box _` not covered
+ --> $DIR/issue-3601.rs:30:44
+ |
+LL | box NodeKind::Element(ed) => match ed.kind {
+ | ^^^^^^^ pattern `box _` not covered
+ |
+note: `Box<ElementKind>` defined here
+ --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+ = note: the matched value is of type `Box<ElementKind>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+LL + box _ => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-39362.rs b/tests/ui/pattern/usefulness/issue-39362.rs
new file mode 100644
index 000000000..ea3c8f88e
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-39362.rs
@@ -0,0 +1,18 @@
+enum Foo {
+ Bar { bar: Bar, id: usize }
+}
+
+enum Bar {
+ A, B, C, D, E, F
+}
+
+fn test(f: Foo) {
+ match f {
+ //~^ ERROR non-exhaustive patterns
+ //~| patterns
+ Foo::Bar { bar: Bar::A, .. } => (),
+ Foo::Bar { bar: Bar::B, .. } => (),
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/issue-39362.stderr b/tests/ui/pattern/usefulness/issue-39362.stderr
new file mode 100644
index 000000000..b8b17918a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-39362.stderr
@@ -0,0 +1,23 @@
+error[E0004]: non-exhaustive patterns: `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered
+ --> $DIR/issue-39362.rs:10:11
+ |
+LL | match f {
+ | ^ patterns `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered
+ |
+note: `Foo` defined here
+ --> $DIR/issue-39362.rs:2:5
+ |
+LL | enum Foo {
+ | ---
+LL | Bar { bar: Bar, id: usize }
+ | ^^^ not covered
+ = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ Foo::Bar { bar: Bar::B, .. } => (),
+LL ~ _ => todo!(),
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-40221.rs b/tests/ui/pattern/usefulness/issue-40221.rs
new file mode 100644
index 000000000..e1f7e975b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-40221.rs
@@ -0,0 +1,16 @@
+enum P {
+ C(PC),
+}
+
+enum PC {
+ Q,
+ QA,
+}
+
+fn test(proto: P) {
+ match proto { //~ ERROR non-exhaustive patterns
+ P::C(PC::Q) => (),
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/issue-40221.stderr b/tests/ui/pattern/usefulness/issue-40221.stderr
new file mode 100644
index 000000000..4973e42b0
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-40221.stderr
@@ -0,0 +1,23 @@
+error[E0004]: non-exhaustive patterns: `P::C(PC::QA)` not covered
+ --> $DIR/issue-40221.rs:11:11
+ |
+LL | match proto {
+ | ^^^^^ pattern `P::C(PC::QA)` not covered
+ |
+note: `P` defined here
+ --> $DIR/issue-40221.rs:2:5
+ |
+LL | enum P {
+ | -
+LL | C(PC),
+ | ^ not covered
+ = note: the matched value is of type `P`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ P::C(PC::Q) => (),
+LL ~ P::C(PC::QA) => todo!(),
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-4321.rs b/tests/ui/pattern/usefulness/issue-4321.rs
new file mode 100644
index 000000000..9715f2eba
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-4321.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let tup = (true, true);
+ println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered
+ (false, false) => "foo",
+ (false, true) => "bar",
+ (true, true) => "baz"
+ });
+}
diff --git a/tests/ui/pattern/usefulness/issue-4321.stderr b/tests/ui/pattern/usefulness/issue-4321.stderr
new file mode 100644
index 000000000..293273174
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-4321.stderr
@@ -0,0 +1,16 @@
+error[E0004]: non-exhaustive patterns: `(true, false)` not covered
+ --> $DIR/issue-4321.rs:3:31
+ |
+LL | println!("foo {:}", match tup {
+ | ^^^ pattern `(true, false)` not covered
+ |
+ = note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (true, true) => "baz",
+LL + (true, false) => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-50900.rs b/tests/ui/pattern/usefulness/issue-50900.rs
new file mode 100644
index 000000000..9cc760e9a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-50900.rs
@@ -0,0 +1,19 @@
+#[derive(PartialEq, Eq)]
+pub struct Tag(pub Context, pub u16);
+
+#[derive(PartialEq, Eq)]
+pub enum Context {
+ Tiff,
+ Exif,
+}
+
+impl Tag {
+ const ExifIFDPointer: Tag = Tag(Context::Tiff, 34665);
+}
+
+fn main() {
+ match Tag::ExifIFDPointer {
+ //~^ ERROR: non-exhaustive patterns: `Tag(Context::Exif, _)` not covered
+ Tag::ExifIFDPointer => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-50900.stderr b/tests/ui/pattern/usefulness/issue-50900.stderr
new file mode 100644
index 000000000..348246d28
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-50900.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `Tag(Context::Exif, _)` not covered
+ --> $DIR/issue-50900.rs:15:11
+ |
+LL | match Tag::ExifIFDPointer {
+ | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Context::Exif, _)` not covered
+ |
+note: `Tag` defined here
+ --> $DIR/issue-50900.rs:2:12
+ |
+LL | pub struct Tag(pub Context, pub u16);
+ | ^^^
+ = note: the matched value is of type `Tag`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Tag::ExifIFDPointer => {}
+LL + Tag(Context::Exif, _) => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs b/tests/ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs
new file mode 100644
index 000000000..5b0482de2
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+// This used to cause a stack overflow during exhaustiveness checking in the compiler.
+
+fn main() {
+ const LARGE_SIZE: usize = 1024 * 1024;
+ let [..] = [0u8; LARGE_SIZE];
+ match [0u8; LARGE_SIZE] {
+ [..] => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-56379.rs b/tests/ui/pattern/usefulness/issue-56379.rs
new file mode 100644
index 000000000..097cf98d0
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-56379.rs
@@ -0,0 +1,14 @@
+enum Foo {
+ A(bool),
+ B(bool),
+ C(bool),
+}
+
+fn main() {
+ match Foo::A(true) {
+ //~^ ERROR non-exhaustive patterns: `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered
+ Foo::A(true) => {}
+ Foo::B(true) => {}
+ Foo::C(true) => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-56379.stderr b/tests/ui/pattern/usefulness/issue-56379.stderr
new file mode 100644
index 000000000..6eed6bfae
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-56379.stderr
@@ -0,0 +1,27 @@
+error[E0004]: non-exhaustive patterns: `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered
+ --> $DIR/issue-56379.rs:8:11
+ |
+LL | match Foo::A(true) {
+ | ^^^^^^^^^^^^ patterns `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/issue-56379.rs:2:5
+ |
+LL | enum Foo {
+ | ---
+LL | A(bool),
+ | ^ not covered
+LL | B(bool),
+ | ^ not covered
+LL | C(bool),
+ | ^ not covered
+ = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Foo::C(true) => {}
+LL + Foo::A(false) | Foo::B(false) | Foo::C(false) => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-57472.rs b/tests/ui/pattern/usefulness/issue-57472.rs
new file mode 100644
index 000000000..113100637
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-57472.rs
@@ -0,0 +1,35 @@
+#![crate_type="lib"]
+#![deny(unreachable_patterns)]
+
+mod test_struct {
+ // Test the exact copy of the minimal example
+ // posted in the issue.
+ pub struct Punned {
+ foo: [u8; 1],
+ bar: [u8; 1],
+ }
+
+ pub fn test(punned: Punned) {
+ match punned {
+ Punned { foo: [_], .. } => println!("foo"),
+ Punned { bar: [_], .. } => println!("bar"),
+ //~^ ERROR unreachable pattern [unreachable_patterns]
+ }
+ }
+}
+
+mod test_union {
+ // Test the same thing using a union.
+ pub union Punned {
+ foo: [u8; 1],
+ bar: [u8; 1],
+ }
+
+ pub fn test(punned: Punned) {
+ match punned {
+ Punned { foo: [_] } => println!("foo"),
+ Punned { bar: [_] } => println!("bar"),
+ //~^ ERROR unreachable pattern [unreachable_patterns]
+ }
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-57472.stderr b/tests/ui/pattern/usefulness/issue-57472.stderr
new file mode 100644
index 000000000..26efdf6db
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-57472.stderr
@@ -0,0 +1,20 @@
+error: unreachable pattern
+ --> $DIR/issue-57472.rs:15:13
+ |
+LL | Punned { bar: [_], .. } => println!("bar"),
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-57472.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/issue-57472.rs:31:13
+ |
+LL | Punned { bar: [_] } => println!("bar"),
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs b/tests/ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs
new file mode 100644
index 000000000..54dfa889e
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+#![deny(unreachable_patterns)]
+
+const C0: &'static [u8] = b"\x00";
+
+fn main() {
+ let x: &[u8] = &[0];
+ match x {
+ &[] => {}
+ &[1..=255] => {}
+ C0 => {}
+ &[_, _, ..] => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-66501.rs b/tests/ui/pattern/usefulness/issue-66501.rs
new file mode 100644
index 000000000..ffcfd4ad8
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-66501.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![allow(unreachable_patterns)]
+
+fn main() {
+ const CONST: &[Option<()>; 1] = &[Some(())];
+ match &[Some(())] {
+ &[None] => {}
+ CONST => {}
+ &[Some(())] => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs b/tests/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs
new file mode 100644
index 000000000..e2ff9ac87
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+// In PR 71930, it was discovered that the code to retrieve the inferred type of a match scrutinee
+// was incorrect.
+
+fn f() -> ! {
+ panic!()
+}
+
+fn g() -> usize {
+ match f() { // Should infer type `bool`
+ false => 0,
+ true => 1,
+ }
+}
+
+fn h() -> usize {
+ match f() { // Should infer type `!`
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/issue-72377.rs b/tests/ui/pattern/usefulness/issue-72377.rs
new file mode 100644
index 000000000..b5ad3075c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-72377.rs
@@ -0,0 +1,17 @@
+#[derive(PartialEq, Eq)]
+enum X { A, B, C, }
+
+fn main() {
+ let x = X::A;
+ let y = Some(X::A);
+
+ match (x, y) {
+ //~^ ERROR non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2
+ //~| more not covered
+ (_, None) => false,
+ (v, Some(w)) if v == w => true,
+ (X::B, Some(X::C)) => false,
+ (X::B, Some(X::A)) => false,
+ (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
+ };
+}
diff --git a/tests/ui/pattern/usefulness/issue-72377.stderr b/tests/ui/pattern/usefulness/issue-72377.stderr
new file mode 100644
index 000000000..123dd051d
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-72377.stderr
@@ -0,0 +1,16 @@
+error[E0004]: non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered
+ --> $DIR/issue-72377.rs:8:11
+ |
+LL | match (x, y) {
+ | ^^^^^^ patterns `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered
+ |
+ = note: the matched value is of type `(X, Option<X>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
+LL ~ _ => todo!(),
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs b/tests/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs
new file mode 100644
index 000000000..058f41967
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs
@@ -0,0 +1,56 @@
+// check-pass
+
+// From https://github.com/rust-lang/rust/issues/72476
+// and https://github.com/rust-lang/rust/issues/89393
+
+trait Trait {
+ type Projection;
+}
+
+struct A;
+impl Trait for A {
+ type Projection = bool;
+}
+
+struct B;
+impl Trait for B {
+ type Projection = (u32, u32);
+}
+
+struct Next<T: Trait>(T::Projection);
+
+fn foo1(item: Next<A>) {
+ match item {
+ Next(true) => {}
+ Next(false) => {}
+ }
+}
+
+fn foo2(x: <A as Trait>::Projection) {
+ match x {
+ true => {}
+ false => {}
+ }
+}
+
+fn foo3(x: Next<B>) {
+ let Next((_, _)) = x;
+ match x {
+ Next((_, _)) => {}
+ }
+}
+
+fn foo4(x: <B as Trait>::Projection) {
+ let (_, _) = x;
+ match x {
+ (_, _) => {}
+ }
+}
+
+fn foo5<T: Trait>(x: <T as Trait>::Projection) {
+ match x {
+ _ => {}
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs
new file mode 100644
index 000000000..cbfcf0eaf
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs
@@ -0,0 +1,12 @@
+enum A {}
+ //~^ NOTE `A` defined here
+ //~| NOTE
+
+fn f(a: &A) {
+ match a {}
+ //~^ ERROR non-exhaustive patterns: type `&A` is non-empty
+ //~| NOTE the matched value is of type `&A`
+ //~| NOTE references are always considered inhabited
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr
new file mode 100644
index 000000000..bf05d616d
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr
@@ -0,0 +1,23 @@
+error[E0004]: non-exhaustive patterns: type `&A` is non-empty
+ --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11
+ |
+LL | match a {}
+ | ^
+ |
+note: `A` defined here
+ --> $DIR/issue-78123-non-exhaustive-reference.rs:1:6
+ |
+LL | enum A {}
+ | ^
+ = note: the matched value is of type `&A`
+ = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match a {
+LL + _ => todo!(),
+LL + }
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs b/tests/ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs
new file mode 100644
index 000000000..2879caf2c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs
@@ -0,0 +1,25 @@
+// check-pass
+// From https://github.com/rust-lang/rust/issues/78549
+
+fn main() {
+ match "foo" {
+ "foo" => {},
+ &_ => {},
+ }
+
+ match "foo" {
+ &_ => {},
+ "foo" => {},
+ }
+
+ match ("foo", 0, "bar") {
+ (&_, 0, &_) => {},
+ ("foo", _, "bar") => {},
+ (&_, _, &_) => {},
+ }
+
+ match (&"foo", "bar") {
+ (&"foo", &_) => {},
+ (&&_, &_) => {},
+ }
+}
diff --git a/tests/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs b/tests/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs
new file mode 100644
index 000000000..aac7d7d53
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs
@@ -0,0 +1,27 @@
+// check-pass
+#![deny(unreachable_patterns)]
+pub enum TypeCtor {
+ Slice,
+ Array,
+}
+
+pub struct ApplicationTy(TypeCtor);
+
+macro_rules! ty_app {
+ ($ctor:pat) => {
+ ApplicationTy($ctor)
+ };
+}
+
+fn _foo(ty: ApplicationTy) {
+ match ty {
+ ty_app!(TypeCtor::Array) | ty_app!(TypeCtor::Slice) => {}
+ }
+
+ // same as above, with the macro expanded
+ match ty {
+ ApplicationTy(TypeCtor::Array) | ApplicationTy(TypeCtor::Slice) => {}
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs
new file mode 100644
index 000000000..c1bfcc734
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs
@@ -0,0 +1,6 @@
+// This used to ICE in exhaustiveness checking. Explanation here:
+// https://github.com/rust-lang/rust/issues/82772#issuecomment-905946768
+fn main() {
+ let Box { 1: _, .. }: Box<()>; //~ ERROR field `1` of
+ let Box { .. }: Box<()>;
+}
diff --git a/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr
new file mode 100644
index 000000000..2c8c85bb1
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr
@@ -0,0 +1,9 @@
+error[E0451]: field `1` of struct `Box` is private
+ --> $DIR/issue-82772-match-box-as-struct.rs:4:15
+ |
+LL | let Box { 1: _, .. }: Box<()>;
+ | ^^^^ private field
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0451`.
diff --git a/tests/ui/pattern/usefulness/issue-88747.rs b/tests/ui/pattern/usefulness/issue-88747.rs
new file mode 100644
index 000000000..948c99f9c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-88747.rs
@@ -0,0 +1,14 @@
+// check-pass: this used to be a stack overflow because of recursion in `usefulness.rs`
+
+macro_rules! long_tuple_arg {
+ ([$($t:tt)*]#$($h:tt)*) => {
+ long_tuple_arg!{[$($t)*$($t)*]$($h)*}
+ };
+ ([$([$t:tt $y:tt])*]) => {
+ pub fn _f(($($t,)*): ($($y,)*)) {}
+ }
+}
+
+long_tuple_arg!{[[_ u8]]########## ###}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/match-arm-statics-2.rs b/tests/ui/pattern/usefulness/match-arm-statics-2.rs
new file mode 100644
index 000000000..3c9c16561
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-arm-statics-2.rs
@@ -0,0 +1,62 @@
+use self::Direction::{North, East, South, West};
+
+#[derive(PartialEq, Eq)]
+struct NewBool(bool);
+
+#[derive(PartialEq, Eq)]
+enum Direction {
+ North,
+ East,
+ South,
+ West
+}
+
+const TRUE_TRUE: (bool, bool) = (true, true);
+
+fn nonexhaustive_1() {
+ match (true, false) {
+ //~^ ERROR non-exhaustive patterns: `(true, false)` not covered
+ TRUE_TRUE => (),
+ (false, false) => (),
+ (false, true) => ()
+ }
+}
+
+const NONE: Option<Direction> = None;
+const EAST: Direction = East;
+
+fn nonexhaustive_2() {
+ match Some(Some(North)) {
+ //~^ ERROR non-exhaustive patterns: `Some(Some(Direction::West))` not covered
+ Some(NONE) => (),
+ Some(Some(North)) => (),
+ Some(Some(EAST)) => (),
+ Some(Some(South)) => (),
+ None => ()
+ }
+}
+
+const NEW_FALSE: NewBool = NewBool(false);
+struct Foo {
+ bar: Option<Direction>,
+ baz: NewBool
+}
+
+const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
+
+fn nonexhaustive_3() {
+ match (Foo { bar: Some(North), baz: NewBool(true) }) {
+ //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(Direction::North), baz: NewBool(true) }`
+ Foo { bar: None, baz: NewBool(true) } => (),
+ Foo { bar: _, baz: NEW_FALSE } => (),
+ Foo { bar: Some(West), baz: NewBool(true) } => (),
+ Foo { bar: Some(South), .. } => (),
+ Foo { bar: Some(EAST), .. } => ()
+ }
+}
+
+fn main() {
+ nonexhaustive_1();
+ nonexhaustive_2();
+ nonexhaustive_3();
+}
diff --git a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
new file mode 100644
index 000000000..e4dd35a59
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
@@ -0,0 +1,54 @@
+error[E0004]: non-exhaustive patterns: `(true, false)` not covered
+ --> $DIR/match-arm-statics-2.rs:17:11
+ |
+LL | match (true, false) {
+ | ^^^^^^^^^^^^^ pattern `(true, false)` not covered
+ |
+ = note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (false, true) => (),
+LL + (true, false) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Some(Some(Direction::West))` not covered
+ --> $DIR/match-arm-statics-2.rs:29:11
+ |
+LL | match Some(Some(North)) {
+ | ^^^^^^^^^^^^^^^^^ pattern `Some(Some(Direction::West))` not covered
+ |
+note: `Option<Option<Direction>>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: not covered
+ |
+ = note: not covered
+ = note: the matched value is of type `Option<Option<Direction>>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ None => (),
+LL + Some(Some(Direction::West)) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Foo { bar: Some(Direction::North), baz: NewBool(true) }` not covered
+ --> $DIR/match-arm-statics-2.rs:48:11
+ |
+LL | match (Foo { bar: Some(North), baz: NewBool(true) }) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(Direction::North), baz: NewBool(true) }` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/match-arm-statics-2.rs:40:8
+ |
+LL | struct Foo {
+ | ^^^
+ = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo { bar: Some(EAST), .. } => (),
+LL + Foo { bar: Some(Direction::North), baz: NewBool(true) } => todo!()
+ |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/match-arm-statics.rs b/tests/ui/pattern/usefulness/match-arm-statics.rs
new file mode 100644
index 000000000..91db76ebb
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-arm-statics.rs
@@ -0,0 +1,69 @@
+#![allow(dead_code)]
+#![deny(unreachable_patterns)]
+
+use self::Direction::{North, East, South, West};
+
+#[derive(PartialEq, Eq)]
+struct NewBool(bool);
+
+#[derive(PartialEq, Eq)]
+enum Direction {
+ North,
+ East,
+ South,
+ West
+}
+
+const TRUE_TRUE: (bool, bool) = (true, true);
+
+fn unreachable_1() {
+ match (true, false) {
+ TRUE_TRUE => (),
+ (false, false) => (),
+ (false, true) => (),
+ (true, false) => (),
+ (true, true) => ()
+ //~^ ERROR unreachable pattern
+ }
+}
+
+const NONE: Option<Direction> = None;
+const EAST: Direction = East;
+
+fn unreachable_2() {
+ match Some(Some(North)) {
+ Some(NONE) => (),
+ Some(Some(North)) => (),
+ Some(Some(EAST)) => (),
+ Some(Some(South)) => (),
+ Some(Some(West)) => (),
+ Some(Some(East)) => (),
+ //~^ ERROR unreachable pattern
+ None => ()
+ }
+}
+
+const NEW_FALSE: NewBool = NewBool(false);
+struct Foo {
+ bar: Option<Direction>,
+ baz: NewBool
+}
+
+fn unreachable_3() {
+ match (Foo { bar: Some(EAST), baz: NewBool(true) }) {
+ Foo { bar: None, baz: NewBool(true) } => (),
+ Foo { bar: _, baz: NEW_FALSE } => (),
+ Foo { bar: Some(West), baz: NewBool(true) } => (),
+ Foo { bar: Some(South), .. } => (),
+ Foo { bar: Some(EAST), .. } => (),
+ Foo { bar: Some(North), baz: NewBool(true) } => (),
+ Foo { bar: Some(EAST), baz: NewBool(false) } => ()
+ //~^ ERROR unreachable pattern
+ }
+}
+
+fn main() {
+ unreachable_1();
+ unreachable_2();
+ unreachable_3();
+}
diff --git a/tests/ui/pattern/usefulness/match-arm-statics.stderr b/tests/ui/pattern/usefulness/match-arm-statics.stderr
new file mode 100644
index 000000000..a5dffebf6
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-arm-statics.stderr
@@ -0,0 +1,26 @@
+error: unreachable pattern
+ --> $DIR/match-arm-statics.rs:25:9
+ |
+LL | (true, true) => ()
+ | ^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/match-arm-statics.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-arm-statics.rs:40:9
+ |
+LL | Some(Some(East)) => (),
+ | ^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-arm-statics.rs:60:9
+ |
+LL | Foo { bar: Some(EAST), baz: NewBool(false) } => ()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/pattern/usefulness/match-byte-array-patterns-2.rs b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.rs
new file mode 100644
index 000000000..33468d03f
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.rs
@@ -0,0 +1,13 @@
+fn main() {
+ let buf = &[0, 1, 2, 3];
+
+ match buf { //~ ERROR non-exhaustive
+ b"AAAA" => {}
+ }
+
+ let buf: &[u8] = buf;
+
+ match buf { //~ ERROR non-exhaustive
+ b"AAAA" => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
new file mode 100644
index 000000000..a90f32f7a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
@@ -0,0 +1,29 @@
+error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
+ --> $DIR/match-byte-array-patterns-2.rs:4:11
+ |
+LL | match buf {
+ | ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
+ |
+ = note: the matched value is of type `&[u8; 4]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ b"AAAA" => {}
+LL + &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
+ --> $DIR/match-byte-array-patterns-2.rs:10:11
+ |
+LL | match buf {
+ | ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
+ |
+ = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ b"AAAA" => {}
+LL + _ => todo!()
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/match-byte-array-patterns.rs b/tests/ui/pattern/usefulness/match-byte-array-patterns.rs
new file mode 100644
index 000000000..9b6c8bd55
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-byte-array-patterns.rs
@@ -0,0 +1,55 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let buf = &[0, 1, 2, 3];
+
+ match buf {
+ b"AAAA" => {},
+ &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+
+ match buf {
+ &[0x41, 0x41, 0x41, 0x41] => {}
+ b"AAAA" => {}, //~ ERROR unreachable pattern
+ _ => {}
+ }
+
+ match buf {
+ &[_, 0x41, 0x41, 0x41] => {},
+ b"AAAA" => {}, //~ ERROR unreachable pattern
+ _ => {}
+ }
+
+ match buf {
+ &[0x41, .., 0x41] => {}
+ b"AAAA" => {}, //~ ERROR unreachable pattern
+ _ => {}
+ }
+
+ let buf: &[u8] = buf;
+
+ match buf {
+ b"AAAA" => {},
+ &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+
+ match buf {
+ &[0x41, 0x41, 0x41, 0x41] => {}
+ b"AAAA" => {}, //~ ERROR unreachable pattern
+ _ => {}
+ }
+
+ match buf {
+ &[_, 0x41, 0x41, 0x41] => {},
+ b"AAAA" => {}, //~ ERROR unreachable pattern
+ _ => {}
+ }
+
+ match buf {
+ &[0x41, .., 0x41] => {}
+ b"AAAA" => {}, //~ ERROR unreachable pattern
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/match-byte-array-patterns.stderr b/tests/ui/pattern/usefulness/match-byte-array-patterns.stderr
new file mode 100644
index 000000000..0c582be8d
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-byte-array-patterns.stderr
@@ -0,0 +1,56 @@
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:8:9
+ |
+LL | &[0x41, 0x41, 0x41, 0x41] => {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/match-byte-array-patterns.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:14:9
+ |
+LL | b"AAAA" => {},
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:20:9
+ |
+LL | b"AAAA" => {},
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:26:9
+ |
+LL | b"AAAA" => {},
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:34:9
+ |
+LL | &[0x41, 0x41, 0x41, 0x41] => {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:40:9
+ |
+LL | b"AAAA" => {},
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:46:9
+ |
+LL | b"AAAA" => {},
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-byte-array-patterns.rs:52:9
+ |
+LL | b"AAAA" => {},
+ | ^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.rs b/tests/ui/pattern/usefulness/match-non-exhaustive.rs
new file mode 100644
index 000000000..3b210a115
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-non-exhaustive.rs
@@ -0,0 +1,4 @@
+fn main() {
+ match 0 { 1 => () } //~ ERROR non-exhaustive patterns
+ match 0 { 0 if false => () } //~ ERROR non-exhaustive patterns
+}
diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
new file mode 100644
index 000000000..08dde523a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
@@ -0,0 +1,27 @@
+error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
+ --> $DIR/match-non-exhaustive.rs:2:11
+ |
+LL | match 0 { 1 => () }
+ | ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
+ |
+ = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL | match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() }
+ | ++++++++++++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/match-non-exhaustive.rs:3:11
+ |
+LL | match 0 { 0 if false => () }
+ | ^ pattern `_` not covered
+ |
+ = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match 0 { 0 if false => (), _ => todo!() }
+ | ++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.rs b/tests/ui/pattern/usefulness/match-privately-empty.rs
new file mode 100644
index 000000000..315eb03d1
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-privately-empty.rs
@@ -0,0 +1,21 @@
+#![feature(never_type)]
+#![feature(exhaustive_patterns)]
+
+mod private {
+ pub struct Private {
+ _bot: !,
+ pub misc: bool,
+ }
+ pub const DATA: Option<Private> = None;
+}
+
+fn main() {
+ match private::DATA {
+ //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
+ None => {}
+ Some(private::Private {
+ misc: false,
+ ..
+ }) => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.stderr b/tests/ui/pattern/usefulness/match-privately-empty.stderr
new file mode 100644
index 000000000..86f75d15c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-privately-empty.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
+ --> $DIR/match-privately-empty.rs:13:11
+ |
+LL | match private::DATA {
+ | ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
+ |
+note: `Option<Private>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: not covered
+ = note: the matched value is of type `Option<Private>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ }) => {}
+LL + Some(Private { misc: true, .. }) => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/match-ref-ice.rs b/tests/ui/pattern/usefulness/match-ref-ice.rs
new file mode 100644
index 000000000..dee110f96
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-ref-ice.rs
@@ -0,0 +1,16 @@
+#![deny(unreachable_patterns)]
+
+// The arity of `ref x` is always 1. If the pattern is compared to some non-structural type whose
+// arity is always 0, an ICE occurs.
+//
+// Related issue: #23009
+
+fn main() {
+ let homura = [1, 2, 3];
+
+ match homura {
+ [1, ref _madoka, 3] => (),
+ [1, 2, 3] => (), //~ ERROR unreachable pattern
+ [_, _, _] => (),
+ }
+}
diff --git a/tests/ui/pattern/usefulness/match-ref-ice.stderr b/tests/ui/pattern/usefulness/match-ref-ice.stderr
new file mode 100644
index 000000000..fad0940ba
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-ref-ice.stderr
@@ -0,0 +1,14 @@
+error: unreachable pattern
+ --> $DIR/match-ref-ice.rs:13:9
+ |
+LL | [1, 2, 3] => (),
+ | ^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/match-ref-ice.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/usefulness/match-slice-patterns.rs b/tests/ui/pattern/usefulness/match-slice-patterns.rs
new file mode 100644
index 000000000..92d74b8c2
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-slice-patterns.rs
@@ -0,0 +1,12 @@
+fn check(list: &[Option<()>]) {
+ match list {
+ //~^ ERROR `&[_, Some(_), .., None, _]` not covered
+ &[] => {},
+ &[_] => {},
+ &[_, _] => {},
+ &[_, None, ..] => {},
+ &[.., Some(_), _] => {},
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/match-slice-patterns.stderr b/tests/ui/pattern/usefulness/match-slice-patterns.stderr
new file mode 100644
index 000000000..961dd5901
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-slice-patterns.stderr
@@ -0,0 +1,16 @@
+error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered
+ --> $DIR/match-slice-patterns.rs:2:11
+ |
+LL | match list {
+ | ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
+ |
+ = note: the matched value is of type `&[Option<()>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[.., Some(_), _] => {}
+LL ~ &[_, Some(_), .., None, _] => todo!(),
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/match-vec-fixed.rs b/tests/ui/pattern/usefulness/match-vec-fixed.rs
new file mode 100644
index 000000000..e611779de
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-vec-fixed.rs
@@ -0,0 +1,18 @@
+#![deny(unreachable_patterns)]
+
+fn a() {
+ let v = [1, 2, 3];
+ match v {
+ [_, _, _] => {}
+ [_, _, _] => {} //~ ERROR unreachable pattern
+ }
+ match v {
+ [_, 1, _] => {}
+ [_, 1, _] => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+}
+
+fn main() {
+ a();
+}
diff --git a/tests/ui/pattern/usefulness/match-vec-fixed.stderr b/tests/ui/pattern/usefulness/match-vec-fixed.stderr
new file mode 100644
index 000000000..e388a06cb
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-vec-fixed.stderr
@@ -0,0 +1,20 @@
+error: unreachable pattern
+ --> $DIR/match-vec-fixed.rs:7:9
+ |
+LL | [_, _, _] => {}
+ | ^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/match-vec-fixed.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-vec-fixed.rs:11:9
+ |
+LL | [_, 1, _] => {}
+ | ^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/pattern/usefulness/match-vec-unreachable.rs b/tests/ui/pattern/usefulness/match-vec-unreachable.rs
new file mode 100644
index 000000000..3342389be
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-vec-unreachable.rs
@@ -0,0 +1,29 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let x: Vec<(isize, isize)> = Vec::new();
+ let x: &[(isize, isize)] = &x;
+ match *x {
+ [a, (2, 3), _] => (),
+ [(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern
+ _ => ()
+ }
+
+ let x: Vec<String> = vec!["foo".to_string(),
+ "bar".to_string(),
+ "baz".to_string()];
+ let x: &[String] = &x;
+ match *x {
+ [ref a, _, _, ..] => { println!("{}", a); }
+ [_, _, _, _, _] => { } //~ ERROR unreachable pattern
+ _ => { }
+ }
+
+ let x: Vec<char> = vec!['a', 'b', 'c'];
+ let x: &[char] = &x;
+ match *x {
+ ['a', 'b', 'c', ref _tail @ ..] => {}
+ ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/match-vec-unreachable.stderr b/tests/ui/pattern/usefulness/match-vec-unreachable.stderr
new file mode 100644
index 000000000..672fd92fb
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-vec-unreachable.stderr
@@ -0,0 +1,26 @@
+error: unreachable pattern
+ --> $DIR/match-vec-unreachable.rs:8:9
+ |
+LL | [(1, 2), (2, 3), b] => (),
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/match-vec-unreachable.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-vec-unreachable.rs:18:9
+ |
+LL | [_, _, _, _, _] => { }
+ | ^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-vec-unreachable.rs:26:9
+ |
+LL | ['a', 'b', 'c'] => {}
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/pattern/usefulness/nested-exhaustive-match.rs b/tests/ui/pattern/usefulness/nested-exhaustive-match.rs
new file mode 100644
index 000000000..8b2294f84
--- /dev/null
+++ b/tests/ui/pattern/usefulness/nested-exhaustive-match.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+struct Foo { foo: bool, bar: Option<isize>, baz: isize }
+
+pub fn main() {
+ match (Foo{foo: true, bar: Some(10), baz: 20}) {
+ Foo{foo: true, bar: Some(_), ..} => {}
+ Foo{foo: false, bar: None, ..} => {}
+ Foo{foo: true, bar: None, ..} => {}
+ Foo{foo: false, bar: Some(_), ..} => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs
new file mode 100644
index 000000000..5145f7690
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs
@@ -0,0 +1,107 @@
+// Test the "defined here" and "not covered" diagnostic hints.
+// We also make sure that references are peeled off from the scrutinee type
+// so that the diagnostics work better with default binding modes.
+
+#[derive(Clone)]
+enum E {
+ //~^ NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
+ A,
+ B,
+ //~^ NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ C
+ //~^ not covered
+ //~| not covered
+ //~| not covered
+ //~| not covered
+ //~| not covered
+ //~| not covered
+}
+
+fn by_val(e: E) {
+ let e1 = e.clone();
+ match e1 { //~ ERROR non-exhaustive patterns: `E::B` and `E::C` not covered
+ //~^ NOTE patterns `E::B` and `E::C` not covered
+ //~| NOTE the matched value is of type `E`
+ E::A => {}
+ }
+
+ let E::A = e;
+ //~^ ERROR refutable pattern in local binding
+ //~| patterns `E::B` and `E::C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `E`
+}
+
+fn by_ref_once(e: &E) {
+ match e {
+ //~^ ERROR non-exhaustive patterns
+ //~| patterns `&E::B` and `&E::C` not covered
+ //~| NOTE the matched value is of type `&E`
+ E::A => {}
+ }
+
+ let E::A = e;
+ //~^ ERROR refutable pattern in local binding
+ //~| patterns `&E::B` and `&E::C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `&E`
+}
+
+fn by_ref_thrice(e: & &mut &E) {
+ match e {
+ //~^ ERROR non-exhaustive patterns
+ //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered
+ //~| NOTE the matched value is of type `&&mut &E`
+ E::A => {}
+ }
+
+ let E::A = e;
+ //~^ ERROR refutable pattern in local binding
+ //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `&&mut &E`
+}
+
+enum Opt {
+ //~^ NOTE
+ //~| NOTE
+ Some(u8),
+ None,
+ //~^ NOTE `Opt` defined here
+ //~| NOTE not covered
+ //~| NOTE not covered
+}
+
+fn ref_pat(e: Opt) {
+ match e {
+ //~^ ERROR non-exhaustive patterns
+ //~| pattern `Opt::None` not covered
+ //~| NOTE the matched value is of type `Opt`
+ Opt::Some(ref _x) => {}
+ }
+
+ let Opt::Some(ref _x) = e;
+ //~^ ERROR refutable pattern in local binding
+ //~| NOTE the matched value is of type `Opt`
+ //~| NOTE pattern `Opt::None` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
new file mode 100644
index 000000000..769d4070f
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
@@ -0,0 +1,194 @@
+error[E0004]: non-exhaustive patterns: `E::B` and `E::C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:35:11
+ |
+LL | match e1 {
+ | ^^ patterns `E::B` and `E::C` not covered
+ |
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
+ = note: the matched value is of type `E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + E::B | E::C => todo!()
+ |
+
+error[E0005]: refutable pattern in local binding
+ --> $DIR/non-exhaustive-defined-here.rs:41:9
+ |
+LL | let E::A = e;
+ | ^^^^ patterns `E::B` and `E::C` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:6:6
+ |
+LL | enum E {
+ | ^
+...
+LL | B,
+ | - not covered
+...
+LL | C
+ | - not covered
+ = note: the matched value is of type `E`
+help: you might want to use `if let` to ignore the variants that aren't matched
+ |
+LL | if let E::A = e { todo!() }
+ | ++ ~~~~~~~~~~~
+
+error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:50:11
+ |
+LL | match e {
+ | ^ patterns `&E::B` and `&E::C` not covered
+ |
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
+ = note: the matched value is of type `&E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + &E::B | &E::C => todo!()
+ |
+
+error[E0005]: refutable pattern in local binding
+ --> $DIR/non-exhaustive-defined-here.rs:57:9
+ |
+LL | let E::A = e;
+ | ^^^^ patterns `&E::B` and `&E::C` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:6:6
+ |
+LL | enum E {
+ | ^
+...
+LL | B,
+ | - not covered
+...
+LL | C
+ | - not covered
+ = note: the matched value is of type `&E`
+help: you might want to use `if let` to ignore the variants that aren't matched
+ |
+LL | if let E::A = e { todo!() }
+ | ++ ~~~~~~~~~~~
+
+error[E0004]: non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:66:11
+ |
+LL | match e {
+ | ^ patterns `&&mut &E::B` and `&&mut &E::C` not covered
+ |
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
+ = note: the matched value is of type `&&mut &E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + &&mut &E::B | &&mut &E::C => todo!()
+ |
+
+error[E0005]: refutable pattern in local binding
+ --> $DIR/non-exhaustive-defined-here.rs:73:9
+ |
+LL | let E::A = e;
+ | ^^^^ patterns `&&mut &E::B` and `&&mut &E::C` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:6:6
+ |
+LL | enum E {
+ | ^
+...
+LL | B,
+ | - not covered
+...
+LL | C
+ | - not covered
+ = note: the matched value is of type `&&mut &E`
+help: you might want to use `if let` to ignore the variants that aren't matched
+ |
+LL | if let E::A = e { todo!() }
+ | ++ ~~~~~~~~~~~
+
+error[E0004]: non-exhaustive patterns: `Opt::None` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:92:11
+ |
+LL | match e {
+ | ^ pattern `Opt::None` not covered
+ |
+note: `Opt` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:85:5
+ |
+LL | enum Opt {
+ | ---
+...
+LL | None,
+ | ^^^^ not covered
+ = note: the matched value is of type `Opt`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Opt::Some(ref _x) => {}
+LL + Opt::None => todo!()
+ |
+
+error[E0005]: refutable pattern in local binding
+ --> $DIR/non-exhaustive-defined-here.rs:99:9
+ |
+LL | let Opt::Some(ref _x) = e;
+ | ^^^^^^^^^^^^^^^^^ pattern `Opt::None` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Opt` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:81:6
+ |
+LL | enum Opt {
+ | ^^^
+...
+LL | None,
+ | ---- not covered
+ = note: the matched value is of type `Opt`
+help: you might want to use `let else` to handle the variant that isn't matched
+ |
+LL | let Opt::Some(ref _x) = e else { todo!() };
+ | ++++++++++++++++
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0004, E0005.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.rs b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.rs
new file mode 100644
index 000000000..69c3c7658
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.rs
@@ -0,0 +1,19 @@
+enum T { A(U), B }
+enum U { C, D }
+
+fn match_nested_vecs<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
+ match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some(&[]), Err(_))` not covered
+ (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
+ (Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any",
+ (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)",
+ (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)"
+ }
+}
+
+fn main() {
+ let x = T::A(U::C);
+ match x { //~ ERROR non-exhaustive patterns: `T::A(U::C)` not covered
+ T::A(U::D) => { panic!("hello"); }
+ T::B => { panic!("goodbye"); }
+ }
+}
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
new file mode 100644
index 000000000..44f327421
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
@@ -0,0 +1,34 @@
+error[E0004]: non-exhaustive patterns: `(Some(&[]), Err(_))` not covered
+ --> $DIR/non-exhaustive-match-nested.rs:5:11
+ |
+LL | match (l1, l2) {
+ | ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered
+ |
+ = note: the matched value is of type `(Option<&[T]>, Result<&[T], ()>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
+LL + (Some(&[]), Err(_)) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `T::A(U::C)` not covered
+ --> $DIR/non-exhaustive-match-nested.rs:15:11
+ |
+LL | match x {
+ | ^ pattern `T::A(U::C)` not covered
+ |
+note: `T` defined here
+ --> $DIR/non-exhaustive-match-nested.rs:1:10
+ |
+LL | enum T { A(U), B }
+ | - ^ not covered
+ = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ T::B => { panic!("goodbye"); }
+LL + T::A(U::C) => todo!()
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.rs b/tests/ui/pattern/usefulness/non-exhaustive-match.rs
new file mode 100644
index 000000000..1cb58b8ce
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match.rs
@@ -0,0 +1,63 @@
+#![allow(illegal_floating_point_literal_pattern)]
+
+enum T { A, B }
+
+fn main() {
+ let x = T::A;
+ match x { T::B => { } } //~ ERROR non-exhaustive patterns: `T::A` not covered
+ match true { //~ ERROR non-exhaustive patterns: `false` not covered
+ true => {}
+ }
+ match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
+ None => {}
+ }
+ match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)`
+ // and `(_, _, 5_i32..=i32::MAX)` not covered
+ (_, _, 4) => {}
+ }
+ match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered
+ (T::A, T::B) => {}
+ (T::B, T::A) => {}
+ }
+ match T::A { //~ ERROR non-exhaustive patterns: `T::B` not covered
+ T::A => {}
+ }
+ // This is exhaustive, though the algorithm got it wrong at one point
+ match (T::A, T::B) {
+ (T::A, _) => {}
+ (_, T::A) => {}
+ (T::B, T::B) => {}
+ }
+ let vec = vec![Some(42), None, Some(21)];
+ let vec: &[Option<isize>] = &vec;
+ match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered
+ [Some(..), None, ref tail @ ..] => {}
+ [Some(..), Some(..), ref tail @ ..] => {}
+ [None] => {}
+ }
+ let vec = vec![1];
+ let vec: &[isize] = &vec;
+ match *vec {
+ [_, ref tail @ ..] => (),
+ [] => ()
+ }
+ let vec = vec![0.5f32];
+ let vec: &[f32] = &vec;
+ match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _, ..]` not covered
+ [0.1, 0.2, 0.3] => (),
+ [0.1, 0.2] => (),
+ [0.1] => (),
+ [] => ()
+ }
+ let vec = vec![Some(42), None, Some(21)];
+ let vec: &[Option<isize>] = &vec;
+ match *vec {
+ [Some(..), None, ref tail @ ..] => {}
+ [Some(..), Some(..), ref tail @ ..] => {}
+ [None, None, ref tail @ ..] => {}
+ [None, Some(..), ref tail @ ..] => {}
+ [Some(_)] => {}
+ [None] => {}
+ [] => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
new file mode 100644
index 000000000..e2260f50b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
@@ -0,0 +1,121 @@
+error[E0004]: non-exhaustive patterns: `T::A` not covered
+ --> $DIR/non-exhaustive-match.rs:7:11
+ |
+LL | match x { T::B => { } }
+ | ^ pattern `T::A` not covered
+ |
+note: `T` defined here
+ --> $DIR/non-exhaustive-match.rs:3:10
+ |
+LL | enum T { A, B }
+ | - ^ not covered
+ = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match x { T::B => { }, T::A => todo!() }
+ | +++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `false` not covered
+ --> $DIR/non-exhaustive-match.rs:8:11
+ |
+LL | match true {
+ | ^^^^ pattern `false` not covered
+ |
+ = note: the matched value is of type `bool`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ true => {}
+LL + false => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Some(_)` not covered
+ --> $DIR/non-exhaustive-match.rs:11:11
+ |
+LL | match Some(10) {
+ | ^^^^^^^^ pattern `Some(_)` not covered
+ |
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: not covered
+ = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ None => {}
+LL + Some(_) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
+ --> $DIR/non-exhaustive-match.rs:14:11
+ |
+LL | match (2, 3, 4) {
+ | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
+ |
+ = note: the matched value is of type `(i32, i32, i32)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (_, _, 4) => {}
+LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered
+ --> $DIR/non-exhaustive-match.rs:18:11
+ |
+LL | match (T::A, T::A) {
+ | ^^^^^^^^^^^^ patterns `(T::A, T::A)` and `(T::B, T::B)` not covered
+ |
+ = note: the matched value is of type `(T, T)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (T::B, T::A) => {}
+LL + (T::A, T::A) | (T::B, T::B) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `T::B` not covered
+ --> $DIR/non-exhaustive-match.rs:22:11
+ |
+LL | match T::A {
+ | ^^^^ pattern `T::B` not covered
+ |
+note: `T` defined here
+ --> $DIR/non-exhaustive-match.rs:3:13
+ |
+LL | enum T { A, B }
+ | - ^ not covered
+ = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ T::A => {}
+LL + T::B => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `[]` not covered
+ --> $DIR/non-exhaustive-match.rs:33:11
+ |
+LL | match *vec {
+ | ^^^^ pattern `[]` not covered
+ |
+ = note: the matched value is of type `[Option<isize>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [None] => {}
+LL + [] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
+ --> $DIR/non-exhaustive-match.rs:46:11
+ |
+LL | match *vec {
+ | ^^^^ pattern `[_, _, _, _, ..]` not covered
+ |
+ = note: the matched value is of type `[f32]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [] => (),
+LL + [_, _, _, _, ..] => todo!()
+ |
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
new file mode 100644
index 000000000..4bd344219
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
@@ -0,0 +1,89 @@
+struct Foo {
+ first: bool,
+ second: Option<[usize; 4]>
+}
+
+fn struct_with_a_nested_enum_and_vector() {
+ match (Foo { first: true, second: None }) {
+//~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+ Foo { first: true, second: None } => (),
+ Foo { first: true, second: Some(_) } => (),
+ Foo { first: false, second: None } => (),
+ Foo { first: false, second: Some([1, 2, 3, 4]) } => ()
+ }
+}
+
+enum Color {
+ Red,
+ Green,
+ CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+}
+
+fn enum_with_single_missing_variant() {
+ match Color::Red {
+ //~^ ERROR non-exhaustive patterns: `Color::Red` not covered
+ Color::CustomRGBA { .. } => (),
+ Color::Green => ()
+ }
+}
+
+enum Direction {
+ North, East, South, West
+}
+
+fn enum_with_multiple_missing_variants() {
+ match Direction::North {
+ //~^ ERROR non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
+ Direction::North => ()
+ }
+}
+
+enum ExcessiveEnum {
+ First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
+}
+
+fn enum_with_excessive_missing_variants() {
+ match ExcessiveEnum::First {
+ //~^ ERROR `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
+
+ ExcessiveEnum::First => ()
+ }
+}
+
+fn enum_struct_variant() {
+ match Color::Red {
+ //~^ ERROR non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
+ Color::Red => (),
+ Color::Green => (),
+ Color::CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
+ Color::CustomRGBA { a: false, r: _, g: _, b: _ } => ()
+ }
+}
+
+enum Enum {
+ First,
+ Second(bool)
+}
+
+fn vectors_with_nested_enums() {
+ let x: &'static [Enum] = &[Enum::First, Enum::Second(false)];
+ match *x {
+ //~^ ERROR non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
+ [] => (),
+ [_] => (),
+ [Enum::First, _] => (),
+ [Enum::Second(true), Enum::First] => (),
+ [Enum::Second(true), Enum::Second(true)] => (),
+ [Enum::Second(false), _] => (),
+ [_, _, ref tail @ .., _] => ()
+ }
+}
+
+fn missing_nil() {
+ match ((), false) {
+ //~^ ERROR non-exhaustive patterns: `((), false)` not covered
+ ((), true) => ()
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
new file mode 100644
index 000000000..b8af566de
--- /dev/null
+++ b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
@@ -0,0 +1,129 @@
+error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+ --> $DIR/non-exhaustive-pattern-witness.rs:7:11
+ |
+LL | match (Foo { first: true, second: None }) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:1:8
+ |
+LL | struct Foo {
+ | ^^^
+ = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
+LL + Foo { first: false, second: Some([_, _, _, _]) } => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Color::Red` not covered
+ --> $DIR/non-exhaustive-pattern-witness.rs:23:11
+ |
+LL | match Color::Red {
+ | ^^^^^^^^^^ pattern `Color::Red` not covered
+ |
+note: `Color` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:17:5
+ |
+LL | enum Color {
+ | -----
+LL | Red,
+ | ^^^ not covered
+ = note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Color::Green => (),
+LL + Color::Red => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
+ --> $DIR/non-exhaustive-pattern-witness.rs:35:11
+ |
+LL | match Direction::North {
+ | ^^^^^^^^^^^^^^^^ patterns `Direction::East`, `Direction::South` and `Direction::West` not covered
+ |
+note: `Direction` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:31:12
+ |
+LL | enum Direction {
+ | ---------
+LL | North, East, South, West
+ | ^^^^ ^^^^^ ^^^^ not covered
+ | | |
+ | | not covered
+ | not covered
+ = note: the matched value is of type `Direction`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Direction::North => (),
+LL + Direction::East | Direction::South | Direction::West => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
+ --> $DIR/non-exhaustive-pattern-witness.rs:46:11
+ |
+LL | match ExcessiveEnum::First {
+ | ^^^^^^^^^^^^^^^^^^^^ patterns `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
+ |
+note: `ExcessiveEnum` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:41:6
+ |
+LL | enum ExcessiveEnum {
+ | ^^^^^^^^^^^^^
+ = note: the matched value is of type `ExcessiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ExcessiveEnum::First => (),
+LL + _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
+ --> $DIR/non-exhaustive-pattern-witness.rs:54:11
+ |
+LL | match Color::Red {
+ | ^^^^^^^^^^ pattern `Color::CustomRGBA { a: true, .. }` not covered
+ |
+note: `Color` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:19:5
+ |
+LL | enum Color {
+ | -----
+...
+LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+ | ^^^^^^^^^^ not covered
+ = note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
+LL + Color::CustomRGBA { a: true, .. } => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
+ --> $DIR/non-exhaustive-pattern-witness.rs:70:11
+ |
+LL | match *x {
+ | ^^ pattern `[Enum::Second(true), Enum::Second(false)]` not covered
+ |
+ = note: the matched value is of type `[Enum]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [_, _, ref tail @ .., _] => (),
+LL + [Enum::Second(true), Enum::Second(false)] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `((), false)` not covered
+ --> $DIR/non-exhaustive-pattern-witness.rs:83:11
+ |
+LL | match ((), false) {
+ | ^^^^^^^^^^^ pattern `((), false)` not covered
+ |
+ = note: the matched value is of type `((), bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ ((), true) => (),
+LL + ((), false) => todo!()
+ |
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.rs b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
new file mode 100644
index 000000000..7a3e991d5
--- /dev/null
+++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
@@ -0,0 +1,9 @@
+fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
+//~^ ERROR refutable pattern in function argument
+//~| `(_, _)` not covered
+
+fn main() {
+ let (1, (Some(1), 2..=3)) = (1, (None, 2));
+ //~^ ERROR refutable pattern in local binding
+ //~| `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
+}
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
new file mode 100644
index 000000000..c518de477
--- /dev/null
+++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
@@ -0,0 +1,25 @@
+error[E0005]: refutable pattern in function argument
+ --> $DIR/refutable-pattern-errors.rs:1:9
+ |
+LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
+ | ^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+ |
+ = note: the matched value is of type `(isize, (Option<isize>, isize))`
+
+error[E0005]: refutable pattern in local binding
+ --> $DIR/refutable-pattern-errors.rs:6:9
+ |
+LL | let (1, (Some(1), 2..=3)) = (1, (None, 2));
+ | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ = note: the matched value is of type `(i32, (Option<i32>, i32))`
+help: you might want to use `if let` to ignore the variants that aren't matched
+ |
+LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() }
+ | ++ ~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
new file mode 100644
index 000000000..17dc38ab2
--- /dev/null
+++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let f = |3: isize| println!("hello");
+ //~^ ERROR refutable pattern in function argument
+ //~| `_` not covered
+ f(4);
+}
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
new file mode 100644
index 000000000..55f0b2319
--- /dev/null
+++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
@@ -0,0 +1,11 @@
+error[E0005]: refutable pattern in function argument
+ --> $DIR/refutable-pattern-in-fn-arg.rs:2:14
+ |
+LL | let f = |3: isize| println!("hello");
+ | ^ pattern `_` not covered
+ |
+ = note: the matched value is of type `isize`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/pattern/usefulness/slice-pattern-const-2.rs b/tests/ui/pattern/usefulness/slice-pattern-const-2.rs
new file mode 100644
index 000000000..4bf8d0fd2
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-pattern-const-2.rs
@@ -0,0 +1,31 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let s = &[0x00; 4][..]; //Slice of any value
+ const MAGIC_TEST: &[u32] = &[4, 5, 6, 7]; //Const slice to pattern match with
+ match s {
+ MAGIC_TEST => (),
+ [0x00, 0x00, 0x00, 0x00] => (),
+ [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ match s {
+ [0x00, 0x00, 0x00, 0x00] => (),
+ MAGIC_TEST => (),
+ [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ match s {
+ [0x00, 0x00, 0x00, 0x00] => (),
+ [4, 5, 6, 7] => (),
+ MAGIC_TEST => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ const FOO: [u32; 1] = [4];
+ match [99] {
+ [0x00] => (),
+ [4] => (),
+ FOO => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+}
diff --git a/tests/ui/pattern/usefulness/slice-pattern-const-2.stderr b/tests/ui/pattern/usefulness/slice-pattern-const-2.stderr
new file mode 100644
index 000000000..dcad11a38
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-pattern-const-2.stderr
@@ -0,0 +1,32 @@
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-2.rs:9:9
+ |
+LL | [4, 5, 6, 7] => (),
+ | ^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/slice-pattern-const-2.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-2.rs:15:9
+ |
+LL | [4, 5, 6, 7] => (),
+ | ^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-2.rs:21:9
+ |
+LL | MAGIC_TEST => (),
+ | ^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-2.rs:28:9
+ |
+LL | FOO => (),
+ | ^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/pattern/usefulness/slice-pattern-const-3.rs b/tests/ui/pattern/usefulness/slice-pattern-const-3.rs
new file mode 100644
index 000000000..2ca8323f0
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-pattern-const-3.rs
@@ -0,0 +1,31 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let s = &["0x00"; 4][..]; //Slice of any value
+ const MAGIC_TEST: &[&str] = &["4", "5", "6", "7"]; //Const slice to pattern match with
+ match s {
+ MAGIC_TEST => (),
+ ["0x00", "0x00", "0x00", "0x00"] => (),
+ ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ match s {
+ ["0x00", "0x00", "0x00", "0x00"] => (),
+ MAGIC_TEST => (),
+ ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ match s {
+ ["0x00", "0x00", "0x00", "0x00"] => (),
+ ["4", "5", "6", "7"] => (),
+ MAGIC_TEST => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ const FOO: [&str; 1] = ["boo"];
+ match ["baa"] {
+ ["0x00"] => (),
+ ["boo"] => (),
+ FOO => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+}
diff --git a/tests/ui/pattern/usefulness/slice-pattern-const-3.stderr b/tests/ui/pattern/usefulness/slice-pattern-const-3.stderr
new file mode 100644
index 000000000..b90b3a88a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-pattern-const-3.stderr
@@ -0,0 +1,32 @@
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-3.rs:9:9
+ |
+LL | ["4", "5", "6", "7"] => (),
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/slice-pattern-const-3.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-3.rs:15:9
+ |
+LL | ["4", "5", "6", "7"] => (),
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-3.rs:21:9
+ |
+LL | MAGIC_TEST => (),
+ | ^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const-3.rs:28:9
+ |
+LL | FOO => (),
+ | ^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/pattern/usefulness/slice-pattern-const.rs b/tests/ui/pattern/usefulness/slice-pattern-const.rs
new file mode 100644
index 000000000..89195d5b1
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-pattern-const.rs
@@ -0,0 +1,54 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let s = &[0x00; 4][..]; //Slice of any value
+ const MAGIC_TEST: &[u8] = b"TEST"; //Const slice to pattern match with
+ match s {
+ MAGIC_TEST => (),
+ [0x00, 0x00, 0x00, 0x00] => (),
+ [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ match s {
+ [0x00, 0x00, 0x00, 0x00] => (),
+ MAGIC_TEST => (),
+ [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ match s {
+ [0x00, 0x00, 0x00, 0x00] => (),
+ [84, 69, 83, 84] => (),
+ MAGIC_TEST => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ const FOO: [u8; 1] = [4];
+ match [99] {
+ [0x00] => (),
+ [4] => (),
+ FOO => (), //~ ERROR unreachable pattern
+ _ => (),
+ }
+ const BAR: &[u8; 1] = &[4];
+ match &[99] {
+ [0x00] => (),
+ [4] => (),
+ BAR => (), //~ ERROR unreachable pattern
+ b"a" => (),
+ _ => (),
+ }
+
+ const BOO: &[u8; 0] = &[];
+ match &[] {
+ [] => (),
+ BOO => (), //~ ERROR unreachable pattern
+ b"" => (), //~ ERROR unreachable pattern
+ _ => (), //~ ERROR unreachable pattern
+ }
+
+ const CONST1: &[bool; 1] = &[true];
+ match &[false] {
+ CONST1 => {}
+ [true] => {} //~ ERROR unreachable pattern
+ [false] => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/slice-pattern-const.stderr b/tests/ui/pattern/usefulness/slice-pattern-const.stderr
new file mode 100644
index 000000000..1fffb9fed
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-pattern-const.stderr
@@ -0,0 +1,62 @@
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:9:9
+ |
+LL | [84, 69, 83, 84] => (),
+ | ^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/slice-pattern-const.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:15:9
+ |
+LL | [84, 69, 83, 84] => (),
+ | ^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:21:9
+ |
+LL | MAGIC_TEST => (),
+ | ^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:28:9
+ |
+LL | FOO => (),
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:35:9
+ |
+LL | BAR => (),
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:43:9
+ |
+LL | BOO => (),
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:44:9
+ |
+LL | b"" => (),
+ | ^^^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:45:9
+ |
+LL | _ => (),
+ | ^
+
+error: unreachable pattern
+ --> $DIR/slice-pattern-const.rs:51:9
+ |
+LL | [true] => {}
+ | ^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
new file mode 100644
index 000000000..46e0da5be
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
@@ -0,0 +1,129 @@
+fn main() {
+ let s: &[bool] = &[true; 0];
+ let s1: &[bool; 1] = &[false; 1];
+ let s2: &[bool; 2] = &[false; 2];
+ let s3: &[bool; 3] = &[false; 3];
+ let s10: &[bool; 10] = &[false; 10];
+
+ match s2 {
+ //~^ ERROR `&[false, _]` not covered
+ [true, .., true] => {}
+ }
+ match s3 {
+ //~^ ERROR `&[false, ..]` not covered
+ [true, .., true] => {}
+ }
+ match s10 {
+ //~^ ERROR `&[false, ..]` not covered
+ [true, .., true] => {}
+ }
+
+ match s1 {
+ [true, ..] => {}
+ [.., false] => {}
+ }
+ match s2 {
+ //~^ ERROR `&[false, true]` not covered
+ [true, ..] => {}
+ [.., false] => {}
+ }
+ match s3 {
+ //~^ ERROR `&[false, .., true]` not covered
+ [true, ..] => {}
+ [.., false] => {}
+ }
+ match s {
+ //~^ ERROR `&[false, .., true]` not covered
+ [] => {}
+ [true, ..] => {}
+ [.., false] => {}
+ }
+
+ match s {
+ //~^ ERROR `&[_, ..]` not covered
+ [] => {}
+ }
+ match s {
+ //~^ ERROR `&[_, _, ..]` not covered
+ [] => {}
+ [_] => {}
+ }
+ match s {
+ //~^ ERROR `&[false, ..]` not covered
+ [] => {}
+ [true, ..] => {}
+ }
+ match s {
+ //~^ ERROR `&[false, _, ..]` not covered
+ [] => {}
+ [_] => {}
+ [true, ..] => {}
+ }
+ match s {
+ //~^ ERROR `&[_, .., false]` not covered
+ [] => {}
+ [_] => {}
+ [.., true] => {}
+ }
+
+ match s {
+ //~^ ERROR `&[_, _, .., true]` not covered
+ [] => {}
+ [_] => {}
+ [_, _] => {}
+ [.., false] => {}
+ }
+ match s {
+ //~^ ERROR `&[true, _, .., _]` not covered
+ [] => {}
+ [_] => {}
+ [_, _] => {}
+ [false, .., false] => {}
+ }
+
+ const CONST: &[bool] = &[true];
+ match s {
+ //~^ ERROR `&[]` and `&[_, _, ..]` not covered
+ &[true] => {}
+ }
+ match s {
+ //~^ ERROR `&[]` and `&[_, _, ..]` not covered
+ CONST => {}
+ }
+ match s {
+ //~^ ERROR `&[]` and `&[_, _, ..]` not covered
+ CONST => {}
+ &[false] => {}
+ }
+ match s {
+ //~^ ERROR `&[]` and `&[_, _, ..]` not covered
+ &[false] => {}
+ CONST => {}
+ }
+ match s {
+ //~^ ERROR `&[_, _, ..]` not covered
+ &[] => {}
+ CONST => {}
+ }
+ match s {
+ //~^ ERROR `&[false]` not covered
+ &[] => {}
+ CONST => {}
+ &[_, _, ..] => {}
+ }
+ match s {
+ [] => {}
+ [false] => {}
+ CONST => {}
+ [_, _, ..] => {}
+ }
+ const CONST1: &[bool; 1] = &[true];
+ match s1 {
+ //~^ ERROR `&[false]` not covered
+ CONST1 => {}
+ }
+ match s1 {
+ CONST1 => {}
+ [false] => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
new file mode 100644
index 000000000..5d1e170ae
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
@@ -0,0 +1,263 @@
+error[E0004]: non-exhaustive patterns: `&[false, _]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:8:11
+ |
+LL | match s2 {
+ | ^^ pattern `&[false, _]` not covered
+ |
+ = note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, _] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:12:11
+ |
+LL | match s3 {
+ | ^^ pattern `&[false, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:16:11
+ |
+LL | match s10 {
+ | ^^^ pattern `&[false, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool; 10]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:25:11
+ |
+LL | match s2 {
+ | ^^ pattern `&[false, true]` not covered
+ |
+ = note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, true] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:30:11
+ |
+LL | match s3 {
+ | ^^ pattern `&[false, .., true]` not covered
+ |
+ = note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, .., true] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:35:11
+ |
+LL | match s {
+ | ^ pattern `&[false, .., true]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, .., true] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:42:11
+ |
+LL | match s {
+ | ^ pattern `&[_, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [] => {}
+LL + &[_, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:46:11
+ |
+LL | match s {
+ | ^ pattern `&[_, _, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [_] => {}
+LL + &[_, _, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:51:11
+ |
+LL | match s {
+ | ^ pattern `&[false, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, ..] => {}
+LL + &[false, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:56:11
+ |
+LL | match s {
+ | ^ pattern `&[false, _, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, ..] => {}
+LL + &[false, _, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:62:11
+ |
+LL | match s {
+ | ^ pattern `&[_, .., false]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., true] => {}
+LL + &[_, .., false] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:69:11
+ |
+LL | match s {
+ | ^ pattern `&[_, _, .., true]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[_, _, .., true] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:76:11
+ |
+LL | match s {
+ | ^ pattern `&[true, _, .., _]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [false, .., false] => {}
+LL + &[true, _, .., _] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:85:11
+ |
+LL | match s {
+ | ^ patterns `&[]` and `&[_, _, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ &[true] => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:89:11
+ |
+LL | match s {
+ | ^ patterns `&[]` and `&[_, _, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ CONST => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:93:11
+ |
+LL | match s {
+ | ^ patterns `&[]` and `&[_, _, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ &[false] => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:98:11
+ |
+LL | match s {
+ | ^ patterns `&[]` and `&[_, _, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ CONST => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:103:11
+ |
+LL | match s {
+ | ^ pattern `&[_, _, ..]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ CONST => {}
+LL + &[_, _, ..] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:108:11
+ |
+LL | match s {
+ | ^ pattern `&[false]` not covered
+ |
+ = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[_, _, ..] => {}
+LL + &[false] => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `&[false]` not covered
+ --> $DIR/slice-patterns-exhaustiveness.rs:121:11
+ |
+LL | match s1 {
+ | ^^ pattern `&[false]` not covered
+ |
+ = note: the matched value is of type `&[bool; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ CONST1 => {}
+LL + &[false] => todo!()
+ |
+
+error: aborting due to 20 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/slice-patterns-irrefutable.rs b/tests/ui/pattern/usefulness/slice-patterns-irrefutable.rs
new file mode 100644
index 000000000..cbf64e2c5
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-patterns-irrefutable.rs
@@ -0,0 +1,26 @@
+// check-pass
+
+fn main() {
+ let s: &[bool] = &[true; 0];
+ let s0: &[bool; 0] = &[];
+ let s1: &[bool; 1] = &[false; 1];
+ let s2: &[bool; 2] = &[false; 2];
+
+ let [] = s0;
+ let [_] = s1;
+ let [_, _] = s2;
+
+ let [..] = s;
+ let [..] = s0;
+ let [..] = s1;
+ let [..] = s2;
+
+ let [_, ..] = s1;
+ let [.., _] = s1;
+ let [_, ..] = s2;
+ let [.., _] = s2;
+
+ let [_, _, ..] = s2;
+ let [_, .., _] = s2;
+ let [.., _, _] = s2;
+}
diff --git a/tests/ui/pattern/usefulness/slice-patterns-reachability.rs b/tests/ui/pattern/usefulness/slice-patterns-reachability.rs
new file mode 100644
index 000000000..7c747b5e0
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-patterns-reachability.rs
@@ -0,0 +1,25 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let s: &[bool] = &[];
+
+ match s {
+ [true, ..] => {}
+ [true, ..] => {} //~ ERROR unreachable pattern
+ [true] => {} //~ ERROR unreachable pattern
+ [..] => {}
+ }
+ match s {
+ [.., true] => {}
+ [.., true] => {} //~ ERROR unreachable pattern
+ [true] => {} //~ ERROR unreachable pattern
+ [..] => {}
+ }
+ match s {
+ [false, .., true] => {}
+ [false, .., true] => {} //~ ERROR unreachable pattern
+ [false, true] => {} //~ ERROR unreachable pattern
+ [false] => {}
+ [..] => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/slice-patterns-reachability.stderr b/tests/ui/pattern/usefulness/slice-patterns-reachability.stderr
new file mode 100644
index 000000000..607ffb765
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice-patterns-reachability.stderr
@@ -0,0 +1,44 @@
+error: unreachable pattern
+ --> $DIR/slice-patterns-reachability.rs:8:9
+ |
+LL | [true, ..] => {}
+ | ^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/slice-patterns-reachability.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-patterns-reachability.rs:9:9
+ |
+LL | [true] => {}
+ | ^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-patterns-reachability.rs:14:9
+ |
+LL | [.., true] => {}
+ | ^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-patterns-reachability.rs:15:9
+ |
+LL | [true] => {}
+ | ^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-patterns-reachability.rs:20:9
+ |
+LL | [false, .., true] => {}
+ | ^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/slice-patterns-reachability.rs:21:9
+ |
+LL | [false, true] => {}
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/pattern/usefulness/stable-gated-fields.rs b/tests/ui/pattern/usefulness/stable-gated-fields.rs
new file mode 100644
index 000000000..90f40a8d6
--- /dev/null
+++ b/tests/ui/pattern/usefulness/stable-gated-fields.rs
@@ -0,0 +1,16 @@
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableStruct;
+
+fn main() {
+ let UnstableStruct { stable } = UnstableStruct::default();
+ //~^ pattern does not mention field `stable2` and inaccessible fields
+
+ let UnstableStruct { stable, stable2 } = UnstableStruct::default();
+ //~^ pattern requires `..` due to inaccessible fields
+
+ // OK: stable field is matched
+ let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+}
diff --git a/tests/ui/pattern/usefulness/stable-gated-fields.stderr b/tests/ui/pattern/usefulness/stable-gated-fields.stderr
new file mode 100644
index 000000000..cf98c51a2
--- /dev/null
+++ b/tests/ui/pattern/usefulness/stable-gated-fields.stderr
@@ -0,0 +1,29 @@
+error[E0027]: pattern does not mention field `stable2` and inaccessible fields
+ --> $DIR/stable-gated-fields.rs:8:9
+ |
+LL | let UnstableStruct { stable } = UnstableStruct::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2` and inaccessible fields
+ |
+help: include the missing field in the pattern and ignore the inaccessible fields
+ |
+LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+ | ~~~~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | let UnstableStruct { stable, .. } = UnstableStruct::default();
+ | ~~~~~~
+
+error: pattern requires `..` due to inaccessible fields
+ --> $DIR/stable-gated-fields.rs:11:9
+ |
+LL | let UnstableStruct { stable, stable2 } = UnstableStruct::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: ignore the inaccessible and unused fields
+ |
+LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/tests/ui/pattern/usefulness/stable-gated-patterns.rs b/tests/ui/pattern/usefulness/stable-gated-patterns.rs
new file mode 100644
index 000000000..03db01160
--- /dev/null
+++ b/tests/ui/pattern/usefulness/stable-gated-patterns.rs
@@ -0,0 +1,18 @@
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableEnum;
+
+fn main() {
+ match UnstableEnum::Stable {
+ UnstableEnum::Stable => {}
+ }
+ //~^^^ non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered
+
+ match UnstableEnum::Stable {
+ UnstableEnum::Stable => {}
+ UnstableEnum::Stable2 => {}
+ }
+ //~^^^^ non-exhaustive patterns: `_` not covered
+}
diff --git a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr
new file mode 100644
index 000000000..7b8588a3c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr
@@ -0,0 +1,42 @@
+error[E0004]: non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered
+ --> $DIR/stable-gated-patterns.rs:8:11
+ |
+LL | match UnstableEnum::Stable {
+ | ^^^^^^^^^^^^^^^^^^^^ patterns `UnstableEnum::Stable2` and `_` not covered
+ |
+note: `UnstableEnum` defined here
+ --> $DIR/auxiliary/unstable.rs:9:5
+ |
+LL | pub enum UnstableEnum {
+ | ---------------------
+...
+LL | Stable2,
+ | ^^^^^^^ not covered
+ = note: the matched value is of type `UnstableEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ UnstableEnum::Stable => {}
+LL + UnstableEnum::Stable2 | _ => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/stable-gated-patterns.rs:13:11
+ |
+LL | match UnstableEnum::Stable {
+ | ^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
+ |
+note: `UnstableEnum` defined here
+ --> $DIR/auxiliary/unstable.rs:5:1
+ |
+LL | pub enum UnstableEnum {
+ | ^^^^^^^^^^^^^^^^^^^^^
+ = note: the matched value is of type `UnstableEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ UnstableEnum::Stable2 => {}
+LL + _ => todo!()
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.rs b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.rs
new file mode 100644
index 000000000..b1fc0f5ad
--- /dev/null
+++ b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.rs
@@ -0,0 +1,12 @@
+enum A {
+ B { x: Option<isize> },
+ C
+}
+
+fn main() {
+ let x = A::B { x: Some(3) };
+ match x { //~ ERROR non-exhaustive patterns
+ A::C => {}
+ A::B { x: None } => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
new file mode 100644
index 000000000..85c97be29
--- /dev/null
+++ b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
@@ -0,0 +1,23 @@
+error[E0004]: non-exhaustive patterns: `A::B { x: Some(_) }` not covered
+ --> $DIR/struct-like-enum-nonexhaustive.rs:8:11
+ |
+LL | match x {
+ | ^ pattern `A::B { x: Some(_) }` not covered
+ |
+note: `A` defined here
+ --> $DIR/struct-like-enum-nonexhaustive.rs:2:5
+ |
+LL | enum A {
+ | -
+LL | B { x: Option<isize> },
+ | ^ not covered
+ = note: the matched value is of type `A`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ A::B { x: None } => {}
+LL + A::B { x: Some(_) } => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/struct-pattern-match-useless.rs b/tests/ui/pattern/usefulness/struct-pattern-match-useless.rs
new file mode 100644
index 000000000..93f0a9317
--- /dev/null
+++ b/tests/ui/pattern/usefulness/struct-pattern-match-useless.rs
@@ -0,0 +1,15 @@
+#![deny(unreachable_patterns)]
+
+struct Foo {
+ x: isize,
+ y: isize,
+}
+
+pub fn main() {
+ let a = Foo { x: 1, y: 2 };
+ match a {
+ Foo { x: _x, y: _y } => (),
+ Foo { .. } => () //~ ERROR unreachable pattern
+ }
+
+}
diff --git a/tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr b/tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr
new file mode 100644
index 000000000..fbee33de6
--- /dev/null
+++ b/tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr
@@ -0,0 +1,16 @@
+error: unreachable pattern
+ --> $DIR/struct-pattern-match-useless.rs:12:9
+ |
+LL | Foo { x: _x, y: _y } => (),
+ | -------------------- matches any value
+LL | Foo { .. } => ()
+ | ^^^^^^^^^^ unreachable pattern
+ |
+note: the lint level is defined here
+ --> $DIR/struct-pattern-match-useless.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/usefulness/top-level-alternation.rs b/tests/ui/pattern/usefulness/top-level-alternation.rs
new file mode 100644
index 000000000..e8cd12ea4
--- /dev/null
+++ b/tests/ui/pattern/usefulness/top-level-alternation.rs
@@ -0,0 +1,57 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+ while let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
+ if let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
+
+ match 0u8 {
+ 0
+ | 0 => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+ match Some(0u8) {
+ Some(0)
+ | Some(0) => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+ match (0u8, 0u8) {
+ (0, _) | (_, 0) => {}
+ (0, 0) => {} //~ ERROR unreachable pattern
+ (1, 1) => {}
+ _ => {}
+ }
+ match (0u8, 0u8) {
+ (0, 1) | (2, 3) => {}
+ (0, 3) => {}
+ (2, 1) => {}
+ _ => {}
+ }
+ match (0u8, 0u8) {
+ (_, 0) | (_, 1) => {}
+ _ => {}
+ }
+ match (0u8, 0u8) {
+ (0, _) | (1, _) => {}
+ _ => {}
+ }
+ match Some(0u8) {
+ None | Some(_) => {}
+ _ => {} //~ ERROR unreachable pattern
+ }
+ match Some(0u8) {
+ None | Some(_) => {}
+ Some(_) => {} //~ ERROR unreachable pattern
+ None => {} //~ ERROR unreachable pattern
+ }
+ match Some(0u8) {
+ Some(_) => {}
+ None => {}
+ None | Some(_) => {} //~ ERROR unreachable pattern
+ }
+ match 0u8 {
+ 1 | 2 => {},
+ 1..=2 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ let (0 | 0) = 0 else { return }; //~ ERROR unreachable pattern
+}
diff --git a/tests/ui/pattern/usefulness/top-level-alternation.stderr b/tests/ui/pattern/usefulness/top-level-alternation.stderr
new file mode 100644
index 000000000..17fa951c5
--- /dev/null
+++ b/tests/ui/pattern/usefulness/top-level-alternation.stderr
@@ -0,0 +1,74 @@
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:4:23
+ |
+LL | while let 0..=2 | 1 = 0 {}
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/top-level-alternation.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:5:20
+ |
+LL | if let 0..=2 | 1 = 0 {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:9:15
+ |
+LL | | 0 => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:14:15
+ |
+LL | | Some(0) => {}
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:19:9
+ |
+LL | (0, 0) => {}
+ | ^^^^^^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:39:9
+ |
+LL | _ => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:43:9
+ |
+LL | Some(_) => {}
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:44:9
+ |
+LL | None => {}
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:49:9
+ |
+LL | None | Some(_) => {}
+ | ^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:53:9
+ |
+LL | 1..=2 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/top-level-alternation.rs:56:14
+ |
+LL | let (0 | 0) = 0 else { return };
+ | ^
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.rs b/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.rs
new file mode 100644
index 000000000..76bcf3fbd
--- /dev/null
+++ b/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.rs
@@ -0,0 +1,9 @@
+struct Foo(isize, isize);
+
+fn main() {
+ let x = Foo(1, 2);
+ match x { //~ ERROR non-exhaustive
+ Foo(1, b) => println!("{}", b),
+ Foo(2, b) => println!("{}", b)
+ }
+}
diff --git a/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr b/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
new file mode 100644
index 000000000..e2a65ff85
--- /dev/null
+++ b/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered
+ --> $DIR/tuple-struct-nonexhaustive.rs:5:11
+ |
+LL | match x {
+ | ^ pattern `Foo(_, _)` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/tuple-struct-nonexhaustive.rs:1:8
+ |
+LL | struct Foo(isize, isize);
+ | ^^^
+ = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo(2, b) => println!("{}", b),
+LL + Foo(_, _) => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs b/tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs
new file mode 100644
index 000000000..cb44c1da7
--- /dev/null
+++ b/tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs
@@ -0,0 +1,36 @@
+#[deny(unreachable_patterns)]
+
+fn parse_data1(data: &[u8]) -> u32 {
+ match data {
+ b"" => 1,
+ _ => 2,
+ }
+}
+
+fn parse_data2(data: &[u8]) -> u32 {
+ match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered
+ b"" => 1,
+ }
+}
+
+fn parse_data3(data: &[u8; 0]) -> u8 {
+ match data {
+ b"" => 1,
+ }
+}
+
+fn parse_data4(data: &[u8]) -> u8 {
+ match data { //~ ERROR non-exhaustive patterns
+ b"aaa" => 0,
+ [_, _, _] => 1,
+ }
+}
+
+fn parse_data5(data: &[u8; 3]) -> u8 {
+ match data {
+ b"aaa" => 0,
+ [_, _, _] => 1,
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr b/tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr
new file mode 100644
index 000000000..acae605da
--- /dev/null
+++ b/tests/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr
@@ -0,0 +1,29 @@
+error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
+ --> $DIR/type_polymorphic_byte_str_literals.rs:11:11
+ |
+LL | match data {
+ | ^^^^ pattern `&[_, ..]` not covered
+ |
+ = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ b"" => 1,
+LL ~ &[_, ..] => todo!(),
+ |
+
+error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
+ --> $DIR/type_polymorphic_byte_str_literals.rs:23:11
+ |
+LL | match data {
+ | ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
+ |
+ = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ [_, _, _] => 1,
+LL ~ _ => todo!(),
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/uninhabited.rs b/tests/ui/pattern/usefulness/uninhabited.rs
new file mode 100644
index 000000000..5622808d4
--- /dev/null
+++ b/tests/ui/pattern/usefulness/uninhabited.rs
@@ -0,0 +1,143 @@
+// check-pass
+// aux-build:empty.rs
+//
+// This tests plays with matching and uninhabited types. This also serves as a test for the
+// `Ty::is_inhabited_from` function.
+#![feature(never_type)]
+#![feature(never_type_fallback)]
+#![feature(exhaustive_patterns)]
+#![deny(unreachable_patterns)]
+
+macro_rules! assert_empty {
+ ($ty:ty) => {
+ const _: () = {
+ fn assert_empty(x: $ty) {
+ match x {}
+ match Some(x) {
+ None => {}
+ }
+ }
+ };
+ };
+}
+macro_rules! assert_non_empty {
+ ($ty:ty) => {
+ const _: () = {
+ fn assert_non_empty(x: $ty) {
+ match x {
+ _ => {}
+ }
+ match Some(x) {
+ None => {}
+ Some(_) => {}
+ }
+ }
+ };
+ };
+}
+
+extern crate empty;
+assert_empty!(empty::EmptyForeignEnum);
+assert_empty!(empty::VisiblyUninhabitedForeignStruct);
+assert_non_empty!(empty::SecretlyUninhabitedForeignStruct);
+
+enum Void {}
+assert_empty!(Void);
+
+enum Enum2 {
+ Foo(Void),
+ Bar(!),
+}
+assert_empty!(Enum2);
+
+enum Enum3 {
+ Foo(Void),
+ Bar {
+ x: u64,
+ y: !,
+ },
+}
+assert_empty!(Enum3);
+
+enum Enum4 {
+ Foo(u64),
+ Bar(!),
+}
+assert_non_empty!(Enum4);
+
+struct Struct1(empty::EmptyForeignEnum);
+assert_empty!(Struct1);
+
+struct Struct2 {
+ x: u64,
+ y: !,
+}
+assert_empty!(Struct2);
+
+union Union {
+ foo: !,
+}
+assert_non_empty!(Union);
+
+assert_empty!((!, String));
+
+assert_non_empty!(&'static !);
+assert_non_empty!(&'static Struct1);
+assert_non_empty!(&'static &'static &'static !);
+
+assert_empty!([!; 1]);
+assert_empty!([Void; 2]);
+assert_non_empty!([!; 0]);
+assert_non_empty!(&'static [!]);
+
+mod visibility {
+ /// This struct can only be seen to be inhabited in modules `b`, `c` or `d`, because otherwise
+ /// the uninhabitedness of both `SecretlyUninhabited` structs is hidden.
+ struct SometimesEmptyStruct {
+ x: a::b::SecretlyUninhabited,
+ y: c::AlsoSecretlyUninhabited,
+ }
+
+ /// This enum can only be seen to be inhabited in module `d`.
+ enum SometimesEmptyEnum {
+ X(c::AlsoSecretlyUninhabited),
+ Y(c::d::VerySecretlyUninhabited),
+ }
+
+ mod a {
+ use super::*;
+ pub mod b {
+ use super::*;
+ pub struct SecretlyUninhabited {
+ _priv: !,
+ }
+ assert_empty!(SometimesEmptyStruct);
+ }
+
+ assert_non_empty!(SometimesEmptyStruct);
+ assert_non_empty!(SometimesEmptyEnum);
+ }
+
+ mod c {
+ use super::*;
+ pub struct AlsoSecretlyUninhabited {
+ _priv: ::Struct1,
+ }
+ assert_empty!(SometimesEmptyStruct);
+ assert_non_empty!(SometimesEmptyEnum);
+
+ pub mod d {
+ use super::*;
+ pub struct VerySecretlyUninhabited {
+ _priv: !,
+ }
+ assert_empty!(SometimesEmptyStruct);
+ assert_empty!(SometimesEmptyEnum);
+ }
+ }
+
+ assert_non_empty!(SometimesEmptyStruct);
+ assert_non_empty!(SometimesEmptyEnum);
+}
+
+fn main() {}
diff --git a/tests/ui/pattern/usefulness/unstable-gated-fields.rs b/tests/ui/pattern/usefulness/unstable-gated-fields.rs
new file mode 100644
index 000000000..2b473ae98
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unstable-gated-fields.rs
@@ -0,0 +1,18 @@
+#![feature(unstable_test_feature)]
+
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableStruct;
+
+fn main() {
+ let UnstableStruct { stable, stable2, } = UnstableStruct::default();
+ //~^ pattern does not mention field `unstable`
+
+ let UnstableStruct { stable, unstable, } = UnstableStruct::default();
+ //~^ pattern does not mention field `stable2`
+
+ // OK: stable field is matched
+ let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default();
+}
diff --git a/tests/ui/pattern/usefulness/unstable-gated-fields.stderr b/tests/ui/pattern/usefulness/unstable-gated-fields.stderr
new file mode 100644
index 000000000..e4f5fa06b
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unstable-gated-fields.stderr
@@ -0,0 +1,33 @@
+error[E0027]: pattern does not mention field `unstable`
+ --> $DIR/unstable-gated-fields.rs:10:9
+ |
+LL | let UnstableStruct { stable, stable2, } = UnstableStruct::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `unstable`
+ |
+help: include the missing field in the pattern
+ |
+LL | let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default();
+ | ~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+ | ~~~~~~
+
+error[E0027]: pattern does not mention field `stable2`
+ --> $DIR/unstable-gated-fields.rs:13:9
+ |
+LL | let UnstableStruct { stable, unstable, } = UnstableStruct::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2`
+ |
+help: include the missing field in the pattern
+ |
+LL | let UnstableStruct { stable, unstable, stable2 } = UnstableStruct::default();
+ | ~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | let UnstableStruct { stable, unstable, .. } = UnstableStruct::default();
+ | ~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/tests/ui/pattern/usefulness/unstable-gated-patterns.rs b/tests/ui/pattern/usefulness/unstable-gated-patterns.rs
new file mode 100644
index 000000000..7046555e0
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unstable-gated-patterns.rs
@@ -0,0 +1,22 @@
+#![feature(unstable_test_feature)]
+
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableEnum;
+
+fn main() {
+ match UnstableEnum::Stable {
+ UnstableEnum::Stable => {}
+ UnstableEnum::Stable2 => {}
+ }
+ //~^^^^ non-exhaustive patterns: `UnstableEnum::Unstable` not covered
+
+ // Ok: all variants are explicitly matched
+ match UnstableEnum::Stable {
+ UnstableEnum::Stable => {}
+ UnstableEnum::Stable2 => {}
+ UnstableEnum::Unstable => {}
+ }
+}
diff --git a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr
new file mode 100644
index 000000000..6dc9a4058
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr
@@ -0,0 +1,24 @@
+error[E0004]: non-exhaustive patterns: `UnstableEnum::Unstable` not covered
+ --> $DIR/unstable-gated-patterns.rs:10:11
+ |
+LL | match UnstableEnum::Stable {
+ | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered
+ |
+note: `UnstableEnum` defined here
+ --> $DIR/auxiliary/unstable.rs:11:5
+ |
+LL | pub enum UnstableEnum {
+ | ---------------------
+...
+LL | Unstable,
+ | ^^^^^^^^ not covered
+ = note: the matched value is of type `UnstableEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ UnstableEnum::Stable2 => {}
+LL + UnstableEnum::Unstable => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.