@@ -24,7 +24,6 @@ use rustc_borrowck as borrowck;
2424use rustc_resolve as resolve;
2525use rustc_trans:: back:: link;
2626use rustc_trans:: back:: write;
27- use rustc_trans:: save;
2827use rustc_trans:: trans;
2928use rustc_typeck as typeck;
3029
@@ -47,23 +46,43 @@ pub fn compile_input(sess: Session,
4746 input : & Input ,
4847 outdir : & Option < Path > ,
4948 output : & Option < Path > ,
50- addl_plugins : Option < Vec < String > > ) {
49+ addl_plugins : Option < Vec < String > > ,
50+ control : CompileController ) {
51+ macro_rules! controller_entry_point{ ( $point: ident, $make_state: expr) => ( {
52+ {
53+ let state = $make_state;
54+ ( control. $point. callback) ( state) ;
55+ }
56+ if control. $point. stop {
57+ return ;
58+ }
59+ } ) }
60+
5161 // We need nested scopes here, because the intermediate results can keep
5262 // large chunks of memory alive and we want to free them as soon as
5363 // possible to keep the peak memory usage low
5464 let ( outputs, trans, sess) = {
5565 let ( outputs, expanded_crate, id) = {
5666 let krate = phase_1_parse_input ( & sess, cfg, input) ;
57- if stop_after_phase_1 ( & sess) { return ; }
67+
68+ controller_entry_point ! ( after_parse,
69+ CompileState :: state_after_parse( input,
70+ & sess,
71+ outdir,
72+ & krate) ) ;
73+
5874 let outputs = build_output_filenames ( input,
5975 outdir,
6076 output,
6177 & krate. attrs [ ] ,
6278 & sess) ;
63- let id = link:: find_crate_name ( Some ( & sess) , & krate. attrs [ ] ,
79+ let id = link:: find_crate_name ( Some ( & sess) ,
80+ & krate. attrs [ ] ,
6481 input) ;
6582 let expanded_crate
66- = match phase_2_configure_and_expand ( & sess, krate, & id[ ] ,
83+ = match phase_2_configure_and_expand ( & sess,
84+ krate,
85+ & id[ ] ,
6786 addl_plugins) {
6887 None => return ,
6988 Some ( k) => k
@@ -72,23 +91,37 @@ pub fn compile_input(sess: Session,
7291 ( outputs, expanded_crate, id)
7392 } ;
7493
94+ controller_entry_point ! ( after_expand,
95+ CompileState :: state_after_expand( input,
96+ & sess,
97+ outdir,
98+ & expanded_crate,
99+ & id[ ] ) ) ;
100+
75101 let mut forest = ast_map:: Forest :: new ( expanded_crate) ;
76102 let ast_map = assign_node_ids_and_map ( & sess, & mut forest) ;
77103
78104 write_out_deps ( & sess, input, & outputs, & id[ ] ) ;
79105
80- if stop_after_phase_2 ( & sess) { return ; }
81-
82106 let arenas = ty:: CtxtArenas :: new ( ) ;
83- let analysis = phase_3_run_analysis_passes ( sess, ast_map, & arenas, id) ;
84- phase_save_analysis ( & analysis. ty_cx . sess , analysis. ty_cx . map . krate ( ) , & analysis, outdir) ;
107+ let analysis = phase_3_run_analysis_passes ( sess,
108+ ast_map,
109+ & arenas,
110+ id,
111+ control. make_glob_map ) ;
112+
113+ controller_entry_point ! ( after_analysis,
114+ CompileState :: state_after_analysis( input,
115+ & analysis. ty_cx. sess,
116+ outdir,
117+ analysis. ty_cx. map. krate( ) ,
118+ & analysis,
119+ & analysis. ty_cx) ) ;
85120
86121 if log_enabled ! ( :: log:: INFO ) {
87122 println ! ( "Pre-trans" ) ;
88123 analysis. ty_cx . print_debug_stats ( ) ;
89124 }
90-
91- if stop_after_phase_3 ( & analysis. ty_cx . sess ) { return ; }
92125 let ( tcx, trans) = phase_4_translate_to_llvm ( analysis) ;
93126
94127 if log_enabled ! ( :: log:: INFO ) {
@@ -102,7 +135,13 @@ pub fn compile_input(sess: Session,
102135 ( outputs, trans, tcx. sess )
103136 } ;
104137 phase_5_run_llvm_passes ( & sess, & trans, & outputs) ;
105- if stop_after_phase_5 ( & sess) { return ; }
138+
139+ controller_entry_point ! ( after_llvm,
140+ CompileState :: state_after_llvm( input,
141+ & sess,
142+ outdir,
143+ & trans) ) ;
144+
106145 phase_6_link_output ( & sess, & trans, & outputs) ;
107146}
108147
@@ -120,6 +159,146 @@ pub fn source_name(input: &Input) -> String {
120159 }
121160}
122161
162+ /// CompileController is used to customise compilation, it allows compilation to
163+ /// be stopped and/or to call arbitrary code at various points in compilation.
164+ /// It also allows for various flags to be set to influence what information gets
165+ /// colelcted during compilation.
166+ ///
167+ /// This is a somewhat higher level controller than a Session - the Session
168+ /// controls what happens in each phase, whereas the CompileController controls
169+ /// whether a phase is run at all and whether other code (from outside the
170+ /// the compiler) is run between phases.
171+ ///
172+ /// Note that if compilation is set to stop and a callback is provided for a
173+ /// given entry point, the callback is called before compilation is stopped.
174+ ///
175+ /// Expect more entry points to be added in the future.
176+ pub struct CompileController < ' a > {
177+ pub after_parse : PhaseController < ' a > ,
178+ pub after_expand : PhaseController < ' a > ,
179+ pub after_analysis : PhaseController < ' a > ,
180+ pub after_llvm : PhaseController < ' a > ,
181+
182+ pub make_glob_map : resolve:: MakeGlobMap ,
183+ }
184+
185+ impl < ' a > CompileController < ' a > {
186+ pub fn basic ( ) -> CompileController < ' a > {
187+ CompileController {
188+ after_parse : PhaseController :: basic ( ) ,
189+ after_expand : PhaseController :: basic ( ) ,
190+ after_analysis : PhaseController :: basic ( ) ,
191+ after_llvm : PhaseController :: basic ( ) ,
192+ make_glob_map : resolve:: MakeGlobMap :: No ,
193+ }
194+ }
195+ }
196+
197+ pub struct PhaseController < ' a > {
198+ pub stop : bool ,
199+ pub callback : Box < Fn ( CompileState ) -> ( ) + ' a > ,
200+ }
201+
202+ impl < ' a > PhaseController < ' a > {
203+ pub fn basic ( ) -> PhaseController < ' a > {
204+ PhaseController {
205+ stop : false ,
206+ callback : box |& : _| { } ,
207+ }
208+ }
209+ }
210+
211+ /// State that is passed to a callback. What state is available depends on when
212+ /// during compilation the callback is made. See the various constructor methods
213+ /// (`state_*`) in the impl to see which data is provided for any given entry point.
214+ pub struct CompileState < ' a , ' ast : ' a , ' tcx : ' a > {
215+ pub input : & ' a Input ,
216+ pub session : & ' a Session ,
217+ pub cfg : Option < & ' a ast:: CrateConfig > ,
218+ pub krate : Option < & ' a ast:: Crate > ,
219+ pub crate_name : Option < & ' a str > ,
220+ pub output_filenames : Option < & ' a OutputFilenames > ,
221+ pub out_dir : Option < & ' a Path > ,
222+ pub expanded_crate : Option < & ' a ast:: Crate > ,
223+ pub ast_map : Option < & ' a ast_map:: Map < ' ast > > ,
224+ pub analysis : Option < & ' a ty:: CrateAnalysis < ' tcx > > ,
225+ pub tcx : Option < & ' a ty:: ctxt < ' tcx > > ,
226+ pub trans : Option < & ' a trans:: CrateTranslation > ,
227+ }
228+
229+ impl < ' a , ' ast , ' tcx > CompileState < ' a , ' ast , ' tcx > {
230+ fn empty ( input : & ' a Input ,
231+ session : & ' a Session ,
232+ out_dir : & ' a Option < Path > )
233+ -> CompileState < ' a , ' ast , ' tcx > {
234+ CompileState {
235+ input : input,
236+ session : session,
237+ out_dir : out_dir. as_ref ( ) ,
238+ cfg : None ,
239+ krate : None ,
240+ crate_name : None ,
241+ output_filenames : None ,
242+ expanded_crate : None ,
243+ ast_map : None ,
244+ analysis : None ,
245+ tcx : None ,
246+ trans : None ,
247+ }
248+ }
249+
250+ fn state_after_parse ( input : & ' a Input ,
251+ session : & ' a Session ,
252+ out_dir : & ' a Option < Path > ,
253+ krate : & ' a ast:: Crate )
254+ -> CompileState < ' a , ' ast , ' tcx > {
255+ CompileState {
256+ krate : Some ( krate) ,
257+ .. CompileState :: empty ( input, session, out_dir)
258+ }
259+ }
260+
261+ fn state_after_expand ( input : & ' a Input ,
262+ session : & ' a Session ,
263+ out_dir : & ' a Option < Path > ,
264+ expanded_crate : & ' a ast:: Crate ,
265+ crate_name : & ' a str )
266+ -> CompileState < ' a , ' ast , ' tcx > {
267+ CompileState {
268+ crate_name : Some ( crate_name) ,
269+ expanded_crate : Some ( expanded_crate) ,
270+ .. CompileState :: empty ( input, session, out_dir)
271+ }
272+ }
273+
274+ fn state_after_analysis ( input : & ' a Input ,
275+ session : & ' a Session ,
276+ out_dir : & ' a Option < Path > ,
277+ krate : & ' a ast:: Crate ,
278+ analysis : & ' a ty:: CrateAnalysis < ' tcx > ,
279+ tcx : & ' a ty:: ctxt < ' tcx > )
280+ -> CompileState < ' a , ' ast , ' tcx > {
281+ CompileState {
282+ analysis : Some ( analysis) ,
283+ tcx : Some ( tcx) ,
284+ krate : Some ( krate) ,
285+ .. CompileState :: empty ( input, session, out_dir)
286+ }
287+ }
288+
289+
290+ fn state_after_llvm ( input : & ' a Input ,
291+ session : & ' a Session ,
292+ out_dir : & ' a Option < Path > ,
293+ trans : & ' a trans:: CrateTranslation )
294+ -> CompileState < ' a , ' ast , ' tcx > {
295+ CompileState {
296+ trans : Some ( trans) ,
297+ .. CompileState :: empty ( input, session, out_dir)
298+ }
299+ }
300+ }
301+
123302pub fn phase_1_parse_input ( sess : & Session , cfg : ast:: CrateConfig , input : & Input )
124303 -> ast:: Crate {
125304 // These may be left in an incoherent state after a previous compile.
@@ -347,7 +526,9 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session,
347526pub fn phase_3_run_analysis_passes < ' tcx > ( sess : Session ,
348527 ast_map : ast_map:: Map < ' tcx > ,
349528 arenas : & ' tcx ty:: CtxtArenas < ' tcx > ,
350- name : String ) -> ty:: CrateAnalysis < ' tcx > {
529+ name : String ,
530+ make_glob_map : resolve:: MakeGlobMap )
531+ -> ty:: CrateAnalysis < ' tcx > {
351532 let time_passes = sess. time_passes ( ) ;
352533 let krate = ast_map. krate ( ) ;
353534
@@ -357,11 +538,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
357538 let lang_items = time ( time_passes, "language item collection" , ( ) , |_|
358539 middle:: lang_items:: collect_language_items ( krate, & sess) ) ;
359540
360- let make_glob_map = if save_analysis ( & sess) {
361- resolve:: MakeGlobMap :: Yes
362- } else {
363- resolve:: MakeGlobMap :: No
364- } ;
365541 let resolve:: CrateMap {
366542 def_map,
367543 freevars,
@@ -483,21 +659,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
483659 }
484660}
485661
486- fn save_analysis ( sess : & Session ) -> bool {
487- sess. opts . debugging_opts . save_analysis
488- }
489-
490- pub fn phase_save_analysis ( sess : & Session ,
491- krate : & ast:: Crate ,
492- analysis : & ty:: CrateAnalysis ,
493- odir : & Option < Path > ) {
494- if !save_analysis ( sess) {
495- return ;
496- }
497- time ( sess. time_passes ( ) , "save analysis" , krate, |krate|
498- save:: process_crate ( sess, krate, analysis, odir) ) ;
499- }
500-
501662/// Run the translation phase to LLVM, after which the AST and analysis can
502663/// be discarded.
503664pub fn phase_4_translate_to_llvm < ' tcx > ( analysis : ty:: CrateAnalysis < ' tcx > )
@@ -559,41 +720,6 @@ pub fn phase_6_link_output(sess: &Session,
559720 os:: setenv ( "PATH" , old_path) ;
560721}
561722
562- pub fn stop_after_phase_3 ( sess : & Session ) -> bool {
563- if sess. opts . no_trans {
564- debug ! ( "invoked with --no-trans, returning early from compile_input" ) ;
565- return true ;
566- }
567- return false ;
568- }
569-
570- pub fn stop_after_phase_1 ( sess : & Session ) -> bool {
571- if sess. opts . parse_only {
572- debug ! ( "invoked with --parse-only, returning early from compile_input" ) ;
573- return true ;
574- }
575- if sess. opts . show_span . is_some ( ) {
576- return true ;
577- }
578- return sess. opts . debugging_opts . ast_json_noexpand ;
579- }
580-
581- pub fn stop_after_phase_2 ( sess : & Session ) -> bool {
582- if sess. opts . no_analysis {
583- debug ! ( "invoked with --no-analysis, returning early from compile_input" ) ;
584- return true ;
585- }
586- return sess. opts . debugging_opts . ast_json ;
587- }
588-
589- pub fn stop_after_phase_5 ( sess : & Session ) -> bool {
590- if !sess. opts . output_types . iter ( ) . any ( |& i| i == config:: OutputTypeExe ) {
591- debug ! ( "not building executable, returning early from compile_input" ) ;
592- return true ;
593- }
594- return false ;
595- }
596-
597723fn escape_dep_filename ( filename : & str ) -> String {
598724 // Apparently clang and gcc *only* escape spaces:
599725 // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
0 commit comments