Skip to content

Commit 486f60d

Browse files
committed
auto merge of #20917 : nick29581/rust/plugins, r=huonw
2 parents 0aec4db + 55d5c46 commit 486f60d

File tree

8 files changed

+268
-81
lines changed

8 files changed

+268
-81
lines changed

src/librustc_driver/driver.rs

+194-68
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use rustc_borrowck as borrowck;
2424
use rustc_resolve as resolve;
2525
use rustc_trans::back::link;
2626
use rustc_trans::back::write;
27-
use rustc_trans::save;
2827
use rustc_trans::trans;
2928
use 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+
123302
pub 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,
347526
pub 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.
503664
pub 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-
597723
fn 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

Comments
 (0)