@@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
12
12
use rustc_data_structures:: indexed_vec:: IndexVec ;
13
13
14
14
use rustc:: ty:: maps:: Providers ;
15
- use rustc:: ty:: { self , TyCtxt } ;
15
+ use rustc:: ty:: { self , Ty , TyCtxt } ;
16
16
use rustc:: hir;
17
17
use rustc:: hir:: def:: Def ;
18
18
use rustc:: hir:: def_id:: DefId ;
@@ -31,6 +31,9 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
31
31
visibility_scope_info : & ' a IndexVec < VisibilityScope , VisibilityScopeInfo > ,
32
32
violations : Vec < UnsafetyViolation > ,
33
33
source_info : SourceInfo ,
34
+ // true if an a part of this *memory block* of this expression
35
+ // is being borrowed, used for repr(packed) checking.
36
+ need_check_packed : bool ,
34
37
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
35
38
param_env : ty:: ParamEnv < ' tcx > ,
36
39
used_unsafe : FxHashSet < ast:: NodeId > ,
@@ -51,6 +54,7 @@ impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
51
54
} ,
52
55
tcx,
53
56
param_env,
57
+ need_check_packed : false ,
54
58
used_unsafe : FxHashSet ( ) ,
55
59
}
56
60
}
@@ -130,6 +134,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
130
134
lvalue : & Lvalue < ' tcx > ,
131
135
context : LvalueContext < ' tcx > ,
132
136
location : Location ) {
137
+ let old_need_check_packed = self . need_check_packed ;
138
+ if let LvalueContext :: Borrow { .. } = context {
139
+ let ty = lvalue. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
140
+ if !self . has_align_1 ( ty) {
141
+ self . need_check_packed = true ;
142
+ }
143
+ }
144
+
133
145
match lvalue {
134
146
& Lvalue :: Projection ( box Projection {
135
147
ref base, ref elem
@@ -143,31 +155,39 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
143
155
self . source_info = self . mir . local_decls [ local] . source_info ;
144
156
}
145
157
}
158
+ if let & ProjectionElem :: Deref = elem {
159
+ self . need_check_packed = false ;
160
+ }
146
161
let base_ty = base. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
147
162
match base_ty. sty {
148
163
ty:: TyRawPtr ( ..) => {
149
164
self . require_unsafe ( "dereference of raw pointer" )
150
165
}
151
- ty:: TyAdt ( adt, _) if adt. is_union ( ) => {
152
- if context == LvalueContext :: Store ||
153
- context == LvalueContext :: Drop
154
- {
155
- let elem_ty = match elem {
156
- & ProjectionElem :: Field ( _, ty) => ty,
157
- _ => span_bug ! (
158
- self . source_info. span,
159
- "non-field projection {:?} from union?" ,
160
- lvalue)
161
- } ;
162
- if elem_ty. moves_by_default ( self . tcx , self . param_env ,
163
- self . source_info . span ) {
164
- self . require_unsafe (
165
- "assignment to non-`Copy` union field" )
166
+ ty:: TyAdt ( adt, _) => {
167
+ if adt. is_union ( ) {
168
+ if context == LvalueContext :: Store ||
169
+ context == LvalueContext :: Drop
170
+ {
171
+ let elem_ty = match elem {
172
+ & ProjectionElem :: Field ( _, ty) => ty,
173
+ _ => span_bug ! (
174
+ self . source_info. span,
175
+ "non-field projection {:?} from union?" ,
176
+ lvalue)
177
+ } ;
178
+ if elem_ty. moves_by_default ( self . tcx , self . param_env ,
179
+ self . source_info . span ) {
180
+ self . require_unsafe (
181
+ "assignment to non-`Copy` union field" )
182
+ } else {
183
+ // write to non-move union, safe
184
+ }
166
185
} else {
167
- // write to non-move union, safe
186
+ self . require_unsafe ( "access to union field" )
168
187
}
169
- } else {
170
- self . require_unsafe ( "access to union field" )
188
+ }
189
+ if adt. repr . packed ( ) && self . need_check_packed {
190
+ self . require_unsafe ( "borrow of packed field" )
171
191
}
172
192
}
173
193
_ => { }
@@ -191,8 +211,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
191
211
} ] ) ;
192
212
}
193
213
}
194
- }
214
+ } ;
195
215
self . super_lvalue ( lvalue, context, location) ;
216
+ self . need_check_packed = old_need_check_packed;
196
217
}
197
218
}
198
219
@@ -215,6 +236,14 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
215
236
}
216
237
}
217
238
}
239
+
240
+ fn has_align_1 ( & self , ty : Ty < ' tcx > ) -> bool {
241
+ self . tcx . at ( self . source_info . span )
242
+ . layout_raw ( self . param_env . and ( ty) )
243
+ . map ( |layout| layout. align ( self . tcx ) . abi ( ) == 1 )
244
+ . unwrap_or ( false )
245
+ }
246
+
218
247
fn require_unsafe ( & mut self ,
219
248
description : & ' static str )
220
249
{
0 commit comments