@@ -78,6 +78,7 @@ pub enum PathElem {
7878 TupleElem ( usize ) ,
7979 Deref ,
8080 Tag ,
81+ DynDowncast ,
8182}
8283
8384/// State for tracking recursive validation of references
@@ -97,75 +98,30 @@ impl<'tcx, Tag: Copy+Eq+Hash> RefTracking<'tcx, Tag> {
9798 }
9899}
99100
100- // Adding a Deref and making a copy of the path to be put into the queue
101- // always go together. This one does it with only new allocation.
102- fn path_clone_and_deref ( path : & Vec < PathElem > ) -> Vec < PathElem > {
103- let mut new_path = Vec :: with_capacity ( path. len ( ) +1 ) ;
104- new_path. clone_from ( path) ;
105- new_path. push ( PathElem :: Deref ) ;
106- new_path
107- }
108-
109101/// Format a path
110102fn path_format ( path : & Vec < PathElem > ) -> String {
111103 use self :: PathElem :: * ;
112104
113105 let mut out = String :: new ( ) ;
114106 for elem in path. iter ( ) {
115107 match elem {
116- Field ( name) => write ! ( out, ".{}" , name) . unwrap ( ) ,
117- ClosureVar ( name) => write ! ( out, ".<closure-var({})>" , name) . unwrap ( ) ,
118- TupleElem ( idx) => write ! ( out, ".{}" , idx) . unwrap ( ) ,
119- ArrayElem ( idx) => write ! ( out, "[{}]" , idx) . unwrap ( ) ,
108+ Field ( name) => write ! ( out, ".{}" , name) ,
109+ ClosureVar ( name) => write ! ( out, ".<closure-var({})>" , name) ,
110+ TupleElem ( idx) => write ! ( out, ".{}" , idx) ,
111+ ArrayElem ( idx) => write ! ( out, "[{}]" , idx) ,
120112 Deref =>
121113 // This does not match Rust syntax, but it is more readable for long paths -- and
122114 // some of the other items here also are not Rust syntax. Actually we can't
123115 // even use the usual syntax because we are just showing the projections,
124116 // not the root.
125- write ! ( out, ".<deref>" ) . unwrap ( ) ,
126- Tag => write ! ( out, ".<enum-tag>" ) . unwrap ( ) ,
127- }
117+ write ! ( out, ".<deref>" ) ,
118+ Tag => write ! ( out, ".<enum-tag>" ) ,
119+ DynDowncast => write ! ( out, ".<dyn-downcast>" ) ,
120+ } . unwrap ( )
128121 }
129122 out
130123}
131124
132- fn aggregate_field_path_elem < ' a , ' tcx > (
133- layout : TyLayout < ' tcx > ,
134- field : usize ,
135- tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
136- ) -> PathElem {
137- match layout. ty . sty {
138- // generators and closures.
139- ty:: Closure ( def_id, _) | ty:: Generator ( def_id, _, _) => {
140- if let Some ( upvar) = tcx. optimized_mir ( def_id) . upvar_decls . get ( field) {
141- PathElem :: ClosureVar ( upvar. debug_name )
142- } else {
143- // Sometimes the index is beyond the number of freevars (seen
144- // for a generator).
145- PathElem :: ClosureVar ( Symbol :: intern ( & field. to_string ( ) ) )
146- }
147- }
148-
149- // tuples
150- ty:: Tuple ( _) => PathElem :: TupleElem ( field) ,
151-
152- // enums
153- ty:: Adt ( def, ..) if def. is_enum ( ) => {
154- let variant = match layout. variants {
155- layout:: Variants :: Single { index } => & def. variants [ index] ,
156- _ => bug ! ( "aggregate_field_path_elem: got enum but not in a specific variant" ) ,
157- } ;
158- PathElem :: Field ( variant. fields [ field] . ident . name )
159- }
160-
161- // other ADTs
162- ty:: Adt ( def, _) => PathElem :: Field ( def. non_enum_variant ( ) . fields [ field] . ident . name ) ,
163-
164- // nothing else has an aggregate layout
165- _ => bug ! ( "aggregate_field_path_elem: got non-aggregate type {:?}" , layout. ty) ,
166- }
167- }
168-
169125fn scalar_format < Tag > ( value : ScalarMaybeUndef < Tag > ) -> String {
170126 match value {
171127 ScalarMaybeUndef :: Undef =>
@@ -177,28 +133,97 @@ fn scalar_format<Tag>(value: ScalarMaybeUndef<Tag>) -> String {
177133 }
178134}
179135
180- struct ValidityVisitor < ' rt , ' tcx , Tag > {
136+ struct ValidityVisitor < ' rt , ' a , ' tcx , Tag > {
181137 op : OpTy < ' tcx , Tag > ,
182138 /// The `path` may be pushed to, but the part that is present when a function
183139 /// starts must not be changed! `visit_fields` and `visit_array` rely on
184140 /// this stack discipline.
185141 path : Vec < PathElem > ,
186142 ref_tracking : Option < & ' rt mut RefTracking < ' tcx , Tag > > ,
187143 const_mode : bool ,
144+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
188145}
189146
190- impl < Tag : fmt:: Debug > fmt:: Debug for ValidityVisitor < ' _ , ' _ , Tag > {
147+ impl < Tag : fmt:: Debug > fmt:: Debug for ValidityVisitor < ' _ , ' _ , ' _ , Tag > {
191148 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
192- write ! ( f, "{:?} ({:?})" , * self . op, self . op. layout. ty)
149+ write ! ( f, "{:?}, {:?}" , * self . op, self . op. layout. ty)
150+ }
151+ }
152+
153+ impl < ' rt , ' a , ' tcx , Tag > ValidityVisitor < ' rt , ' a , ' tcx , Tag > {
154+ fn push_aggregate_field_path_elem (
155+ & mut self ,
156+ layout : TyLayout < ' tcx > ,
157+ field : usize ,
158+ ) {
159+ let elem = match layout. ty . sty {
160+ // generators and closures.
161+ ty:: Closure ( def_id, _) | ty:: Generator ( def_id, _, _) => {
162+ if let Some ( upvar) = self . tcx . optimized_mir ( def_id) . upvar_decls . get ( field) {
163+ PathElem :: ClosureVar ( upvar. debug_name )
164+ } else {
165+ // Sometimes the index is beyond the number of freevars (seen
166+ // for a generator).
167+ PathElem :: ClosureVar ( Symbol :: intern ( & field. to_string ( ) ) )
168+ }
169+ }
170+
171+ // tuples
172+ ty:: Tuple ( _) => PathElem :: TupleElem ( field) ,
173+
174+ // enums
175+ ty:: Adt ( def, ..) if def. is_enum ( ) => {
176+ let variant = match layout. variants {
177+ layout:: Variants :: Single { index } => & def. variants [ index] ,
178+ _ => bug ! ( "aggregate_field_path_elem: got enum but not in a specific variant" ) ,
179+ } ;
180+ PathElem :: Field ( variant. fields [ field] . ident . name )
181+ }
182+
183+ // other ADTs
184+ ty:: Adt ( def, _) => PathElem :: Field ( def. non_enum_variant ( ) . fields [ field] . ident . name ) ,
185+
186+ // arrays/slices
187+ ty:: Array ( ..) | ty:: Slice ( ..) => PathElem :: ArrayElem ( field) ,
188+
189+ // dyn traits
190+ ty:: Dynamic ( ..) => PathElem :: DynDowncast ,
191+
192+ // nothing else has an aggregate layout
193+ _ => bug ! ( "aggregate_field_path_elem: got non-aggregate type {:?}" , layout. ty) ,
194+ } ;
195+ self . path . push ( elem) ;
193196 }
194197}
195198
196199impl < ' rt , ' a , ' mir , ' tcx , M : Machine < ' a , ' mir , ' tcx > >
197- ValueVisitor < ' a , ' mir , ' tcx , M > for ValidityVisitor < ' rt , ' tcx , M :: PointerTag >
200+ ValueVisitor < ' a , ' mir , ' tcx , M > for ValidityVisitor < ' rt , ' a , ' tcx , M :: PointerTag >
198201{
202+ type V = OpTy < ' tcx , M :: PointerTag > ;
203+
199204 #[ inline( always) ]
200- fn layout ( & self ) -> TyLayout < ' tcx > {
201- self . op . layout
205+ fn value ( & self ) -> & OpTy < ' tcx , M :: PointerTag > {
206+ & self . op
207+ }
208+
209+ #[ inline]
210+ fn with_field (
211+ & mut self ,
212+ val : Self :: V ,
213+ field : usize ,
214+ f : impl FnOnce ( & mut Self ) -> EvalResult < ' tcx > ,
215+ ) -> EvalResult < ' tcx > {
216+ // Remember the old state
217+ let path_len = self . path . len ( ) ;
218+ let op = self . op ;
219+ // Perform operation
220+ self . push_aggregate_field_path_elem ( op. layout , field) ;
221+ self . op = val;
222+ f ( self ) ?;
223+ // Undo changes
224+ self . path . truncate ( path_len) ;
225+ self . op = op;
226+ Ok ( ( ) )
202227 }
203228
204229 fn downcast_enum ( & mut self , ectx : & EvalContext < ' a , ' mir , ' tcx , M > )
@@ -227,15 +252,6 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
227252 Ok ( ( ) )
228253 }
229254
230- fn downcast_dyn_trait ( & mut self , ectx : & EvalContext < ' a , ' mir , ' tcx , M > )
231- -> EvalResult < ' tcx >
232- {
233- // FIXME: Should we reflect this in `self.path`?
234- let dest = self . op . to_mem_place ( ) ; // immediate trait objects are not a thing
235- self . op = ectx. unpack_dyn_trait ( dest) ?. 1 . into ( ) ;
236- Ok ( ( ) )
237- }
238-
239255 fn visit_primitive ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
240256 -> EvalResult < ' tcx >
241257 {
@@ -365,7 +381,13 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
365381 let op = place. into ( ) ;
366382 if ref_tracking. seen . insert ( op) {
367383 trace ! ( "Recursing below ptr {:#?}" , * op) ;
368- ref_tracking. todo . push ( ( op, path_clone_and_deref ( & self . path ) ) ) ;
384+ // We need to clone the path anyway, make sure it gets created
385+ // with enough space for the additional `Deref`.
386+ let mut new_path = Vec :: with_capacity ( self . path . len ( ) +1 ) ;
387+ new_path. clone_from ( & self . path ) ;
388+ new_path. push ( PathElem :: Deref ) ;
389+ // Remember to come back to this later.
390+ ref_tracking. todo . push ( ( op, new_path) ) ;
369391 }
370392 }
371393 }
@@ -378,12 +400,17 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
378400 // FIXME: Check if the signature matches
379401 }
380402 // This should be all the primitive types
381- ty:: Never => bug ! ( "Uninhabited type should have been caught earlier" ) ,
382403 _ => bug ! ( "Unexpected primitive type {}" , value. layout. ty)
383404 }
384405 Ok ( ( ) )
385406 }
386407
408+ fn visit_uninhabited ( & mut self , _ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
409+ -> EvalResult < ' tcx >
410+ {
411+ validation_failure ! ( "a value of an uninhabited type" , self . path)
412+ }
413+
387414 fn visit_scalar ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > , layout : & layout:: Scalar )
388415 -> EvalResult < ' tcx >
389416 {
@@ -468,47 +495,16 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
468495 }
469496 }
470497
471- fn visit_fields ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > , num_fields : usize )
472- -> EvalResult < ' tcx >
473- {
474- // Remember some stuff that will change for the recursive calls
475- let op = self . op ;
476- let path_len = self . path . len ( ) ;
477- // Go look at all the fields
478- for i in 0 ..num_fields {
479- // Adapt our state
480- self . op = ectx. operand_field ( op, i as u64 ) ?;
481- self . path . push ( aggregate_field_path_elem ( op. layout , i, * ectx. tcx ) ) ;
482- // Recursive visit
483- ectx. visit_value ( self ) ?;
484- // Restore original state
485- self . op = op;
486- self . path . truncate ( path_len) ;
487- }
488- Ok ( ( ) )
489- }
490-
491- fn visit_str ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
492- -> EvalResult < ' tcx >
493- {
494- let mplace = self . op . to_mem_place ( ) ; // strings are never immediate
495- try_validation ! ( ectx. read_str( mplace) ,
496- "uninitialized or non-UTF-8 data in str" , self . path) ;
497- Ok ( ( ) )
498- }
499-
500- fn visit_array ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > ) -> EvalResult < ' tcx >
498+ fn handle_array ( & mut self , ectx : & EvalContext < ' a , ' mir , ' tcx , M > )
499+ -> EvalResult < ' tcx , bool >
501500 {
502- let mplace = if self . op . layout . is_zst ( ) {
503- // it's a ZST, the memory content cannot matter
504- MPlaceTy :: dangling ( self . op . layout , & ectx)
505- } else {
506- // non-ZST array/slice/str cannot be immediate
507- self . op . to_mem_place ( )
508- } ;
509- match self . op . layout . ty . sty {
510- ty:: Str => bug ! ( "Strings should be handled separately" ) ,
511- // Special handling for arrays/slices of builtin integer types
501+ Ok ( match self . op . layout . ty . sty {
502+ ty:: Str => {
503+ let mplace = self . op . to_mem_place ( ) ; // strings are never immediate
504+ try_validation ! ( ectx. read_str( mplace) ,
505+ "uninitialized or non-UTF-8 data in str" , self . path) ;
506+ true
507+ }
512508 ty:: Array ( tys, ..) | ty:: Slice ( tys) if {
513509 // This optimization applies only for integer and floating point types
514510 // (i.e., types that can hold arbitrary bytes).
@@ -517,8 +513,15 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
517513 _ => false ,
518514 }
519515 } => {
516+ let mplace = if self . op . layout . is_zst ( ) {
517+ // it's a ZST, the memory content cannot matter
518+ MPlaceTy :: dangling ( self . op . layout , ectx)
519+ } else {
520+ // non-ZST array/slice/str cannot be immediate
521+ self . op . to_mem_place ( )
522+ } ;
520523 // This is the length of the array/slice.
521- let len = mplace. len ( & ectx) ?;
524+ let len = mplace. len ( ectx) ?;
522525 // This is the element type size.
523526 let ty_size = ectx. layout_of ( tys) ?. size ;
524527 // This is the size in bytes of the whole array.
@@ -539,7 +542,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
539542 /*allow_ptr_and_undef*/ !self . const_mode ,
540543 ) {
541544 // In the happy case, we needn't check anything else.
542- Ok ( ( ) ) => { } ,
545+ Ok ( ( ) ) => true , // handled these arrays
543546 // Some error happened, try to provide a more detailed description.
544547 Err ( err) => {
545548 // For some errors we might be able to provide extra information
@@ -560,26 +563,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
560563 }
561564 }
562565 }
563- } ,
564- _ => {
565- // Remember some stuff that will change for the recursive calls
566- let op = self . op ;
567- let path_len = self . path . len ( ) ;
568- // This handles the unsized case correctly as well, as well as
569- // SIMD and all sorts of other array-like types.
570- for ( i, field) in ectx. mplace_array_fields ( mplace) ?. enumerate ( ) {
571- // Adapt our state
572- self . op = field?. into ( ) ;
573- self . path . push ( PathElem :: ArrayElem ( i) ) ;
574- // Recursive visit
575- ectx. visit_value ( self ) ?;
576- // Restore original state
577- self . op = op;
578- self . path . truncate ( path_len) ;
579- }
580566 }
581- }
582- Ok ( ( ) )
567+ _ => false , // not handled
568+ } )
583569 }
584570}
585571
@@ -605,7 +591,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
605591 op,
606592 path,
607593 ref_tracking,
608- const_mode
594+ const_mode,
595+ tcx : * self . tcx ,
609596 } ;
610597
611598 // Run it
0 commit comments