@@ -7,6 +7,7 @@ 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
12
13
struct UnsafetyVisitor < ' a , ' tcx > {
@@ -19,6 +20,9 @@ struct UnsafetyVisitor<'a, 'tcx> {
19
20
/// `unsafe` block, and whether it has been used.
20
21
safety_context : SafetyContext ,
21
22
body_unsafety : BodyUnsafety ,
23
+ /// The `#[target_feature]` attributes of the body. Used for checking
24
+ /// calls to functions with `#[target_feature]` (RFC 2396).
25
+ body_target_features : & ' tcx Vec < Symbol > ,
22
26
}
23
27
24
28
impl < ' tcx > UnsafetyVisitor < ' _ , ' tcx > {
@@ -148,11 +152,28 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
148
152
ExprKind :: Call { fun, ty : _, args : _, from_hir_call : _, fn_span : _ } => {
149
153
if self . thir [ fun] . ty . fn_sig ( self . tcx ) . unsafety ( ) == hir:: Unsafety :: Unsafe {
150
154
self . requires_unsafe ( expr. span , CallToUnsafeFunction ) ;
155
+ } else if let & ty:: FnDef ( func_did, _) = self . thir [ fun] . ty . kind ( ) {
156
+ // If the called function has target features the calling function hasn't,
157
+ // the call requires `unsafe`.
158
+ if !self
159
+ . tcx
160
+ . codegen_fn_attrs ( func_did)
161
+ . target_features
162
+ . iter ( )
163
+ . all ( |feature| self . body_target_features . contains ( feature) )
164
+ {
165
+ self . requires_unsafe ( expr. span , CallToFunctionWith ) ;
166
+ }
151
167
}
152
168
}
153
169
ExprKind :: InlineAsm { .. } | ExprKind :: LlvmInlineAsm { .. } => {
154
170
self . requires_unsafe ( expr. span , UseOfInlineAssembly ) ;
155
171
}
172
+ ExprKind :: Deref { arg } => {
173
+ if self . thir [ arg] . ty . is_unsafe_ptr ( ) {
174
+ self . requires_unsafe ( expr. span , DerefOfRawPointer ) ;
175
+ }
176
+ }
156
177
_ => { }
157
178
}
158
179
@@ -203,7 +224,6 @@ enum UnsafeOpKind {
203
224
UseOfMutableStatic ,
204
225
#[ allow( dead_code) ] // FIXME
205
226
UseOfExternStatic ,
206
- #[ allow( dead_code) ] // FIXME
207
227
DerefOfRawPointer ,
208
228
#[ allow( dead_code) ] // FIXME
209
229
AssignToDroppingUnionField ,
@@ -213,7 +233,6 @@ enum UnsafeOpKind {
213
233
MutationOfLayoutConstrainedField ,
214
234
#[ allow( dead_code) ] // FIXME
215
235
BorrowOfLayoutConstrainedField ,
216
- #[ allow( dead_code) ] // FIXME
217
236
CallToFunctionWith ,
218
237
}
219
238
@@ -287,6 +306,7 @@ pub fn check_unsafety<'tcx>(
287
306
tcx : TyCtxt < ' tcx > ,
288
307
thir : & Thir < ' tcx > ,
289
308
expr : ExprId ,
309
+ def_id : LocalDefId ,
290
310
hir_id : hir:: HirId ,
291
311
) {
292
312
let body_unsafety = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) . map_or ( BodyUnsafety :: Safe , |fn_sig| {
@@ -296,10 +316,17 @@ pub fn check_unsafety<'tcx>(
296
316
BodyUnsafety :: Safe
297
317
}
298
318
} ) ;
319
+ let body_target_features = & tcx. codegen_fn_attrs ( def_id) . target_features ;
299
320
let safety_context =
300
321
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 } ;
322
+ let mut visitor = UnsafetyVisitor {
323
+ tcx,
324
+ thir,
325
+ safety_context,
326
+ hir_context : hir_id,
327
+ body_unsafety,
328
+ body_target_features,
329
+ } ;
303
330
visitor. visit_expr ( & thir[ expr] ) ;
304
331
}
305
332
@@ -311,7 +338,7 @@ crate fn thir_check_unsafety_inner<'tcx>(
311
338
let body_id = tcx. hir ( ) . body_owned_by ( hir_id) ;
312
339
let body = tcx. hir ( ) . body ( body_id) ;
313
340
let ( thir, expr) = cx:: build_thir ( tcx, def, & body. value ) ;
314
- check_unsafety ( tcx, & thir, expr, hir_id) ;
341
+ check_unsafety ( tcx, & thir, expr, def . did , hir_id) ;
315
342
}
316
343
317
344
crate fn thir_check_unsafety < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) {
0 commit comments