@@ -7,8 +7,11 @@ use rustc_middle::ty::{self, TyCtxt};
7
7
use rustc_session:: lint:: builtin:: { UNSAFE_OP_IN_UNSAFE_FN , UNUSED_UNSAFE } ;
8
8
use rustc_session:: lint:: Level ;
9
9
use rustc_span:: def_id:: { DefId , LocalDefId } ;
10
+ use rustc_span:: symbol:: Symbol ;
10
11
use rustc_span:: Span ;
11
12
13
+ use std:: ops:: Bound ;
14
+
12
15
struct UnsafetyVisitor < ' a , ' tcx > {
13
16
tcx : TyCtxt < ' tcx > ,
14
17
thir : & ' a Thir < ' tcx > ,
@@ -19,6 +22,10 @@ struct UnsafetyVisitor<'a, 'tcx> {
19
22
/// `unsafe` block, and whether it has been used.
20
23
safety_context : SafetyContext ,
21
24
body_unsafety : BodyUnsafety ,
25
+ /// The `#[target_feature]` attributes of the body. Used for checking
26
+ /// calls to functions with `#[target_feature]` (RFC 2396).
27
+ body_target_features : & ' tcx Vec < Symbol > ,
28
+ is_const : bool ,
22
29
}
23
30
24
31
impl < ' tcx > UnsafetyVisitor < ' _ , ' tcx > {
@@ -148,11 +155,55 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
148
155
ExprKind :: Call { fun, ty : _, args : _, from_hir_call : _, fn_span : _ } => {
149
156
if self . thir [ fun] . ty . fn_sig ( self . tcx ) . unsafety ( ) == hir:: Unsafety :: Unsafe {
150
157
self . requires_unsafe ( expr. span , CallToUnsafeFunction ) ;
158
+ } else if let & ty:: FnDef ( func_did, _) = self . thir [ fun] . ty . kind ( ) {
159
+ // If the called function has target features the calling function hasn't,
160
+ // the call requires `unsafe`.
161
+ if !self
162
+ . tcx
163
+ . codegen_fn_attrs ( func_did)
164
+ . target_features
165
+ . iter ( )
166
+ . all ( |feature| self . body_target_features . contains ( feature) )
167
+ {
168
+ self . requires_unsafe ( expr. span , CallToFunctionWith ) ;
169
+ }
170
+ }
171
+ }
172
+ ExprKind :: Deref { arg } => {
173
+ if let ExprKind :: StaticRef { def_id, .. } = self . thir [ arg] . kind {
174
+ if self . tcx . is_mutable_static ( def_id) {
175
+ self . requires_unsafe ( expr. span , UseOfMutableStatic ) ;
176
+ } else if self . tcx . is_foreign_item ( def_id) {
177
+ self . requires_unsafe ( expr. span , UseOfExternStatic ) ;
178
+ }
179
+ } else if self . thir [ arg] . ty . is_unsafe_ptr ( ) {
180
+ self . requires_unsafe ( expr. span , DerefOfRawPointer ) ;
151
181
}
152
182
}
153
183
ExprKind :: InlineAsm { .. } | ExprKind :: LlvmInlineAsm { .. } => {
154
184
self . requires_unsafe ( expr. span , UseOfInlineAssembly ) ;
155
185
}
186
+ ExprKind :: Adt {
187
+ adt_def,
188
+ variant_index : _,
189
+ substs : _,
190
+ user_ty : _,
191
+ fields : _,
192
+ base : _,
193
+ } => match self . tcx . layout_scalar_valid_range ( adt_def. did ) {
194
+ ( Bound :: Unbounded , Bound :: Unbounded ) => { }
195
+ _ => self . requires_unsafe ( expr. span , InitializingTypeWith ) ,
196
+ } ,
197
+ ExprKind :: Cast { source } => {
198
+ let source = & self . thir [ source] ;
199
+ if self . tcx . features ( ) . const_raw_ptr_to_usize_cast
200
+ && self . is_const
201
+ && ( source. ty . is_unsafe_ptr ( ) || source. ty . is_fn_ptr ( ) )
202
+ && expr. ty . is_integral ( )
203
+ {
204
+ self . requires_unsafe ( expr. span , CastOfPointerToInt ) ;
205
+ }
206
+ }
156
207
_ => { }
157
208
}
158
209
@@ -195,15 +246,10 @@ impl BodyUnsafety {
195
246
enum UnsafeOpKind {
196
247
CallToUnsafeFunction ,
197
248
UseOfInlineAssembly ,
198
- #[ allow( dead_code) ] // FIXME
199
249
InitializingTypeWith ,
200
- #[ allow( dead_code) ] // FIXME
201
250
CastOfPointerToInt ,
202
- #[ allow( dead_code) ] // FIXME
203
251
UseOfMutableStatic ,
204
- #[ allow( dead_code) ] // FIXME
205
252
UseOfExternStatic ,
206
- #[ allow( dead_code) ] // FIXME
207
253
DerefOfRawPointer ,
208
254
#[ allow( dead_code) ] // FIXME
209
255
AssignToDroppingUnionField ,
@@ -213,7 +259,6 @@ enum UnsafeOpKind {
213
259
MutationOfLayoutConstrainedField ,
214
260
#[ allow( dead_code) ] // FIXME
215
261
BorrowOfLayoutConstrainedField ,
216
- #[ allow( dead_code) ] // FIXME
217
262
CallToFunctionWith ,
218
263
}
219
264
@@ -287,6 +332,7 @@ pub fn check_unsafety<'tcx>(
287
332
tcx : TyCtxt < ' tcx > ,
288
333
thir : & Thir < ' tcx > ,
289
334
expr : ExprId ,
335
+ def_id : LocalDefId ,
290
336
hir_id : hir:: HirId ,
291
337
) {
292
338
let body_unsafety = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) . map_or ( BodyUnsafety :: Safe , |fn_sig| {
@@ -296,10 +342,23 @@ pub fn check_unsafety<'tcx>(
296
342
BodyUnsafety :: Safe
297
343
}
298
344
} ) ;
345
+ let body_target_features = & tcx. codegen_fn_attrs ( def_id) . target_features ;
299
346
let safety_context =
300
347
if body_unsafety. is_unsafe ( ) { SafetyContext :: UnsafeFn } else { SafetyContext :: Safe } ;
301
- let mut visitor =
302
- UnsafetyVisitor { tcx, thir, safety_context, hir_context : hir_id, body_unsafety } ;
348
+ let is_const = match tcx. hir ( ) . body_owner_kind ( hir_id) {
349
+ hir:: BodyOwnerKind :: Closure => false ,
350
+ hir:: BodyOwnerKind :: Fn => tcx. is_const_fn_raw ( def_id. to_def_id ( ) ) ,
351
+ hir:: BodyOwnerKind :: Const | hir:: BodyOwnerKind :: Static ( _) => true ,
352
+ } ;
353
+ let mut visitor = UnsafetyVisitor {
354
+ tcx,
355
+ thir,
356
+ safety_context,
357
+ hir_context : hir_id,
358
+ body_unsafety,
359
+ body_target_features,
360
+ is_const,
361
+ } ;
303
362
visitor. visit_expr ( & thir[ expr] ) ;
304
363
}
305
364
@@ -311,7 +370,7 @@ crate fn thir_check_unsafety_inner<'tcx>(
311
370
let body_id = tcx. hir ( ) . body_owned_by ( hir_id) ;
312
371
let body = tcx. hir ( ) . body ( body_id) ;
313
372
let ( thir, expr) = cx:: build_thir ( tcx, def, & body. value ) ;
314
- check_unsafety ( tcx, & thir, expr, hir_id) ;
373
+ check_unsafety ( tcx, & thir, expr, def . did , hir_id) ;
315
374
}
316
375
317
376
crate fn thir_check_unsafety < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) {
0 commit comments