@@ -12,16 +12,46 @@ use crate::borrow_tracker::tree_borrows::{
12
12
use crate :: borrow_tracker:: { AccessKind , ProtectorKind } ;
13
13
use crate :: * ;
14
14
15
+ /// Cause of an access: either a real access or one
16
+ /// inserted by Tree Borrows due to a reborrow or a deallocation.
17
+ #[ derive( Clone , Copy , Debug ) ]
18
+ pub enum AccessCause {
19
+ Explicit ( AccessKind ) ,
20
+ Reborrow ,
21
+ Dealloc ,
22
+ }
23
+
24
+ impl fmt:: Display for AccessCause {
25
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
26
+ match self {
27
+ Self :: Explicit ( kind) => write ! ( f, "{kind}" ) ,
28
+ Self :: Reborrow => write ! ( f, "reborrow" ) ,
29
+ Self :: Dealloc => write ! ( f, "deallocation" ) ,
30
+ }
31
+ }
32
+ }
33
+
34
+ impl AccessCause {
35
+ fn print_as_access ( self , is_foreign : bool ) -> String {
36
+ let rel = if is_foreign { "foreign" } else { "child" } ;
37
+ match self {
38
+ Self :: Explicit ( kind) => format ! ( "{rel} {kind}" ) ,
39
+ Self :: Reborrow => format ! ( "reborrow (acting as a {rel} read access)" ) ,
40
+ Self :: Dealloc => format ! ( "deallocation (acting as a {rel} write access)" ) ,
41
+ }
42
+ }
43
+ }
44
+
15
45
/// Complete data for an event:
16
46
#[ derive( Clone , Debug ) ]
17
47
pub struct Event {
18
- /// Transformation of permissions that occured because of this event
48
+ /// Transformation of permissions that occured because of this event.
19
49
pub transition : PermTransition ,
20
- /// Kind of the access that triggered this event
21
- pub access_kind : AccessKind ,
22
- /// Relative position of the tag to the one used for the access
50
+ /// Kind of the access that triggered this event.
51
+ pub access_cause : AccessCause ,
52
+ /// Relative position of the tag to the one used for the access.
23
53
pub is_foreign : bool ,
24
- /// User-visible range of the access
54
+ /// User-visible range of the access.
25
55
pub access_range : AllocRange ,
26
56
/// The transition recorded by this event only occured on a subrange of
27
57
/// `access_range`: a single access on `access_range` triggers several events,
@@ -36,7 +66,7 @@ pub struct Event {
36
66
/// the `TbError`, which should satisfy
37
67
/// `event.transition_range.contains(error.error_offset)`.
38
68
pub transition_range : Range < u64 > ,
39
- /// Line of code that triggered this event
69
+ /// Line of code that triggered this event.
40
70
pub span : Span ,
41
71
}
42
72
@@ -83,17 +113,19 @@ impl HistoryData {
83
113
self . events . push ( ( Some ( created. 0 . data ( ) ) , msg_creation) ) ;
84
114
for & Event {
85
115
transition,
86
- access_kind,
87
116
is_foreign,
117
+ access_cause,
88
118
access_range,
89
119
span,
90
120
transition_range : _,
91
121
} in & events
92
122
{
93
123
// NOTE: `transition_range` is explicitly absent from the error message, it has no significance
94
124
// to the user. The meaningful one is `access_range`.
95
- self . events . push ( ( Some ( span. data ( ) ) , format ! ( "{this} later transitioned to {endpoint} due to a {rel} {access_kind} at offsets {access_range:?}" , endpoint = transition. endpoint( ) , rel = if is_foreign { "foreign" } else { "child" } ) ) ) ;
96
- self . events . push ( ( None , format ! ( "this corresponds to {}" , transition. summary( ) ) ) ) ;
125
+ let access = access_cause. print_as_access ( is_foreign) ;
126
+ self . events . push ( ( Some ( span. data ( ) ) , format ! ( "{this} later transitioned to {endpoint} due to a {access} at offsets {access_range:?}" , endpoint = transition. endpoint( ) ) ) ) ;
127
+ self . events
128
+ . push ( ( None , format ! ( "this transition corresponds to {}" , transition. summary( ) ) ) ) ;
97
129
}
98
130
}
99
131
}
@@ -238,9 +270,8 @@ pub(super) struct TbError<'node> {
238
270
/// On accesses rejected due to insufficient permissions, this is the
239
271
/// tag that lacked those permissions.
240
272
pub conflicting_info : & ' node NodeDebugInfo ,
241
- /// Whether this was a Read or Write access. This field is ignored
242
- /// when the error was triggered by a deallocation.
243
- pub access_kind : AccessKind ,
273
+ // What kind of access caused this error (read, write, reborrow, deallocation)
274
+ pub access_cause : AccessCause ,
244
275
/// Which tag the access that caused this error was made through, i.e.
245
276
/// which tag was used to read/write/deallocate.
246
277
pub accessed_info : & ' node NodeDebugInfo ,
@@ -250,46 +281,46 @@ impl TbError<'_> {
250
281
/// Produce a UB error.
251
282
pub fn build < ' tcx > ( self ) -> InterpError < ' tcx > {
252
283
use TransitionError :: * ;
253
- let kind = self . access_kind ;
284
+ let cause = self . access_cause ;
254
285
let accessed = self . accessed_info ;
255
286
let conflicting = self . conflicting_info ;
256
287
let accessed_is_conflicting = accessed. tag == conflicting. tag ;
288
+ let title = format ! ( "{cause} through {accessed} is forbidden" ) ;
257
289
let ( title, details, conflicting_tag_name) = match self . error_kind {
258
290
ChildAccessForbidden ( perm) => {
259
291
let conflicting_tag_name =
260
292
if accessed_is_conflicting { "accessed" } else { "conflicting" } ;
261
- let title = format ! ( "{kind} through {accessed} is forbidden" ) ;
262
293
let mut details = Vec :: new ( ) ;
263
294
if !accessed_is_conflicting {
264
295
details. push ( format ! (
265
296
"the accessed tag {accessed} is a child of the conflicting tag {conflicting}"
266
297
) ) ;
267
298
}
299
+ let access = cause. print_as_access ( /* is_foreign */ false ) ;
268
300
details. push ( format ! (
269
- "the {conflicting_tag_name} tag {conflicting} has state {perm} which forbids child {kind}es "
301
+ "the {conflicting_tag_name} tag {conflicting} has state {perm} which forbids this {access} "
270
302
) ) ;
271
303
( title, details, conflicting_tag_name)
272
304
}
273
305
ProtectedTransition ( transition) => {
274
306
let conflicting_tag_name = "protected" ;
275
- let title = format ! ( "{kind} through {accessed} is forbidden" ) ;
307
+ let access = cause . print_as_access ( /* is_foreign */ true ) ;
276
308
let details = vec ! [
277
309
format!(
278
310
"the accessed tag {accessed} is foreign to the {conflicting_tag_name} tag {conflicting} (i.e., it is not a child)"
279
311
) ,
280
312
format!(
281
- "the access would cause the {conflicting_tag_name} tag {conflicting} to transition {transition}"
313
+ "this { access} would cause the {conflicting_tag_name} tag {conflicting} to transition {transition}"
282
314
) ,
283
315
format!(
284
- "this is {loss}, which is not allowed for protected tags" ,
316
+ "this transition would be {loss}, which is not allowed for protected tags" ,
285
317
loss = transition. summary( ) ,
286
318
) ,
287
319
] ;
288
320
( title, details, conflicting_tag_name)
289
321
}
290
322
ProtectedDealloc => {
291
323
let conflicting_tag_name = "strongly protected" ;
292
- let title = format ! ( "deallocation through {accessed} is forbidden" ) ;
293
324
let details = vec ! [
294
325
format!(
295
326
"the allocation of the accessed tag {accessed} also contains the {conflicting_tag_name} tag {conflicting}"
0 commit comments