@@ -4,6 +4,7 @@ use rustc_data_structures::sync::Lrc;
44
55use  rustc:: ty:: query:: Providers ; 
66use  rustc:: ty:: { self ,  TyCtxt } ; 
7+ use  rustc:: ty:: cast:: CastTy ; 
78use  rustc:: hir; 
89use  rustc:: hir:: Node ; 
910use  rustc:: hir:: def_id:: DefId ; 
@@ -20,6 +21,7 @@ use util;
2021
2122pub  struct  UnsafetyChecker < ' a ,  ' tcx :  ' a >  { 
2223    mir :  & ' a  Mir < ' tcx > , 
24+     const_context :  bool , 
2325    min_const_fn :  bool , 
2426    source_scope_local_data :  & ' a  IndexVec < SourceScope ,  SourceScopeLocalData > , 
2527    violations :  Vec < UnsafetyViolation > , 
@@ -33,14 +35,20 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
3335
3436impl < ' a ,  ' gcx ,  ' tcx >  UnsafetyChecker < ' a ,  ' tcx >  { 
3537    fn  new ( 
38+         const_context :  bool , 
3639        min_const_fn :  bool , 
3740        mir :  & ' a  Mir < ' tcx > , 
3841        source_scope_local_data :  & ' a  IndexVec < SourceScope ,  SourceScopeLocalData > , 
3942        tcx :  TyCtxt < ' a ,  ' tcx ,  ' tcx > , 
4043        param_env :  ty:: ParamEnv < ' tcx > , 
4144    )  -> Self  { 
45+         // sanity check 
46+         if  min_const_fn { 
47+             assert ! ( const_context) ; 
48+         } 
4249        Self  { 
4350            mir, 
51+             const_context, 
4452            min_const_fn, 
4553            source_scope_local_data, 
4654            violations :  vec ! [ ] , 
@@ -124,29 +132,70 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
124132                    rvalue :  & Rvalue < ' tcx > , 
125133                    location :  Location ) 
126134    { 
127-         if  let  & Rvalue :: Aggregate ( box ref  aggregate,  _)  = rvalue { 
128-             match  aggregate { 
129-                 & AggregateKind :: Array ( ..)  |
130-                 & AggregateKind :: Tuple  => { } 
131-                 & AggregateKind :: Adt ( ref  def,  ..)  => { 
132-                     match  self . tcx . layout_scalar_valid_range ( def. did )  { 
133-                         ( Bound :: Unbounded ,  Bound :: Unbounded )  => { } , 
134-                         _ => self . require_unsafe ( 
135-                             "initializing type with `rustc_layout_scalar_valid_range` attr" , 
136-                             "initializing a layout restricted type's field with a value outside \  
137- , 
138-                             UnsafetyViolationKind :: GeneralAndConstFn , 
139-                         ) , 
135+         match  rvalue { 
136+             Rvalue :: Aggregate ( box ref  aggregate,  _)  => { 
137+                 match  aggregate { 
138+                     & AggregateKind :: Array ( ..)  |
139+                     & AggregateKind :: Tuple  => { } 
140+                     & AggregateKind :: Adt ( ref  def,  ..)  => { 
141+                         match  self . tcx . layout_scalar_valid_range ( def. did )  { 
142+                             ( Bound :: Unbounded ,  Bound :: Unbounded )  => { } , 
143+                             _ => self . require_unsafe ( 
144+                                 "initializing type with `rustc_layout_scalar_valid_range` attr" , 
145+                                 "initializing a layout restricted type's field with a value \  
146+ , 
147+                                 UnsafetyViolationKind :: GeneralAndConstFn , 
148+                             ) , 
149+                         } 
150+                     } 
151+                     & AggregateKind :: Closure ( def_id,  _)  |
152+                     & AggregateKind :: Generator ( def_id,  _,  _)  => { 
153+                         let  UnsafetyCheckResult  { 
154+                             violations,  unsafe_blocks
155+                         }  = self . tcx . unsafety_check_result ( def_id) ; 
156+                         self . register_violations ( & violations,  & unsafe_blocks) ; 
140157                    } 
141158                } 
142-                 & AggregateKind :: Closure ( def_id,  _)  |
143-                 & AggregateKind :: Generator ( def_id,  _,  _)  => { 
144-                     let  UnsafetyCheckResult  { 
145-                         violations,  unsafe_blocks
146-                     }  = self . tcx . unsafety_check_result ( def_id) ; 
147-                     self . register_violations ( & violations,  & unsafe_blocks) ; 
159+             } , 
160+             // casting pointers to ints is unsafe in const fn because the const evaluator cannot 
161+             // possibly know what the result of various operations like `address / 2` would be 
162+             // pointers during const evaluation have no integral address, only an abstract one 
163+             Rvalue :: Cast ( CastKind :: Misc ,  ref  operand,  cast_ty) 
164+             if  self . const_context  && self . tcx . features ( ) . const_raw_ptr_to_usize_cast  => { 
165+                 let  operand_ty = operand. ty ( self . mir ,  self . tcx ) ; 
166+                 let  cast_in = CastTy :: from_ty ( operand_ty) . expect ( "bad input type for cast" ) ; 
167+                 let  cast_out = CastTy :: from_ty ( cast_ty) . expect ( "bad output type for cast" ) ; 
168+                 match  ( cast_in,  cast_out)  { 
169+                     ( CastTy :: Ptr ( _) ,  CastTy :: Int ( _) )  |
170+                     ( CastTy :: FnPtr ,  CastTy :: Int ( _) )  => { 
171+                         self . register_violations ( & [ UnsafetyViolation  { 
172+                             source_info :  self . source_info , 
173+                             description :  Symbol :: intern ( "cast of pointer to int" ) . as_interned_str ( ) , 
174+                             details :  Symbol :: intern ( "casting pointers to integers in constants" ) 
175+                                      . as_interned_str ( ) , 
176+                             kind :  UnsafetyViolationKind :: General , 
177+                         } ] ,  & [ ] ) ; 
178+                     } , 
179+                     _ => { } , 
148180                } 
149181            } 
182+             // raw pointer and fn pointer operations are unsafe as it is not clear whether one 
183+             // pointer would be "less" or "equal" to another, because we cannot know where llvm 
184+             // or the linker will place various statics in memory. Without this information the 
185+             // result of a comparison of addresses would differ between runtime and compile-time. 
186+             Rvalue :: BinaryOp ( _,  ref  lhs,  _) 
187+             if  self . const_context  && self . tcx . features ( ) . const_compare_raw_pointers  => { 
188+                 if  let  ty:: RawPtr ( _)  | ty:: FnPtr ( ..)  = lhs. ty ( self . mir ,  self . tcx ) . sty  { 
189+                     self . register_violations ( & [ UnsafetyViolation  { 
190+                         source_info :  self . source_info , 
191+                         description :  Symbol :: intern ( "pointer operation" ) . as_interned_str ( ) , 
192+                         details :  Symbol :: intern ( "operations on pointers in constants" ) 
193+                                  . as_interned_str ( ) , 
194+                         kind :  UnsafetyViolationKind :: General , 
195+                     } ] ,  & [ ] ) ; 
196+                 } 
197+             } 
198+             _ => { } , 
150199        } 
151200        self . super_rvalue ( rvalue,  location) ; 
152201    } 
@@ -484,8 +533,16 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
484533    } ; 
485534
486535    let  param_env = tcx. param_env ( def_id) ; 
536+ 
537+     let  id = tcx. hir ( ) . as_local_node_id ( def_id) . unwrap ( ) ; 
538+     let  ( const_context,  min_const_fn)  = match  tcx. hir ( ) . body_owner_kind ( id)  { 
539+         hir:: BodyOwnerKind :: Closure  => ( false ,  false ) , 
540+         hir:: BodyOwnerKind :: Fn  => ( tcx. is_const_fn ( def_id) ,  tcx. is_min_const_fn ( def_id) ) , 
541+         hir:: BodyOwnerKind :: Const  |
542+         hir:: BodyOwnerKind :: Static ( _)  => ( true ,  false ) , 
543+     } ; 
487544    let  mut  checker = UnsafetyChecker :: new ( 
488-         tcx . is_min_const_fn ( def_id ) , 
545+         const_context ,  min_const_fn , 
489546        mir,  source_scope_local_data,  tcx,  param_env) ; 
490547    checker. visit_mir ( mir) ; 
491548
0 commit comments