@@ -5,21 +5,22 @@ use rustc::hir;
5
5
use rustc:: mir:: interpret:: ConstEvalErr ;
6
6
use rustc:: mir;
7
7
use rustc:: ty:: { self , TyCtxt , Instance } ;
8
- use rustc:: ty:: layout:: { LayoutOf , Primitive , TyLayout } ;
8
+ use rustc:: ty:: layout:: { LayoutOf , Primitive , TyLayout , Size } ;
9
9
use rustc:: ty:: subst:: Subst ;
10
10
use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
11
11
12
12
use syntax:: ast:: Mutability ;
13
13
use syntax:: source_map:: Span ;
14
14
use syntax:: source_map:: DUMMY_SP ;
15
+ use syntax:: symbol:: Symbol ;
15
16
16
17
use rustc:: mir:: interpret:: {
17
18
EvalResult , EvalError , EvalErrorKind , GlobalId ,
18
19
Scalar , AllocId , Allocation , ConstValue ,
19
20
} ;
20
21
use super :: {
21
22
Place , PlaceExtra , PlaceTy , MemPlace , OpTy , Operand , Value ,
22
- EvalContext , StackPopCleanup , Memory , MemoryKind
23
+ EvalContext , StackPopCleanup , Memory , MemoryKind , MPlaceTy ,
23
24
} ;
24
25
25
26
pub fn mk_borrowck_eval_cx < ' a , ' mir , ' tcx > (
@@ -237,23 +238,56 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
237
238
if !ecx. tcx . is_const_fn ( instance. def_id ( ) ) {
238
239
let def_id = instance. def_id ( ) ;
239
240
// Some fn calls are actually BinOp intrinsics
240
- let ( op, oflo) = if let Some ( op) = ecx. tcx . is_binop_lang_item ( def_id) {
241
- op
241
+ let _: ! = if let Some ( ( op, oflo) ) = ecx. tcx . is_binop_lang_item ( def_id) {
242
+ let ( dest, bb) = destination. expect ( "128 lowerings can't diverge" ) ;
243
+ let l = ecx. read_value ( args[ 0 ] ) ?;
244
+ let r = ecx. read_value ( args[ 1 ] ) ?;
245
+ if oflo {
246
+ ecx. binop_with_overflow ( op, l, r, dest) ?;
247
+ } else {
248
+ ecx. binop_ignore_overflow ( op, l, r, dest) ?;
249
+ }
250
+ ecx. goto_block ( bb) ;
251
+ return Ok ( true ) ;
252
+ } else if Some ( def_id) == ecx. tcx . lang_items ( ) . panic_fn ( ) {
253
+ assert ! ( args. len( ) == 1 ) ;
254
+ // &(&'static str, &'static str, u32, u32)
255
+ let ptr = ecx. read_value ( args[ 0 ] ) ?;
256
+ let place = ecx. ref_to_mplace ( ptr) ?;
257
+ let ( msg, file, line, col) = (
258
+ place_field ( ecx, 0 , place) ?,
259
+ place_field ( ecx, 1 , place) ?,
260
+ place_field ( ecx, 2 , place) ?,
261
+ place_field ( ecx, 3 , place) ?,
262
+ ) ;
263
+
264
+ let msg = to_str ( ecx, msg) ?;
265
+ let file = to_str ( ecx, file) ?;
266
+ let line = to_u32 ( line) ?;
267
+ let col = to_u32 ( col) ?;
268
+ return Err ( EvalErrorKind :: Panic { msg, file, line, col } . into ( ) ) ;
269
+ } else if Some ( def_id) == ecx. tcx . lang_items ( ) . begin_panic_fn ( ) {
270
+ assert ! ( args. len( ) == 2 ) ;
271
+ // &'static str, &(&'static str, u32, u32)
272
+ let msg = ecx. read_value ( args[ 0 ] ) ?;
273
+ let ptr = ecx. read_value ( args[ 1 ] ) ?;
274
+ let place = ecx. ref_to_mplace ( ptr) ?;
275
+ let ( file, line, col) = (
276
+ place_field ( ecx, 0 , place) ?,
277
+ place_field ( ecx, 1 , place) ?,
278
+ place_field ( ecx, 2 , place) ?,
279
+ ) ;
280
+
281
+ let msg = to_str ( ecx, msg. value ) ?;
282
+ let file = to_str ( ecx, file) ?;
283
+ let line = to_u32 ( line) ?;
284
+ let col = to_u32 ( col) ?;
285
+ return Err ( EvalErrorKind :: Panic { msg, file, line, col } . into ( ) ) ;
242
286
} else {
243
287
return Err (
244
288
ConstEvalError :: NotConst ( format ! ( "calling non-const fn `{}`" , instance) ) . into ( ) ,
245
289
) ;
246
290
} ;
247
- let ( dest, bb) = destination. expect ( "128 lowerings can't diverge" ) ;
248
- let l = ecx. read_value ( args[ 0 ] ) ?;
249
- let r = ecx. read_value ( args[ 1 ] ) ?;
250
- if oflo {
251
- ecx. binop_with_overflow ( op, l, r, dest) ?;
252
- } else {
253
- ecx. binop_ignore_overflow ( op, l, r, dest) ?;
254
- }
255
- ecx. goto_block ( bb) ;
256
- return Ok ( true ) ;
257
291
}
258
292
let mir = match ecx. load_mir ( instance. def ) {
259
293
Ok ( mir) => mir,
@@ -412,6 +446,39 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
412
446
}
413
447
}
414
448
449
+ fn place_field < ' a , ' tcx , ' mir > (
450
+ ecx : & mut EvalContext < ' a , ' mir , ' tcx , CompileTimeEvaluator > ,
451
+ i : u64 ,
452
+ place : MPlaceTy < ' tcx > ,
453
+ ) -> EvalResult < ' tcx , Value > {
454
+ let place = ecx. mplace_field ( place, i) ?;
455
+ Ok ( ecx. try_read_value_from_mplace ( place) ?. expect ( "bad panic arg layout" ) )
456
+ }
457
+
458
+ fn to_str < ' a , ' tcx , ' mir > (
459
+ ecx : & mut EvalContext < ' a , ' mir , ' tcx , CompileTimeEvaluator > ,
460
+ val : Value ,
461
+ ) -> EvalResult < ' tcx , Symbol > {
462
+ if let Value :: ScalarPair ( ptr, len) = val {
463
+ let len = len. not_undef ( ) ?. to_bits ( ecx. memory . pointer_size ( ) ) ?;
464
+ let bytes = ecx. memory . read_bytes ( ptr. not_undef ( ) ?, Size :: from_bytes ( len as u64 ) ) ?;
465
+ let str = :: std:: str:: from_utf8 ( bytes) . map_err ( |err| EvalErrorKind :: ValidationFailure ( err. to_string ( ) ) ) ?;
466
+ Ok ( Symbol :: intern ( str) )
467
+ } else {
468
+ bug ! ( "panic arg is not a str" )
469
+ }
470
+ }
471
+
472
+ fn to_u32 < ' a , ' tcx , ' mir > (
473
+ val : Value ,
474
+ ) -> EvalResult < ' tcx , u32 > {
475
+ if let Value :: Scalar ( n) = val {
476
+ Ok ( n. not_undef ( ) ?. to_bits ( Size :: from_bits ( 32 ) ) ? as u32 )
477
+ } else {
478
+ bug ! ( "panic arg is not a str" )
479
+ }
480
+ }
481
+
415
482
/// Project to a field of a (variant of a) const
416
483
pub fn const_field < ' a , ' tcx > (
417
484
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
0 commit comments