@@ -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,6 +152,18 @@ 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 { .. } => {
@@ -217,7 +233,6 @@ enum UnsafeOpKind {
217
233
MutationOfLayoutConstrainedField ,
218
234
#[ allow( dead_code) ] // FIXME
219
235
BorrowOfLayoutConstrainedField ,
220
- #[ allow( dead_code) ] // FIXME
221
236
CallToFunctionWith ,
222
237
}
223
238
@@ -291,6 +306,7 @@ pub fn check_unsafety<'tcx>(
291
306
tcx : TyCtxt < ' tcx > ,
292
307
thir : & Thir < ' tcx > ,
293
308
expr : ExprId ,
309
+ def_id : LocalDefId ,
294
310
hir_id : hir:: HirId ,
295
311
) {
296
312
let body_unsafety = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) . map_or ( BodyUnsafety :: Safe , |fn_sig| {
@@ -300,10 +316,17 @@ pub fn check_unsafety<'tcx>(
300
316
BodyUnsafety :: Safe
301
317
}
302
318
} ) ;
319
+ let body_target_features = & tcx. codegen_fn_attrs ( def_id) . target_features ;
303
320
let safety_context =
304
321
if body_unsafety. is_unsafe ( ) { SafetyContext :: UnsafeFn } else { SafetyContext :: Safe } ;
305
- let mut visitor =
306
- 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
+ } ;
307
330
visitor. visit_expr ( & thir[ expr] ) ;
308
331
}
309
332
@@ -315,7 +338,7 @@ crate fn thir_check_unsafety_inner<'tcx>(
315
338
let body_id = tcx. hir ( ) . body_owned_by ( hir_id) ;
316
339
let body = tcx. hir ( ) . body ( body_id) ;
317
340
let ( thir, expr) = cx:: build_thir ( tcx, def, & body. value ) ;
318
- check_unsafety ( tcx, & thir, expr, hir_id) ;
341
+ check_unsafety ( tcx, & thir, expr, def . did , hir_id) ;
319
342
}
320
343
321
344
crate fn thir_check_unsafety < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) {
0 commit comments