@@ -4,6 +4,7 @@ use rustc_data_structures::sync::Lrc;
4
4
5
5
use rustc:: ty:: query:: Providers ;
6
6
use rustc:: ty:: { self , TyCtxt } ;
7
+ use rustc:: ty:: cast:: CastTy ;
7
8
use rustc:: hir;
8
9
use rustc:: hir:: Node ;
9
10
use rustc:: hir:: def_id:: DefId ;
@@ -20,6 +21,7 @@ use util;
20
21
21
22
pub struct UnsafetyChecker < ' a , ' tcx : ' a > {
22
23
mir : & ' a Mir < ' tcx > ,
24
+ const_context : bool ,
23
25
min_const_fn : bool ,
24
26
source_scope_local_data : & ' a IndexVec < SourceScope , SourceScopeLocalData > ,
25
27
violations : Vec < UnsafetyViolation > ,
@@ -33,14 +35,20 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
33
35
34
36
impl < ' a , ' gcx , ' tcx > UnsafetyChecker < ' a , ' tcx > {
35
37
fn new (
38
+ const_context : bool ,
36
39
min_const_fn : bool ,
37
40
mir : & ' a Mir < ' tcx > ,
38
41
source_scope_local_data : & ' a IndexVec < SourceScope , SourceScopeLocalData > ,
39
42
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
40
43
param_env : ty:: ParamEnv < ' tcx > ,
41
44
) -> Self {
45
+ // sanity check
46
+ if min_const_fn {
47
+ assert ! ( const_context) ;
48
+ }
42
49
Self {
43
50
mir,
51
+ const_context,
44
52
min_const_fn,
45
53
source_scope_local_data,
46
54
violations : vec ! [ ] ,
@@ -124,29 +132,70 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
124
132
rvalue : & Rvalue < ' tcx > ,
125
133
location : Location )
126
134
{
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) ;
140
157
}
141
158
}
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
+ _ => { } ,
148
180
}
149
181
}
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
+ _ => { } ,
150
199
}
151
200
self . super_rvalue ( rvalue, location) ;
152
201
}
@@ -484,8 +533,16 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
484
533
} ;
485
534
486
535
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
+ } ;
487
544
let mut checker = UnsafetyChecker :: new (
488
- tcx . is_min_const_fn ( def_id ) ,
545
+ const_context , min_const_fn ,
489
546
mir, source_scope_local_data, tcx, param_env) ;
490
547
checker. visit_mir ( mir) ;
491
548
0 commit comments