@@ -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- the valid range is undefined behavior",
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+ outside the valid range is undefined behavior",
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