Skip to content

Commit e61b272

Browse files
committed
require StructuralPartialEq on generics
1 parent 037b621 commit e61b272

17 files changed

Lines changed: 138 additions & 92 deletions

compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub(crate) fn expand_deriving_partial_eq(
2222
path: path_std!(marker::StructuralPartialEq),
2323
skip_path_as_bound: true, // crucial!
2424
needs_copy_as_bound_if_packed: false,
25-
additional_bounds: Vec::new(),
25+
additional_bounds: vec![Ty::Path(path_std!(marker::StructuralPartialEq))],
2626
// We really don't support unions, but that's already checked by the impl generated below;
2727
// a second check here would lead to redundant error messages.
2828
supports_unions: true,

tests/ui/consts/const_in_pattern/issue-65466.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const C: &[O<B>] = &[O::None];
1111
fn main() {
1212
let x = O::None;
1313
match &[x][..] {
14-
C => (), //~ ERROR constant of non-structural type `&[O<B>]` in a pattern
14+
C => (), //~ ERROR constant of non-structural type `O<B>` in a pattern
1515
_ => (),
1616
}
1717
}
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
error: constant of non-structural type `&[O<B>]` in a pattern
1+
error: constant of non-structural type `O<B>` in a pattern
22
--> $DIR/issue-65466.rs:14:9
33
|
4-
LL | struct B;
5-
| -------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
6-
LL |
4+
LL | enum O<T> {
5+
| --------- `O<B>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
6+
...
77
LL | const C: &[O<B>] = &[O::None];
88
| ---------------- constant defined here
99
...
1010
LL | C => (),
1111
| ^ constant of non-structural type
1212
|
13-
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
13+
help: if `O<B>` manually implemented `PartialEq`, you could add a condition to the match arm checking for equality
14+
|
15+
LL - C => (),
16+
LL + binding if binding == C => (),
17+
|
1418

1519
error: aborting due to 1 previous error
1620

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Regression test for https://github.com/rust-lang/rust/issues/147714.
2+
3+
#[allow(dead_code)]
4+
#[derive(PartialEq)]
5+
enum Thing<T> {
6+
A(T),
7+
B,
8+
}
9+
10+
struct Incomparable;
11+
12+
impl PartialEq for Thing<Incomparable> {
13+
fn eq(&self, _: &Self) -> bool {
14+
panic!()
15+
}
16+
}
17+
18+
const X: Thing<Incomparable> = Thing::B;
19+
20+
fn main() {
21+
if let X = X { //~ ERROR constant of non-structural type `Thing<Incomparable>` in a pattern
22+
println!("equal");
23+
}
24+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: constant of non-structural type `Thing<Incomparable>` in a pattern
2+
--> $DIR/issue-147714.rs:21:12
3+
|
4+
LL | enum Thing<T> {
5+
| ------------- `Thing<Incomparable>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
6+
...
7+
LL | const X: Thing<Incomparable> = Thing::B;
8+
| ---------------------------- constant defined here
9+
...
10+
LL | if let X = X {
11+
| ^ constant of non-structural type
12+
|
13+
help: if `Thing<Incomparable>` manually implemented `PartialEq`, you could check for equality instead of pattern matching
14+
|
15+
LL - if let X = X {
16+
LL + if X == X {
17+
|
18+
19+
error: aborting due to 1 previous error
20+

tests/ui/consts/const_in_pattern/reject_non_structural.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ struct NoPartialEq;
1717

1818
#[derive(Copy, Clone, Debug)]
1919
struct NoDerive;
20-
//~^ NOTE must be annotated with `#[derive(PartialEq)]`
21-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
22-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
23-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
24-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
25-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
26-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
27-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
28-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
29-
//~| NOTE must be annotated with `#[derive(PartialEq)]`
20+
//~^ NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
21+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
22+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
23+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
24+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
25+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
26+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
27+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
28+
//~| NOTE `NoDerive` must be annotated with `#[derive(PartialEq)]`
3029

3130
// This impl makes `NoDerive` irreflexive.
3231
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
@@ -39,7 +38,6 @@ impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
3938
//~| NOTE StructuralPartialEq.html for details
4039
//~| NOTE StructuralPartialEq.html for details
4140
//~| NOTE StructuralPartialEq.html for details
42-
//~| NOTE StructuralPartialEq.html for details
4341

4442
impl Eq for NoDerive { }
4543

@@ -55,10 +53,11 @@ impl Eq for TrivialEq { }
5553
fn main() {
5654
#[derive(PartialEq, Eq, Debug)]
5755
enum Derive<X> { Some(X), None, }
56+
//~^ NOTE `Derive<NoDerive>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
5857

5958
const ENUM: Derive<NoDerive> = Derive::Some(NoDerive); //~ NOTE constant defined here
6059
match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
61-
//~^ ERROR constant of non-structural type `NoDerive` in a pattern
60+
//~^ ERROR constant of non-structural type `Derive<NoDerive>` in a pattern
6261
//~| NOTE constant of non-structural type
6362

6463
const FIELD: OND = TrivialEq(Some(NoDerive)).0; //~ NOTE constant defined here

tests/ui/consts/const_in_pattern/reject_non_structural.stderr

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
1-
error: constant of non-structural type `NoDerive` in a pattern
2-
--> $DIR/reject_non_structural.rs:60:36
1+
error: constant of non-structural type `Derive<NoDerive>` in a pattern
2+
--> $DIR/reject_non_structural.rs:59:36
33
|
4-
LL | struct NoDerive;
5-
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
4+
LL | enum Derive<X> { Some(X), None, }
5+
| -------------- `Derive<NoDerive>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
66
...
77
LL | const ENUM: Derive<NoDerive> = Derive::Some(NoDerive);
88
| ---------------------------- constant defined here
99
LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
1010
| ^^^^ constant of non-structural type
1111
|
12-
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
13-
--> $DIR/reject_non_structural.rs:32:1
14-
|
15-
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
16-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
17-
help: add a condition to the match arm checking for equality
12+
help: if `Derive<NoDerive>` manually implemented `PartialEq`, you could add a condition to the match arm checking for equality
1813
|
1914
LL - match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
2015
LL + match Derive::Some(NoDerive) { binding if binding == ENUM => dbg!(ENUM), _ => panic!("whoops"), };
2116
|
2217

2318
error: constant of non-structural type `NoDerive` in a pattern
24-
--> $DIR/reject_non_structural.rs:65:28
19+
--> $DIR/reject_non_structural.rs:64:28
2520
|
2621
LL | struct NoDerive;
2722
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -32,7 +27,7 @@ LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
3227
| ^^^^^ constant of non-structural type
3328
|
3429
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
35-
--> $DIR/reject_non_structural.rs:32:1
30+
--> $DIR/reject_non_structural.rs:31:1
3631
|
3732
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
3833
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +38,7 @@ LL + match Some(NoDerive) { binding if binding == FIELD => dbg!(FIELD), _ =>
4338
|
4439

4540
error: constant of non-structural type `NoDerive` in a pattern
46-
--> $DIR/reject_non_structural.rs:71:27
41+
--> $DIR/reject_non_structural.rs:70:27
4742
|
4843
LL | struct NoDerive;
4944
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -54,7 +49,7 @@ LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops")
5449
| ^^^^^^^^ constant of non-structural type
5550
|
5651
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
57-
--> $DIR/reject_non_structural.rs:32:1
52+
--> $DIR/reject_non_structural.rs:31:1
5853
|
5954
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
6055
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -65,7 +60,7 @@ LL + match Some(NoDerive) {binding if binding == INDIRECT => dbg!(INDIRECT),
6560
|
6661

6762
error: constant of non-structural type `NoDerive` in a pattern
68-
--> $DIR/reject_non_structural.rs:76:36
63+
--> $DIR/reject_non_structural.rs:75:36
6964
|
7065
LL | struct NoDerive;
7166
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -76,7 +71,7 @@ LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoop
7671
| ^^^^^ constant of non-structural type
7772
|
7873
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
79-
--> $DIR/reject_non_structural.rs:32:1
74+
--> $DIR/reject_non_structural.rs:31:1
8075
|
8176
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
8277
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +82,7 @@ LL + match (None, Some(NoDerive)) { binding if binding == TUPLE => dbg!(TUPL
8782
|
8883

8984
error: constant of non-structural type `NoDerive` in a pattern
90-
--> $DIR/reject_non_structural.rs:81:28
85+
--> $DIR/reject_non_structural.rs:80:28
9186
|
9287
LL | struct NoDerive;
9388
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -98,7 +93,7 @@ LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => p
9893
| ^^^^^^^^^^^^^^^ constant of non-structural type
9994
|
10095
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
101-
--> $DIR/reject_non_structural.rs:32:1
96+
--> $DIR/reject_non_structural.rs:31:1
10297
|
10398
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
10499
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -109,7 +104,7 @@ LL + match Some(NoDerive) { binding if binding == TYPE_ASCRIPTION => dbg!(TY
109104
|
110105

111106
error: constant of non-structural type `NoDerive` in a pattern
112-
--> $DIR/reject_non_structural.rs:86:36
107+
--> $DIR/reject_non_structural.rs:85:36
113108
|
114109
LL | struct NoDerive;
115110
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -120,7 +115,7 @@ LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoop
120115
| ^^^^^ constant of non-structural type
121116
|
122117
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
123-
--> $DIR/reject_non_structural.rs:32:1
118+
--> $DIR/reject_non_structural.rs:31:1
124119
|
125120
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
126121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -131,7 +126,7 @@ LL + match [None, Some(NoDerive)] { binding if binding == ARRAY => dbg!(ARRA
131126
|
132127

133128
error: constant of non-structural type `NoDerive` in a pattern
134-
--> $DIR/reject_non_structural.rs:91:33
129+
--> $DIR/reject_non_structural.rs:90:33
135130
|
136131
LL | struct NoDerive;
137132
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -142,7 +137,7 @@ LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops
142137
| ^^^^^^ constant of non-structural type
143138
|
144139
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
145-
--> $DIR/reject_non_structural.rs:32:1
140+
--> $DIR/reject_non_structural.rs:31:1
146141
|
147142
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
148143
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -153,7 +148,7 @@ LL + match [Some(NoDerive); 2] { binding if binding == REPEAT => dbg!(REPEAT
153148
|
154149

155150
error: constant of non-structural type `NoDerive` in a pattern
156-
--> $DIR/reject_non_structural.rs:97:28
151+
--> $DIR/reject_non_structural.rs:96:28
157152
|
158153
LL | struct NoDerive;
159154
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -165,7 +160,7 @@ LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => p
165160
| ^^^^^^^^^^^^^^^ constant of non-structural type
166161
|
167162
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
168-
--> $DIR/reject_non_structural.rs:32:1
163+
--> $DIR/reject_non_structural.rs:31:1
169164
|
170165
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
171166
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -176,7 +171,7 @@ LL + match Some(NoDerive) { binding if binding == NoDerive::ASSOC => dbg!(No
176171
|
177172

178173
error: constant of non-structural type `NoDerive` in a pattern
179-
--> $DIR/reject_non_structural.rs:102:28
174+
--> $DIR/reject_non_structural.rs:101:28
180175
|
181176
LL | struct NoDerive;
182177
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -187,7 +182,7 @@ LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
187182
| ^^^^^ constant of non-structural type
188183
|
189184
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
190-
--> $DIR/reject_non_structural.rs:32:1
185+
--> $DIR/reject_non_structural.rs:31:1
191186
|
192187
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
193188
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +193,7 @@ LL + match Some(NoDerive) { binding if binding == BLOCK => dbg!(BLOCK), _ =>
198193
|
199194

200195
error: constant of non-structural type `NoDerive` in a pattern
201-
--> $DIR/reject_non_structural.rs:107:29
196+
--> $DIR/reject_non_structural.rs:106:29
202197
|
203198
LL | struct NoDerive;
204199
| --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -209,7 +204,7 @@ LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops")
209204
| ^^^^^^^ constant of non-structural type
210205
|
211206
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
212-
--> $DIR/reject_non_structural.rs:32:1
207+
--> $DIR/reject_non_structural.rs:31:1
213208
|
214209
LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
215210
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/ui/derives/deriving-all-codegen.stdout

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,11 @@ impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash
836836
}
837837
}
838838
#[automatically_derived]
839-
impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { }
839+
impl<T: ::core::marker::StructuralPartialEq + Trait,
840+
U: ::core::marker::StructuralPartialEq>
841+
::core::marker::StructuralPartialEq for Generic<T, U> where
842+
T::A: ::core::marker::StructuralPartialEq {
843+
}
840844
#[automatically_derived]
841845
impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
842846
::core::cmp::PartialEq for Generic<T, U> where
@@ -953,8 +957,10 @@ impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait,
953957
}
954958
}
955959
#[automatically_derived]
956-
impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U>
957-
{
960+
impl<T: ::core::marker::StructuralPartialEq + Trait,
961+
U: ::core::marker::StructuralPartialEq>
962+
::core::marker::StructuralPartialEq for PackedGeneric<T, U> where
963+
T::A: ::core::marker::StructuralPartialEq {
958964
}
959965
#[automatically_derived]
960966
impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
@@ -1678,7 +1684,10 @@ impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for
16781684
}
16791685
}
16801686
#[automatically_derived]
1681-
impl<T, U> ::core::marker::StructuralPartialEq for EnumGeneric<T, U> { }
1687+
impl<T: ::core::marker::StructuralPartialEq,
1688+
U: ::core::marker::StructuralPartialEq>
1689+
::core::marker::StructuralPartialEq for EnumGeneric<T, U> {
1690+
}
16821691
#[automatically_derived]
16831692
impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
16841693
::core::cmp::PartialEq for EnumGeneric<T, U> {
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
error: constant of non-structural type `EnumSet<Enum8>` in a pattern
22
--> $DIR/issue-72896-non-partial-eq-const.rs:19:9
33
|
4-
LL | enum Enum8 { }
5-
| ---------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
4+
LL | struct EnumSet<T: EnumSetType> {
5+
| ------------------------------ `EnumSet<Enum8>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
66
...
77
LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
88
| ------------------------------- constant defined here
99
...
1010
LL | CONST_SET => { /* ok */ }
1111
| ^^^^^^^^^ constant of non-structural type
1212
|
13-
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
13+
help: if `EnumSet<Enum8>` manually implemented `PartialEq`, you could add a condition to the match arm checking for equality
14+
|
15+
LL - CONST_SET => { /* ok */ }
16+
LL + binding if binding == CONST_SET => { /* ok */ }
17+
|
1418

1519
error: aborting due to 1 previous error
1620

tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const WRAP_DIRECT_PARAM: WrapParam<NoDerive> = WrapParam(NoDerive(0));
1919
fn main() {
2020
match WRAP_DIRECT_PARAM {
2121
WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
22-
//~^ ERROR constant of non-structural type `NoDerive` in a pattern
22+
//~^ ERROR constant of non-structural type `WrapParam<NoDerive>` in a pattern
2323
_ => { println!("WRAP_DIRECT_PARAM did not match itself"); }
2424
}
2525
}

0 commit comments

Comments
 (0)