@@ -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_id:: DefId ;
18
18
use rustc:: lint:: builtin:: { SAFE_EXTERN_STATICS , UNUSED_UNSAFE } ;
@@ -29,6 +29,9 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
29
29
visibility_scope_info : & ' a IndexVec < VisibilityScope , VisibilityScopeInfo > ,
30
30
violations : Vec < UnsafetyViolation > ,
31
31
source_info : SourceInfo ,
32
+ // true if an a part of this *memory block* of this expression
33
+ // is being borrowed, used for repr(packed) checking.
34
+ need_check_packed : bool ,
32
35
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
33
36
param_env : ty:: ParamEnv < ' tcx > ,
34
37
used_unsafe : FxHashSet < ast:: NodeId > ,
@@ -50,6 +53,7 @@ impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
50
53
} ,
51
54
tcx,
52
55
param_env,
56
+ need_check_packed : false ,
53
57
used_unsafe : FxHashSet ( ) ,
54
58
inherited_blocks : vec ! [ ] ,
55
59
}
@@ -138,6 +142,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
138
142
lvalue : & Lvalue < ' tcx > ,
139
143
context : LvalueContext < ' tcx > ,
140
144
location : Location ) {
145
+ let old_need_check_packed = self . need_check_packed ;
146
+ if let LvalueContext :: Borrow { .. } = context {
147
+ let ty = lvalue. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
148
+ if !self . has_align_1 ( ty) {
149
+ self . need_check_packed = true ;
150
+ }
151
+ }
152
+
141
153
match lvalue {
142
154
& Lvalue :: Projection ( box Projection {
143
155
ref base, ref elem
@@ -151,31 +163,39 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
151
163
self . source_info = self . mir . local_decls [ local] . source_info ;
152
164
}
153
165
}
166
+ if let & ProjectionElem :: Deref = elem {
167
+ self . need_check_packed = false ;
168
+ }
154
169
let base_ty = base. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
155
170
match base_ty. sty {
156
171
ty:: TyRawPtr ( ..) => {
157
172
self . require_unsafe ( "dereference of raw pointer" )
158
173
}
159
- ty:: TyAdt ( adt, _) if adt. is_union ( ) => {
160
- if context == LvalueContext :: Store ||
161
- context == LvalueContext :: Drop
162
- {
163
- let elem_ty = match elem {
164
- & ProjectionElem :: Field ( _, ty) => ty,
165
- _ => span_bug ! (
166
- self . source_info. span,
167
- "non-field projection {:?} from union?" ,
168
- lvalue)
169
- } ;
170
- if elem_ty. moves_by_default ( self . tcx , self . param_env ,
171
- self . source_info . span ) {
172
- self . require_unsafe (
173
- "assignment to non-`Copy` union field" )
174
+ ty:: TyAdt ( adt, _) => {
175
+ if adt. is_union ( ) {
176
+ if context == LvalueContext :: Store ||
177
+ context == LvalueContext :: Drop
178
+ {
179
+ let elem_ty = match elem {
180
+ & ProjectionElem :: Field ( _, ty) => ty,
181
+ _ => span_bug ! (
182
+ self . source_info. span,
183
+ "non-field projection {:?} from union?" ,
184
+ lvalue)
185
+ } ;
186
+ if elem_ty. moves_by_default ( self . tcx , self . param_env ,
187
+ self . source_info . span ) {
188
+ self . require_unsafe (
189
+ "assignment to non-`Copy` union field" )
190
+ } else {
191
+ // write to non-move union, safe
192
+ }
174
193
} else {
175
- // write to non-move union, safe
194
+ self . require_unsafe ( "access to union field" )
176
195
}
177
- } else {
178
- self . require_unsafe ( "access to union field" )
196
+ }
197
+ if adt. repr . packed ( ) && self . need_check_packed {
198
+ self . require_unsafe ( "borrow of packed field" )
179
199
}
180
200
}
181
201
_ => { }
@@ -199,12 +219,21 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
199
219
} ] , & [ ] ) ;
200
220
}
201
221
}
202
- }
222
+ } ;
203
223
self . super_lvalue ( lvalue, context, location) ;
224
+ self . need_check_packed = old_need_check_packed;
204
225
}
205
226
}
206
227
207
228
impl < ' a , ' tcx > UnsafetyChecker < ' a , ' tcx > {
229
+
230
+ fn has_align_1 ( & self , ty : Ty < ' tcx > ) -> bool {
231
+ self . tcx . at ( self . source_info . span )
232
+ . layout_raw ( self . param_env . and ( ty) )
233
+ . map ( |layout| layout. align . abi ( ) == 1 )
234
+ . unwrap_or ( false )
235
+ }
236
+
208
237
fn require_unsafe ( & mut self ,
209
238
description : & ' static str )
210
239
{
0 commit comments