Skip to content

Commit 56de455

Browse files
authored
Fix capacity overflow in single_match with deref patterns (rust-lang#15124)
Fixes rust-lang/rust-clippy#14882 changelog: [`single_match`]: fix ICE with deref patterns and string literals
2 parents 6543a09 + bfc4d17 commit 56de455

File tree

4 files changed

+348
-8
lines changed

4 files changed

+348
-8
lines changed

clippy_lints/src/matches/single_match.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,21 +152,26 @@ fn report_single_pattern(
152152
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
153153
_ => pat_ref_count,
154154
};
155-
// References are only implicitly added to the pattern, so no overflow here.
156-
// e.g. will work: match &Some(_) { Some(_) => () }
157-
// will not: match Some(_) { &Some(_) => () }
158-
let ref_count_diff = ty_ref_count - pat_ref_count;
159155

160-
// Try to remove address of expressions first.
161-
let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
162-
let ref_count_diff = ref_count_diff - removed;
156+
// References are implicitly removed when `deref_patterns` are used.
157+
// They are implicitly added when match ergonomics are used.
158+
let (ex, ref_or_deref_adjust) = if ty_ref_count > pat_ref_count {
159+
let ref_count_diff = ty_ref_count - pat_ref_count;
160+
161+
// Try to remove address of expressions first.
162+
let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
163+
164+
(ex, String::from(if ref_count_diff == removed { "" } else { "&" }))
165+
} else {
166+
(ex, "*".repeat(pat_ref_count - ty_ref_count))
167+
};
163168

164169
let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
165170
let sugg = format!(
166171
"if {} == {}{} {}{els_str}",
167172
snippet_with_context(cx, ex.span, ctxt, "..", &mut app).0,
168173
// PartialEq for different reference counts may not exist.
169-
"&".repeat(ref_count_diff),
174+
ref_or_deref_adjust,
170175
snippet_with_applicability(cx, arm.pat.span, "..", &mut app),
171176
expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
172177
);
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#![feature(deref_patterns)]
2+
#![allow(
3+
incomplete_features,
4+
clippy::eq_op,
5+
clippy::op_ref,
6+
clippy::deref_addrof,
7+
clippy::borrow_deref_ref,
8+
clippy::needless_if
9+
)]
10+
#![deny(clippy::single_match_else)]
11+
12+
fn string() {
13+
if *"" == *"" {}
14+
15+
if *&*&*&*"" == *"" {}
16+
17+
if ***&&"" == *"" {}
18+
19+
if *&*&*"" == *"" {}
20+
21+
if **&&*"" == *"" {}
22+
}
23+
24+
fn int() {
25+
if &&&1 == &&&2 { unreachable!() } else {
26+
// ok
27+
}
28+
//~^^^^^^ single_match_else
29+
if &&1 == &&2 { unreachable!() } else {
30+
// ok
31+
}
32+
//~^^^^^^ single_match_else
33+
if &&1 == &&2 { unreachable!() } else {
34+
// ok
35+
}
36+
//~^^^^^^ single_match_else
37+
if &1 == &2 { unreachable!() } else {
38+
// ok
39+
}
40+
//~^^^^^^ single_match_else
41+
if &1 == &2 { unreachable!() } else {
42+
// ok
43+
}
44+
//~^^^^^^ single_match_else
45+
if 1 == 2 { unreachable!() } else {
46+
// ok
47+
}
48+
//~^^^^^^ single_match_else
49+
if 1 == 2 { unreachable!() } else {
50+
// ok
51+
}
52+
//~^^^^^^ single_match_else
53+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#![feature(deref_patterns)]
2+
#![allow(
3+
incomplete_features,
4+
clippy::eq_op,
5+
clippy::op_ref,
6+
clippy::deref_addrof,
7+
clippy::borrow_deref_ref,
8+
clippy::needless_if
9+
)]
10+
#![deny(clippy::single_match_else)]
11+
12+
fn string() {
13+
match *"" {
14+
//~^ single_match
15+
"" => {},
16+
_ => {},
17+
}
18+
19+
match *&*&*&*"" {
20+
//~^ single_match
21+
"" => {},
22+
_ => {},
23+
}
24+
25+
match ***&&"" {
26+
//~^ single_match
27+
"" => {},
28+
_ => {},
29+
}
30+
31+
match *&*&*"" {
32+
//~^ single_match
33+
"" => {},
34+
_ => {},
35+
}
36+
37+
match **&&*"" {
38+
//~^ single_match
39+
"" => {},
40+
_ => {},
41+
}
42+
}
43+
44+
fn int() {
45+
match &&&1 {
46+
&&&2 => unreachable!(),
47+
_ => {
48+
// ok
49+
},
50+
}
51+
//~^^^^^^ single_match_else
52+
match &&&1 {
53+
&&2 => unreachable!(),
54+
_ => {
55+
// ok
56+
},
57+
}
58+
//~^^^^^^ single_match_else
59+
match &&1 {
60+
&&2 => unreachable!(),
61+
_ => {
62+
// ok
63+
},
64+
}
65+
//~^^^^^^ single_match_else
66+
match &&&1 {
67+
&2 => unreachable!(),
68+
_ => {
69+
// ok
70+
},
71+
}
72+
//~^^^^^^ single_match_else
73+
match &&1 {
74+
&2 => unreachable!(),
75+
_ => {
76+
// ok
77+
},
78+
}
79+
//~^^^^^^ single_match_else
80+
match &&&1 {
81+
2 => unreachable!(),
82+
_ => {
83+
// ok
84+
},
85+
}
86+
//~^^^^^^ single_match_else
87+
match &&1 {
88+
2 => unreachable!(),
89+
_ => {
90+
// ok
91+
},
92+
}
93+
//~^^^^^^ single_match_else
94+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
2+
--> tests/ui/single_match_else_deref_patterns.rs:13:5
3+
|
4+
LL | / match *"" {
5+
LL | |
6+
LL | | "" => {},
7+
LL | | _ => {},
8+
LL | | }
9+
| |_____^ help: try: `if *"" == *"" {}`
10+
|
11+
= note: you might want to preserve the comments from inside the `match`
12+
= note: `-D clippy::single-match` implied by `-D warnings`
13+
= help: to override `-D warnings` add `#[allow(clippy::single_match)]`
14+
15+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
16+
--> tests/ui/single_match_else_deref_patterns.rs:19:5
17+
|
18+
LL | / match *&*&*&*"" {
19+
LL | |
20+
LL | | "" => {},
21+
LL | | _ => {},
22+
LL | | }
23+
| |_____^ help: try: `if *&*&*&*"" == *"" {}`
24+
|
25+
= note: you might want to preserve the comments from inside the `match`
26+
27+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
28+
--> tests/ui/single_match_else_deref_patterns.rs:25:5
29+
|
30+
LL | / match ***&&"" {
31+
LL | |
32+
LL | | "" => {},
33+
LL | | _ => {},
34+
LL | | }
35+
| |_____^ help: try: `if ***&&"" == *"" {}`
36+
|
37+
= note: you might want to preserve the comments from inside the `match`
38+
39+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
40+
--> tests/ui/single_match_else_deref_patterns.rs:31:5
41+
|
42+
LL | / match *&*&*"" {
43+
LL | |
44+
LL | | "" => {},
45+
LL | | _ => {},
46+
LL | | }
47+
| |_____^ help: try: `if *&*&*"" == *"" {}`
48+
|
49+
= note: you might want to preserve the comments from inside the `match`
50+
51+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
52+
--> tests/ui/single_match_else_deref_patterns.rs:37:5
53+
|
54+
LL | / match **&&*"" {
55+
LL | |
56+
LL | | "" => {},
57+
LL | | _ => {},
58+
LL | | }
59+
| |_____^ help: try: `if **&&*"" == *"" {}`
60+
|
61+
= note: you might want to preserve the comments from inside the `match`
62+
63+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
64+
--> tests/ui/single_match_else_deref_patterns.rs:45:5
65+
|
66+
LL | / match &&&1 {
67+
LL | | &&&2 => unreachable!(),
68+
LL | | _ => {
69+
... |
70+
LL | | }
71+
| |_____^
72+
|
73+
note: the lint level is defined here
74+
--> tests/ui/single_match_else_deref_patterns.rs:10:9
75+
|
76+
LL | #![deny(clippy::single_match_else)]
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
78+
help: try
79+
|
80+
LL ~ if &&&1 == &&&2 { unreachable!() } else {
81+
LL + // ok
82+
LL + }
83+
|
84+
85+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
86+
--> tests/ui/single_match_else_deref_patterns.rs:52:5
87+
|
88+
LL | / match &&&1 {
89+
LL | | &&2 => unreachable!(),
90+
LL | | _ => {
91+
... |
92+
LL | | }
93+
| |_____^
94+
|
95+
help: try
96+
|
97+
LL ~ if &&1 == &&2 { unreachable!() } else {
98+
LL + // ok
99+
LL + }
100+
|
101+
102+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
103+
--> tests/ui/single_match_else_deref_patterns.rs:59:5
104+
|
105+
LL | / match &&1 {
106+
LL | | &&2 => unreachable!(),
107+
LL | | _ => {
108+
... |
109+
LL | | }
110+
| |_____^
111+
|
112+
help: try
113+
|
114+
LL ~ if &&1 == &&2 { unreachable!() } else {
115+
LL + // ok
116+
LL + }
117+
|
118+
119+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
120+
--> tests/ui/single_match_else_deref_patterns.rs:66:5
121+
|
122+
LL | / match &&&1 {
123+
LL | | &2 => unreachable!(),
124+
LL | | _ => {
125+
... |
126+
LL | | }
127+
| |_____^
128+
|
129+
help: try
130+
|
131+
LL ~ if &1 == &2 { unreachable!() } else {
132+
LL + // ok
133+
LL + }
134+
|
135+
136+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
137+
--> tests/ui/single_match_else_deref_patterns.rs:73:5
138+
|
139+
LL | / match &&1 {
140+
LL | | &2 => unreachable!(),
141+
LL | | _ => {
142+
... |
143+
LL | | }
144+
| |_____^
145+
|
146+
help: try
147+
|
148+
LL ~ if &1 == &2 { unreachable!() } else {
149+
LL + // ok
150+
LL + }
151+
|
152+
153+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
154+
--> tests/ui/single_match_else_deref_patterns.rs:80:5
155+
|
156+
LL | / match &&&1 {
157+
LL | | 2 => unreachable!(),
158+
LL | | _ => {
159+
... |
160+
LL | | }
161+
| |_____^
162+
|
163+
help: try
164+
|
165+
LL ~ if 1 == 2 { unreachable!() } else {
166+
LL + // ok
167+
LL + }
168+
|
169+
170+
error: you seem to be trying to use `match` for an equality check. Consider using `if`
171+
--> tests/ui/single_match_else_deref_patterns.rs:87:5
172+
|
173+
LL | / match &&1 {
174+
LL | | 2 => unreachable!(),
175+
LL | | _ => {
176+
... |
177+
LL | | }
178+
| |_____^
179+
|
180+
help: try
181+
|
182+
LL ~ if 1 == 2 { unreachable!() } else {
183+
LL + // ok
184+
LL + }
185+
|
186+
187+
error: aborting due to 12 previous errors
188+

0 commit comments

Comments
 (0)