@@ -291,9 +291,10 @@ pub(super) struct TbError<'node> {
291291pub conflicting_info : & ' node NodeDebugInfo ,
292292// What kind of access caused this error (read, write, reborrow, deallocation)
293293pub 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<'_> {
302303use TransitionError :: * ;
303304let cause = self . access_cause ;
304305let accessed = self . accessed_info ;
306+ let accessed_str =
307+ self . accessed_info . map ( |v| format ! ( "{v}" ) ) . unwrap_or_else ( || "<wildcard>" . into ( ) ) ;
305308let 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 ) ;
307318let 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<'_> {
316327let mut details = Vec :: new ( ) ;
317328if !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}
322333let access = cause. print_as_access ( /* is_foreign */ false ) ;
@@ -330,7 +341,7 @@ impl TbError<'_> {
330341let access = cause. print_as_access ( /* is_foreign */ true ) ;
331342let 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<'_> {
343354let conflicting_tag_name = "strongly protected" ;
344355let 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} ;
353364let 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 (
358371self . 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
625652let 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 {
788815show_unnamed : bool ,
789816) -> InterpResult < ' tcx > {
790817let 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 < _ > > ( ) ;
792819if let Some ( repr) = DisplayRepr :: from ( self , show_unnamed) {
793820 repr. print (
794821& DEFAULT_FORMATTER ,
0 commit comments