@@ -291,9 +291,10 @@ pub(super) struct TbError<'node> {
291291 pub conflicting_info : & ' node NodeDebugInfo ,
292292 // What kind of access caused this error (read, write, reborrow, deallocation)
293293 pub access_cause : AccessCause ,
294- /// Which tag the access that caused this error was made through, i.e.
294+ /// Which tag, if any, the access that caused this error was made through, i.e.
295295 /// which tag was used to read/write/deallocate.
296- pub accessed_info : & ' node NodeDebugInfo ,
296+ /// Not set on wildcard accesses.
297+ pub accessed_info : Option < & ' node NodeDebugInfo > ,
297298}
298299
299300impl TbError < ' _ > {
@@ -302,10 +303,20 @@ impl TbError<'_> {
302303 use TransitionError :: * ;
303304 let cause = self . access_cause ;
304305 let accessed = self . accessed_info ;
306+ let accessed_str =
307+ self . accessed_info . map ( |v| format ! ( "{v}" ) ) . unwrap_or_else ( || "<wildcard>" . into ( ) ) ;
305308 let conflicting = self . conflicting_info ;
306- let accessed_is_conflicting = accessed. tag == conflicting. tag ;
309+ // An access is considered conflicting if it happened through a
310+ // different tag than the one who caused UB.
311+ // When doing a wildcard access (where `accessed` is `None`) we
312+ // do not know which precise tag the accessed happened from,
313+ // however we can be certain that it did not come from the
314+ // conflicting tag.
315+ // This is because the wildcard data structure already removes
316+ // all tags through which an access would cause UB.
317+ let accessed_is_conflicting = accessed. map ( |a| a. tag ) == Some ( conflicting. tag ) ;
307318 let title = format ! (
308- "{cause} through {accessed } at {alloc_id:?}[{offset:#x}] is forbidden" ,
319+ "{cause} through {accessed_str } at {alloc_id:?}[{offset:#x}] is forbidden" ,
309320 alloc_id = self . alloc_id,
310321 offset = self . error_offset
311322 ) ;
@@ -316,7 +327,7 @@ impl TbError<'_> {
316327 let mut details = Vec :: new ( ) ;
317328 if !accessed_is_conflicting {
318329 details. push ( format ! (
319- "the accessed tag {accessed } is a child of the conflicting tag {conflicting}"
330+ "the accessed tag {accessed_str } is a child of the conflicting tag {conflicting}"
320331 ) ) ;
321332 }
322333 let access = cause. print_as_access ( /* is_foreign */ false ) ;
@@ -330,7 +341,7 @@ impl TbError<'_> {
330341 let access = cause. print_as_access ( /* is_foreign */ true ) ;
331342 let details = vec ! [
332343 format!(
333- "the accessed tag {accessed } is foreign to the {conflicting_tag_name} tag {conflicting} (i.e., it is not a child)"
344+ "the accessed tag {accessed_str } is foreign to the {conflicting_tag_name} tag {conflicting} (i.e., it is not a child)"
334345 ) ,
335346 format!(
336347 "this {access} would cause the {conflicting_tag_name} tag {conflicting} (currently {before_disabled}) to become Disabled"
@@ -343,16 +354,18 @@ impl TbError<'_> {
343354 let conflicting_tag_name = "strongly protected" ;
344355 let details = vec ! [
345356 format!(
346- "the allocation of the accessed tag {accessed } also contains the {conflicting_tag_name} tag {conflicting}"
357+ "the allocation of the accessed tag {accessed_str } also contains the {conflicting_tag_name} tag {conflicting}"
347358 ) ,
348359 format!( "the {conflicting_tag_name} tag {conflicting} disallows deallocations" ) ,
349360 ] ;
350361 ( title, details, conflicting_tag_name)
351362 }
352363 } ;
353364 let mut history = HistoryData :: default ( ) ;
354- if !accessed_is_conflicting {
355- history. extend ( self . accessed_info . history . forget ( ) , "accessed" , false ) ;
365+ if let Some ( accessed_info) = self . accessed_info
366+ && !accessed_is_conflicting
367+ {
368+ history. extend ( accessed_info. history . forget ( ) , "accessed" , false ) ;
356369 }
357370 history. extend (
358371 self . conflicting_info . history . extract_relevant ( self . error_offset , self . error_kind ) ,
@@ -363,6 +376,20 @@ impl TbError<'_> {
363376 }
364377}
365378
379+ /// Cannot access this allocation with wildcard provenance, as there are no
380+ /// valid exposed references for this access kind.
381+ pub fn no_valid_exposed_references_error < ' tcx > (
382+ alloc_id : AllocId ,
383+ offset : u64 ,
384+ access_cause : AccessCause ,
385+ ) -> InterpErrorKind < ' tcx > {
386+ let title =
387+ format ! ( "{access_cause} through <wildcard> at {alloc_id:?}[{offset:#x}] is forbidden" ) ;
388+ let details = vec ! [ format!( "there are no exposed tags which may perform this access here" ) ] ;
389+ let history = HistoryData :: default ( ) ;
390+ err_machine_stop ! ( TerminationInfo :: TreeBorrowsUb { title, details, history } )
391+ }
392+
366393type S = & ' static str ;
367394/// Pretty-printing details
368395///
@@ -623,10 +650,10 @@ impl DisplayRepr {
623650 } else {
624651 // We take this node
625652 let rperm = tree
626- . rperms
653+ . locations
627654 . iter_all ( )
628- . map ( move |( _offset, perms ) | {
629- let perm = perms. get ( idx) ;
655+ . map ( move |( _offset, loc ) | {
656+ let perm = loc . perms . get ( idx) ;
630657 perm. cloned ( )
631658 } )
632659 . collect :: < Vec < _ > > ( ) ;
@@ -788,7 +815,7 @@ impl<'tcx> Tree {
788815 show_unnamed : bool ,
789816 ) -> InterpResult < ' tcx > {
790817 let mut indenter = DisplayIndent :: new ( ) ;
791- let ranges = self . rperms . iter_all ( ) . map ( |( range, _perms ) | range) . collect :: < Vec < _ > > ( ) ;
818+ let ranges = self . locations . iter_all ( ) . map ( |( range, _loc ) | range) . collect :: < Vec < _ > > ( ) ;
792819 if let Some ( repr) = DisplayRepr :: from ( self , show_unnamed) {
793820 repr. print (
794821 & DEFAULT_FORMATTER ,
0 commit comments