@@ -47,9 +47,9 @@ use super::UnsupportedOpInfo::*;
4747macro_rules! err_validation_failure {
4848 ( $where: expr, $msg: expr ) => { {
4949 let where_ = & $where;
50- let path = if !where_. is_empty( ) {
50+ let path = if !where_. projs . is_empty( ) {
5151 let mut path = String :: new( ) ;
52- write_path( & mut path, where_) ;
52+ write_path( & mut path, & where_. projs ) ;
5353 Some ( path)
5454 } else {
5555 None
@@ -59,6 +59,7 @@ macro_rules! err_validation_failure {
5959 use ValidationErrorKind :: * ;
6060 let msg = ValidationErrorKind :: from( $msg) ;
6161 err_ub!( ValidationError {
62+ orig_ty: where_. orig_ty,
6263 path,
6364 ptr_bytes_warning: msg. ptr_bytes_warning( ) ,
6465 msg: msg. to_string( ) ,
@@ -234,7 +235,7 @@ fn fmt_range(r: WrappingRange, max_hi: u128) -> String {
234235/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
235236/// need to later print something for the user.
236237#[ derive( Copy , Clone , Debug ) ]
237- pub enum PathElem {
238+ pub enum PathElem < ' tcx > {
238239 Field ( Symbol ) ,
239240 Variant ( Symbol ) ,
240241 CoroutineState ( VariantIdx ) ,
@@ -244,10 +245,22 @@ pub enum PathElem {
244245 Deref ,
245246 EnumTag ,
246247 CoroutineTag ,
247- DynDowncast ,
248+ DynDowncast ( Ty < ' tcx > ) ,
248249 Vtable ,
249250}
250251
252+ #[ derive( Clone , Debug ) ]
253+ pub struct Path < ' tcx > {
254+ orig_ty : Ty < ' tcx > ,
255+ projs : Vec < PathElem < ' tcx > > ,
256+ }
257+
258+ impl < ' tcx > Path < ' tcx > {
259+ fn new ( ty : Ty < ' tcx > ) -> Self {
260+ Self { orig_ty : ty, projs : vec ! [ ] }
261+ }
262+ }
263+
251264/// Extra things to check for during validation of CTFE results.
252265#[ derive( Copy , Clone ) ]
253266pub enum CtfeValidationMode {
@@ -280,16 +293,10 @@ pub struct RefTracking<T, PATH = ()> {
280293 todo : Vec < ( T , PATH ) > ,
281294}
282295
283- impl < T : Clone + Eq + Hash + std:: fmt:: Debug , PATH : Default > RefTracking < T , PATH > {
296+ impl < T : Clone + Eq + Hash + std:: fmt:: Debug , PATH > RefTracking < T , PATH > {
284297 pub fn empty ( ) -> Self {
285298 RefTracking { seen : FxHashSet :: default ( ) , todo : vec ! [ ] }
286299 }
287- pub fn new ( val : T ) -> Self {
288- let mut ref_tracking_for_consts =
289- RefTracking { seen : FxHashSet :: default ( ) , todo : vec ! [ ( val. clone( ) , PATH :: default ( ) ) ] } ;
290- ref_tracking_for_consts. seen . insert ( val) ;
291- ref_tracking_for_consts
292- }
293300 pub fn next ( & mut self ) -> Option < ( T , PATH ) > {
294301 self . todo . pop ( )
295302 }
@@ -304,8 +311,17 @@ impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH>
304311 }
305312}
306313
314+ impl < ' tcx , T : Clone + Eq + Hash + std:: fmt:: Debug > RefTracking < T , Path < ' tcx > > {
315+ pub fn new ( val : T , ty : Ty < ' tcx > ) -> Self {
316+ let mut ref_tracking_for_consts =
317+ RefTracking { seen : FxHashSet :: default ( ) , todo : vec ! [ ( val. clone( ) , Path :: new( ty) ) ] } ;
318+ ref_tracking_for_consts. seen . insert ( val) ;
319+ ref_tracking_for_consts
320+ }
321+ }
322+
307323/// Format a path
308- fn write_path ( out : & mut String , path : & [ PathElem ] ) {
324+ fn write_path ( out : & mut String , path : & [ PathElem < ' _ > ] ) {
309325 use self :: PathElem :: * ;
310326
311327 for elem in path. iter ( ) {
@@ -323,7 +339,7 @@ fn write_path(out: &mut String, path: &[PathElem]) {
323339 // even use the usual syntax because we are just showing the projections,
324340 // not the root.
325341 Deref => write ! ( out, ".<deref>" ) ,
326- DynDowncast => write ! ( out, ".<dyn-downcast>" ) ,
342+ DynDowncast ( ty ) => write ! ( out, ".<dyn-downcast({ty}) >" ) ,
327343 Vtable => write ! ( out, ".<vtable>" ) ,
328344 }
329345 . unwrap ( )
@@ -382,10 +398,9 @@ impl RangeSet {
382398
383399struct ValidityVisitor < ' rt , ' tcx , M : Machine < ' tcx > > {
384400 /// The `path` may be pushed to, but the part that is present when a function
385- /// starts must not be changed! `visit_fields` and `visit_array` rely on
386- /// this stack discipline.
387- path : Vec < PathElem > ,
388- ref_tracking : Option < & ' rt mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Vec < PathElem > > > ,
401+ /// starts must not be changed! `with_elem` relies on this stack discipline.
402+ path : Path < ' tcx > ,
403+ ref_tracking : Option < & ' rt mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Path < ' tcx > > > ,
389404 /// `None` indicates this is not validating for CTFE (but for runtime).
390405 ctfe_mode : Option < CtfeValidationMode > ,
391406 ecx : & ' rt mut InterpCx < ' tcx , M > ,
@@ -404,7 +419,12 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
404419}
405420
406421impl < ' rt , ' tcx , M : Machine < ' tcx > > ValidityVisitor < ' rt , ' tcx , M > {
407- fn aggregate_field_path_elem ( & mut self , layout : TyAndLayout < ' tcx > , field : usize ) -> PathElem {
422+ fn aggregate_field_path_elem (
423+ & mut self ,
424+ layout : TyAndLayout < ' tcx > ,
425+ field : usize ,
426+ field_ty : Ty < ' tcx > ,
427+ ) -> PathElem < ' tcx > {
408428 // First, check if we are projecting to a variant.
409429 match layout. variants {
410430 Variants :: Multiple { tag_field, .. } => {
@@ -474,7 +494,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
474494 // dyn traits
475495 ty:: Dynamic ( ..) => {
476496 assert_eq ! ( field, 0 ) ;
477- PathElem :: DynDowncast
497+ PathElem :: DynDowncast ( field_ty )
478498 }
479499
480500 // nothing else has an aggregate layout
@@ -484,17 +504,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
484504
485505 fn with_elem < R > (
486506 & mut self ,
487- elem : PathElem ,
507+ elem : PathElem < ' tcx > ,
488508 f : impl FnOnce ( & mut Self ) -> InterpResult < ' tcx , R > ,
489509 ) -> InterpResult < ' tcx , R > {
490510 // Remember the old state
491- let path_len = self . path . len ( ) ;
511+ let path_len = self . path . projs . len ( ) ;
492512 // Record new element
493- self . path . push ( elem) ;
513+ self . path . projs . push ( elem) ;
494514 // Perform operation
495515 let r = f ( self ) ?;
496516 // Undo changes
497- self . path . truncate ( path_len) ;
517+ self . path . projs . truncate ( path_len) ;
498518 // Done
499519 interp_ok ( r)
500520 }
@@ -796,10 +816,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
796816 ref_tracking. track ( place, || {
797817 // We need to clone the path anyway, make sure it gets created
798818 // with enough space for the additional `Deref`.
799- let mut new_path = Vec :: with_capacity ( path. len ( ) + 1 ) ;
800- new_path . extend ( path) ;
801- new_path . push ( PathElem :: Deref ) ;
802- new_path
819+ let mut new_projs = Vec :: with_capacity ( path. projs . len ( ) + 1 ) ;
820+ new_projs . extend ( & path. projs ) ;
821+ new_projs . push ( PathElem :: Deref ) ;
822+ Path { projs : new_projs , orig_ty : path . orig_ty }
803823 } ) ;
804824 }
805825 interp_ok ( ( ) )
@@ -1220,7 +1240,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12201240 field : usize ,
12211241 new_val : & PlaceTy < ' tcx , M :: Provenance > ,
12221242 ) -> InterpResult < ' tcx > {
1223- let elem = self . aggregate_field_path_elem ( old_val. layout , field) ;
1243+ let elem = self . aggregate_field_path_elem ( old_val. layout , field, new_val . layout . ty ) ;
12241244 self . with_elem ( elem, move |this| this. visit_value ( new_val) )
12251245 }
12261246
@@ -1385,7 +1405,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
13851405 access. bad . start . bytes ( ) / layout. size . bytes ( ) ,
13861406 )
13871407 . unwrap ( ) ;
1388- self . path . push ( PathElem :: ArrayElem ( i) ) ;
1408+ self . path . projs . push ( PathElem :: ArrayElem ( i) ) ;
13891409
13901410 if matches ! ( kind, Ub ( InvalidUninitBytes ( _) ) ) {
13911411 err_validation_failure ! ( self . path, Uninit { expected } )
@@ -1515,8 +1535,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
15151535 fn validate_operand_internal (
15161536 & mut self ,
15171537 val : & PlaceTy < ' tcx , M :: Provenance > ,
1518- path : Vec < PathElem > ,
1519- ref_tracking : Option < & mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Vec < PathElem > > > ,
1538+ path : Path < ' tcx > ,
1539+ ref_tracking : Option < & mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Path < ' tcx > > > ,
15201540 ctfe_mode : Option < CtfeValidationMode > ,
15211541 reset_provenance_and_padding : bool ,
15221542 ) -> InterpResult < ' tcx > {
@@ -1569,8 +1589,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
15691589 pub ( crate ) fn const_validate_operand (
15701590 & mut self ,
15711591 val : & PlaceTy < ' tcx , M :: Provenance > ,
1572- path : Vec < PathElem > ,
1573- ref_tracking : & mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Vec < PathElem > > ,
1592+ path : Path < ' tcx > ,
1593+ ref_tracking : & mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Path < ' tcx > > ,
15741594 ctfe_mode : CtfeValidationMode ,
15751595 ) -> InterpResult < ' tcx > {
15761596 self . validate_operand_internal (
@@ -1599,14 +1619,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
15991619 reset_provenance_and_padding,
16001620 ?val,
16011621 ) ;
1602-
16031622 // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
16041623 // still correct to not use `ctfe_mode`: that mode is for validation of the final constant
16051624 // value, it rules out things like `UnsafeCell` in awkward places.
16061625 if !recursive {
16071626 return self . validate_operand_internal (
16081627 val,
1609- vec ! [ ] ,
1628+ Path :: new ( val . layout . ty ) ,
16101629 None ,
16111630 None ,
16121631 reset_provenance_and_padding,
@@ -1616,7 +1635,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
16161635 let mut ref_tracking = RefTracking :: empty ( ) ;
16171636 self . validate_operand_internal (
16181637 val,
1619- vec ! [ ] ,
1638+ Path :: new ( val . layout . ty ) ,
16201639 Some ( & mut ref_tracking) ,
16211640 None ,
16221641 reset_provenance_and_padding,
0 commit comments