@@ -6,29 +6,10 @@ use rustc_data_structures::fx::FxHashSet;
66use rustc_hir as hir;
77use rustc_hir:: lang_items:: LangItem ;
88use 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 } ;
1010use rustc_span:: Span ;
1111use std:: ops:: ControlFlow ;
1212
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-
3213/// This method traverses the structure of `ty`, trying to find an
3314/// instance of an ADT (i.e. struct or enum) that doesn't implement
3415/// the structural-match traits, or a generic type parameter
@@ -54,15 +35,28 @@ pub enum NonStructuralMatchTyKind<'tcx> {
5435/// For more background on why Rust has this requirement, and issues
5536/// that arose when the requirement was not enforced completely, see
5637/// 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
5938pub fn search_for_structural_match_violation < ' tcx > (
6039 span : Span ,
6140 tcx : TyCtxt < ' tcx > ,
6241 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 } )
6660 . break_value ( )
6761}
6862
@@ -125,7 +119,10 @@ struct Search<'tcx> {
125119 /// we will not recur on them again.
126120 seen : FxHashSet < hir:: def_id:: DefId > ,
127121
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 ,
129126}
130127
131128impl < ' tcx > Search < ' tcx > {
@@ -135,59 +132,35 @@ impl<'tcx> Search<'tcx> {
135132}
136133
137134impl < ' tcx > TypeVisitor < ' tcx > for Search < ' tcx > {
138- type BreakTy = NonStructuralMatchTy < ' tcx > ;
135+ type BreakTy = Ty < ' tcx > ;
139136
140137 fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
141138 debug ! ( "Search visiting ty: {:?}" , ty) ;
142139
143140 let ( adt_def, substs) = match * ty. kind ( ) {
144141 ty:: Adt ( adt_def, substs) => ( adt_def, substs) ,
145142 ty:: Param ( _) => {
146- let kind = NonStructuralMatchTyKind :: Param ;
147- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
143+ return ControlFlow :: Break ( ty) ;
148144 }
149145 ty:: Dynamic ( ..) => {
150- let kind = NonStructuralMatchTyKind :: Dynamic ;
151- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
146+ return ControlFlow :: Break ( ty) ;
152147 }
153148 ty:: Foreign ( _) => {
154- let kind = NonStructuralMatchTyKind :: Foreign ;
155- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
149+ return ControlFlow :: Break ( ty) ;
156150 }
157151 ty:: Opaque ( ..) => {
158- let kind = NonStructuralMatchTyKind :: Opaque ;
159- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
152+ return ControlFlow :: Break ( ty) ;
160153 }
161154 ty:: Projection ( ..) => {
162- let kind = NonStructuralMatchTyKind :: Projection ;
163- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
155+ return ControlFlow :: Break ( ty) ;
164156 }
165157 ty:: Closure ( ..) => {
166- let kind = NonStructuralMatchTyKind :: Closure ;
167- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
158+ return ControlFlow :: Break ( ty) ;
168159 }
169160 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) ;
189162 }
190- ty:: FnDef ( ..) | ty :: FnPtr ( .. ) => {
163+ ty:: FnDef ( ..) => {
191164 // Types of formals and return in `fn(_) -> _` are also irrelevant;
192165 // so we do not recur into them via `super_visit_with`
193166 return ControlFlow :: CONTINUE ;
@@ -206,14 +179,41 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
206179 return ControlFlow :: CONTINUE ;
207180 }
208181
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+
209212 ty:: Float ( _) => {
210- if self . floats_allowed {
213+ if ! self . adt_const_param {
211214 return ControlFlow :: CONTINUE ;
212215 } else {
213- return ControlFlow :: Break ( NonStructuralMatchTy {
214- ty,
215- kind : NonStructuralMatchTyKind :: Float ,
216- } ) ;
216+ return ControlFlow :: Break ( ty) ;
217217 }
218218 }
219219
@@ -239,8 +239,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
239239
240240 if !self . type_marked_structural ( ty) {
241241 debug ! ( "Search found ty: {:?}" , ty) ;
242- let kind = NonStructuralMatchTyKind :: Adt ( adt_def) ;
243- return ControlFlow :: Break ( NonStructuralMatchTy { ty, kind } ) ;
242+ return ControlFlow :: Break ( ty) ;
244243 }
245244
246245 // structural-match does not care about the
0 commit comments