@@ -7,8 +7,11 @@ use rustc_middle::ty::{self, TyCtxt};
77use rustc_session:: lint:: builtin:: { UNSAFE_OP_IN_UNSAFE_FN , UNUSED_UNSAFE } ;
88use rustc_session:: lint:: Level ;
99use rustc_span:: def_id:: { DefId , LocalDefId } ;
10+ use rustc_span:: symbol:: Symbol ;
1011use rustc_span:: Span ;
1112
13+ use std:: ops:: Bound ;
14+
1215struct UnsafetyVisitor < ' a , ' tcx > {
1316 tcx : TyCtxt < ' tcx > ,
1417 thir : & ' a Thir < ' tcx > ,
@@ -19,6 +22,10 @@ struct UnsafetyVisitor<'a, 'tcx> {
1922 /// `unsafe` block, and whether it has been used.
2023 safety_context : SafetyContext ,
2124 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 ,
2229}
2330
2431impl < ' tcx > UnsafetyVisitor < ' _ , ' tcx > {
@@ -148,11 +155,55 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
148155 ExprKind :: Call { fun, ty : _, args : _, from_hir_call : _, fn_span : _ } => {
149156 if self . thir [ fun] . ty . fn_sig ( self . tcx ) . unsafety ( ) == hir:: Unsafety :: Unsafe {
150157 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 ) ;
151181 }
152182 }
153183 ExprKind :: InlineAsm { .. } | ExprKind :: LlvmInlineAsm { .. } => {
154184 self . requires_unsafe ( expr. span , UseOfInlineAssembly ) ;
155185 }
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+ }
156207 _ => { }
157208 }
158209
@@ -195,15 +246,10 @@ impl BodyUnsafety {
195246enum UnsafeOpKind {
196247 CallToUnsafeFunction ,
197248 UseOfInlineAssembly ,
198- #[ allow( dead_code) ] // FIXME
199249 InitializingTypeWith ,
200- #[ allow( dead_code) ] // FIXME
201250 CastOfPointerToInt ,
202- #[ allow( dead_code) ] // FIXME
203251 UseOfMutableStatic ,
204- #[ allow( dead_code) ] // FIXME
205252 UseOfExternStatic ,
206- #[ allow( dead_code) ] // FIXME
207253 DerefOfRawPointer ,
208254 #[ allow( dead_code) ] // FIXME
209255 AssignToDroppingUnionField ,
@@ -213,7 +259,6 @@ enum UnsafeOpKind {
213259 MutationOfLayoutConstrainedField ,
214260 #[ allow( dead_code) ] // FIXME
215261 BorrowOfLayoutConstrainedField ,
216- #[ allow( dead_code) ] // FIXME
217262 CallToFunctionWith ,
218263}
219264
@@ -287,6 +332,7 @@ pub fn check_unsafety<'tcx>(
287332 tcx : TyCtxt < ' tcx > ,
288333 thir : & Thir < ' tcx > ,
289334 expr : ExprId ,
335+ def_id : LocalDefId ,
290336 hir_id : hir:: HirId ,
291337) {
292338 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>(
296342 BodyUnsafety :: Safe
297343 }
298344 } ) ;
345+ let body_target_features = & tcx. codegen_fn_attrs ( def_id) . target_features ;
299346 let safety_context =
300347 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+ } ;
303362 visitor. visit_expr ( & thir[ expr] ) ;
304363}
305364
@@ -311,7 +370,7 @@ crate fn thir_check_unsafety_inner<'tcx>(
311370 let body_id = tcx. hir ( ) . body_owned_by ( hir_id) ;
312371 let body = tcx. hir ( ) . body ( body_id) ;
313372 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) ;
315374}
316375
317376crate fn thir_check_unsafety < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) {
0 commit comments