@@ -6,29 +6,10 @@ use rustc_data_structures::fx::FxHashSet;
6
6
use rustc_hir as hir;
7
7
use rustc_hir:: lang_items:: LangItem ;
8
8
use rustc_middle:: ty:: query:: Providers ;
9
- use rustc_middle:: ty:: { self , AdtDef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor } ;
9
+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor } ;
10
10
use rustc_span:: Span ;
11
11
use std:: ops:: ControlFlow ;
12
12
13
- #[ derive( Debug ) ]
14
- pub struct NonStructuralMatchTy < ' tcx > {
15
- pub ty : Ty < ' tcx > ,
16
- pub kind : NonStructuralMatchTyKind < ' tcx > ,
17
- }
18
-
19
- #[ derive( Debug ) ]
20
- pub enum NonStructuralMatchTyKind < ' tcx > {
21
- Adt ( AdtDef < ' tcx > ) ,
22
- Param ,
23
- Dynamic ,
24
- Foreign ,
25
- Opaque ,
26
- Closure ,
27
- Generator ,
28
- Projection ,
29
- Float ,
30
- }
31
-
32
13
/// This method traverses the structure of `ty`, trying to find an
33
14
/// instance of an ADT (i.e. struct or enum) that doesn't implement
34
15
/// the structural-match traits, or a generic type parameter
@@ -54,15 +35,28 @@ pub enum NonStructuralMatchTyKind<'tcx> {
54
35
/// For more background on why Rust has this requirement, and issues
55
36
/// that arose when the requirement was not enforced completely, see
56
37
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
57
- ///
58
- /// The floats_allowed flag is used to deny constants in floating point
59
38
pub fn search_for_structural_match_violation < ' tcx > (
60
39
span : Span ,
61
40
tcx : TyCtxt < ' tcx > ,
62
41
ty : Ty < ' tcx > ,
63
- floats_allowed : bool ,
64
- ) -> Option < NonStructuralMatchTy < ' tcx > > {
65
- ty. visit_with ( & mut Search { tcx, span, seen : FxHashSet :: default ( ) , floats_allowed } )
42
+ ) -> Option < Ty < ' tcx > > {
43
+ ty. visit_with ( & mut Search { tcx, span, seen : FxHashSet :: default ( ) , adt_const_param : false } )
44
+ . break_value ( )
45
+ }
46
+
47
+ /// This method traverses the structure of `ty`, trying to find any
48
+ /// types that are not allowed to be used in a const generic.
49
+ ///
50
+ /// This is either because the type does not implement `StructuralEq`
51
+ /// and `StructuralPartialEq`, or because the type is intentionally
52
+ /// not supported in const generics (such as floats and raw pointers,
53
+ /// which are allowed in match blocks).
54
+ pub fn search_for_adt_const_param_violation < ' tcx > (
55
+ span : Span ,
56
+ tcx : TyCtxt < ' tcx > ,
57
+ ty : Ty < ' tcx > ,
58
+ ) -> Option < Ty < ' tcx > > {
59
+ ty. visit_with ( & mut Search { tcx, span, seen : FxHashSet :: default ( ) , adt_const_param : true } )
66
60
. break_value ( )
67
61
}
68
62
@@ -125,7 +119,10 @@ struct Search<'tcx> {
125
119
/// we will not recur on them again.
126
120
seen : FxHashSet < hir:: def_id:: DefId > ,
127
121
128
- floats_allowed : bool ,
122
+ // Additionally deny things that have been allowed in patterns,
123
+ // but are not allowed in adt const params, such as floats and
124
+ // fn ptrs.
125
+ adt_const_param : bool ,
129
126
}
130
127
131
128
impl < ' tcx > Search < ' tcx > {
@@ -135,59 +132,35 @@ impl<'tcx> Search<'tcx> {
135
132
}
136
133
137
134
impl < ' tcx > TypeVisitor < ' tcx > for Search < ' tcx > {
138
- type BreakTy = NonStructuralMatchTy < ' tcx > ;
135
+ type BreakTy = Ty < ' tcx > ;
139
136
140
137
fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
141
138
debug ! ( "Search visiting ty: {:?}" , ty) ;
142
139
143
140
let ( adt_def, substs) = match * ty. kind ( ) {
144
141
ty:: Adt ( adt_def, substs) => ( adt_def, substs) ,
145
142
ty:: Param ( _) => {
146
- let kind = NonStructuralMatchTyKind :: Param ;
147
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
143
+ return ControlFlow :: Break ( ty) ;
148
144
}
149
145
ty:: Dynamic ( ..) => {
150
- let kind = NonStructuralMatchTyKind :: Dynamic ;
151
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
146
+ return ControlFlow :: Break ( ty) ;
152
147
}
153
148
ty:: Foreign ( _) => {
154
- let kind = NonStructuralMatchTyKind :: Foreign ;
155
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
149
+ return ControlFlow :: Break ( ty) ;
156
150
}
157
151
ty:: Opaque ( ..) => {
158
- let kind = NonStructuralMatchTyKind :: Opaque ;
159
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
152
+ return ControlFlow :: Break ( ty) ;
160
153
}
161
154
ty:: Projection ( ..) => {
162
- let kind = NonStructuralMatchTyKind :: Projection ;
163
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
155
+ return ControlFlow :: Break ( ty) ;
164
156
}
165
157
ty:: Closure ( ..) => {
166
- let kind = NonStructuralMatchTyKind :: Closure ;
167
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
158
+ return ControlFlow :: Break ( ty) ;
168
159
}
169
160
ty:: Generator ( ..) | ty:: GeneratorWitness ( ..) => {
170
- let kind = NonStructuralMatchTyKind :: Generator ;
171
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
172
- }
173
- ty:: RawPtr ( ..) => {
174
- // structural-match ignores substructure of
175
- // `*const _`/`*mut _`, so skip `super_visit_with`.
176
- //
177
- // For example, if you have:
178
- // ```
179
- // struct NonStructural;
180
- // #[derive(PartialEq, Eq)]
181
- // struct T(*const NonStructural);
182
- // const C: T = T(std::ptr::null());
183
- // ```
184
- //
185
- // Even though `NonStructural` does not implement `PartialEq`,
186
- // structural equality on `T` does not recur into the raw
187
- // pointer. Therefore, one can still use `C` in a pattern.
188
- return ControlFlow :: CONTINUE ;
161
+ return ControlFlow :: Break ( ty) ;
189
162
}
190
- ty:: FnDef ( ..) | ty :: FnPtr ( .. ) => {
163
+ ty:: FnDef ( ..) => {
191
164
// Types of formals and return in `fn(_) -> _` are also irrelevant;
192
165
// so we do not recur into them via `super_visit_with`
193
166
return ControlFlow :: CONTINUE ;
@@ -206,14 +179,41 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
206
179
return ControlFlow :: CONTINUE ;
207
180
}
208
181
182
+ ty:: FnPtr ( ..) => {
183
+ if !self . adt_const_param {
184
+ return ControlFlow :: CONTINUE ;
185
+ } else {
186
+ return ControlFlow :: Break ( ty) ;
187
+ }
188
+ }
189
+
190
+ ty:: RawPtr ( ..) => {
191
+ if !self . adt_const_param {
192
+ // structural-match ignores substructure of
193
+ // `*const _`/`*mut _`, so skip `super_visit_with`.
194
+ //
195
+ // For example, if you have:
196
+ // ```
197
+ // struct NonStructural;
198
+ // #[derive(PartialEq, Eq)]
199
+ // struct T(*const NonStructural);
200
+ // const C: T = T(std::ptr::null());
201
+ // ```
202
+ //
203
+ // Even though `NonStructural` does not implement `PartialEq`,
204
+ // structural equality on `T` does not recur into the raw
205
+ // pointer. Therefore, one can still use `C` in a pattern.
206
+ return ControlFlow :: CONTINUE ;
207
+ } else {
208
+ return ControlFlow :: Break ( ty) ;
209
+ }
210
+ }
211
+
209
212
ty:: Float ( _) => {
210
- if self . floats_allowed {
213
+ if ! self . adt_const_param {
211
214
return ControlFlow :: CONTINUE ;
212
215
} else {
213
- return ControlFlow :: Break ( NonStructuralMatchTy {
214
- ty,
215
- kind : NonStructuralMatchTyKind :: Float ,
216
- } ) ;
216
+ return ControlFlow :: Break ( ty) ;
217
217
}
218
218
}
219
219
@@ -239,8 +239,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
239
239
240
240
if !self . type_marked_structural ( ty) {
241
241
debug ! ( "Search found ty: {:?}" , ty) ;
242
- let kind = NonStructuralMatchTyKind :: Adt ( adt_def) ;
243
- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
242
+ return ControlFlow :: Break ( ty) ;
244
243
}
245
244
246
245
// structural-match does not care about the
0 commit comments