@@ -7,11 +7,21 @@ extern crate rustc;
7
7
extern crate rustc_driver;
8
8
extern crate env_logger;
9
9
extern crate log_settings;
10
- extern crate log;
10
+ extern crate syntax;
11
+ #[ macro_use] extern crate log;
11
12
12
- use miri:: interpreter;
13
+ use miri:: {
14
+ EvalContext ,
15
+ CachedMir ,
16
+ step,
17
+ EvalError ,
18
+ Frame ,
19
+ } ;
13
20
use rustc:: session:: Session ;
14
21
use rustc_driver:: { driver, CompilerCalls } ;
22
+ use rustc:: ty:: { TyCtxt , subst} ;
23
+ use rustc:: mir:: mir_map:: MirMap ;
24
+ use rustc:: hir:: def_id:: DefId ;
15
25
16
26
struct MiriCompilerCalls ;
17
27
@@ -25,13 +35,84 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
25
35
26
36
control. after_analysis . callback = Box :: new ( |state| {
27
37
state. session . abort_if_errors ( ) ;
28
- interpreter :: interpret_start_points ( state. tcx . unwrap ( ) , state. mir_map . unwrap ( ) ) ;
38
+ interpret_start_points ( state. tcx . unwrap ( ) , state. mir_map . unwrap ( ) ) ;
29
39
} ) ;
30
40
31
41
control
32
42
}
33
43
}
34
44
45
+
46
+
47
+ fn interpret_start_points < ' a , ' tcx > (
48
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
49
+ mir_map : & MirMap < ' tcx > ,
50
+ ) {
51
+ let initial_indentation = :: log_settings:: settings ( ) . indentation ;
52
+ for ( & id, mir) in & mir_map. map {
53
+ for attr in tcx. map . attrs ( id) {
54
+ use syntax:: attr:: AttrMetaMethods ;
55
+ if attr. check_name ( "miri_run" ) {
56
+ let item = tcx. map . expect_item ( id) ;
57
+
58
+ :: log_settings:: settings ( ) . indentation = initial_indentation;
59
+
60
+ debug ! ( "Interpreting: {}" , item. name) ;
61
+
62
+ let mut ecx = EvalContext :: new ( tcx, mir_map) ;
63
+ let substs = tcx. mk_substs ( subst:: Substs :: empty ( ) ) ;
64
+ let return_ptr = ecx. alloc_ret_ptr ( mir. return_ty , substs) ;
65
+
66
+ ecx. push_stack_frame ( tcx. map . local_def_id ( id) , mir. span , CachedMir :: Ref ( mir) , substs, return_ptr) ;
67
+
68
+ loop {
69
+ match ( step ( & mut ecx) , return_ptr) {
70
+ ( Ok ( true ) , _) => { } ,
71
+ ( Ok ( false ) , Some ( ptr) ) => if log_enabled ! ( :: log:: LogLevel :: Debug ) {
72
+ ecx. memory ( ) . dump ( ptr. alloc_id ) ;
73
+ break ;
74
+ } ,
75
+ ( Ok ( false ) , None ) => {
76
+ warn ! ( "diverging function returned" ) ;
77
+ break ;
78
+ } ,
79
+ // FIXME: diverging functions can end up here in some future miri
80
+ ( Err ( e) , _) => {
81
+ report ( tcx, & ecx, e) ;
82
+ break ;
83
+ } ,
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ fn report ( tcx : TyCtxt , ecx : & EvalContext , e : EvalError ) {
92
+ let frame = ecx. stack ( ) . last ( ) . expect ( "stackframe was empty" ) ;
93
+ let block = frame. mir . basic_block_data ( frame. next_block ) ;
94
+ let span = if frame. stmt < block. statements . len ( ) {
95
+ block. statements [ frame. stmt ] . span
96
+ } else {
97
+ block. terminator ( ) . span
98
+ } ;
99
+ let mut err = tcx. sess . struct_span_err ( span, & e. to_string ( ) ) ;
100
+ for & Frame { def_id, substs, span, .. } in ecx. stack ( ) . iter ( ) . rev ( ) {
101
+ // FIXME(solson): Find a way to do this without this Display impl hack.
102
+ use rustc:: util:: ppaux;
103
+ use std:: fmt;
104
+ struct Instance < ' tcx > ( DefId , & ' tcx subst:: Substs < ' tcx > ) ;
105
+ impl < ' tcx > fmt:: Display for Instance < ' tcx > {
106
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
107
+ ppaux:: parameterized ( f, self . 1 , self . 0 , ppaux:: Ns :: Value , & [ ] ,
108
+ |tcx| tcx. lookup_item_type ( self . 0 ) . generics )
109
+ }
110
+ }
111
+ err. span_note ( span, & format ! ( "inside call to {}" , Instance ( def_id, substs) ) ) ;
112
+ }
113
+ err. emit ( ) ;
114
+ }
115
+
35
116
#[ miri_run]
36
117
fn main ( ) {
37
118
init_logger ( ) ;
0 commit comments