]> git.lizzy.rs Git - rust.git/blob - src/librustc/session/mod.rs
Auto merge of #36335 - mcarton:compiletest, r=GuillaumeGomez
[rust.git] / src / librustc / session / mod.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use dep_graph::DepGraph;
12 use hir::def_id::{CrateNum, DefIndex};
13 use hir::svh::Svh;
14 use lint;
15 use middle::cstore::CrateStore;
16 use middle::dependency_format;
17 use session::search_paths::PathKind;
18 use session::config::{DebugInfoLevel, PanicStrategy};
19 use ty::tls;
20 use util::nodemap::{NodeMap, FnvHashMap};
21 use util::common::duration_to_secs_str;
22 use mir::transform as mir_pass;
23
24 use syntax::ast::NodeId;
25 use errors::{self, DiagnosticBuilder};
26 use errors::emitter::{Emitter, EmitterWriter};
27 use syntax::json::JsonEmitter;
28 use syntax::feature_gate;
29 use syntax::parse;
30 use syntax::parse::ParseSess;
31 use syntax::parse::token;
32 use syntax::{ast, codemap};
33 use syntax::feature_gate::AttributeType;
34 use syntax_pos::{Span, MultiSpan};
35
36 use rustc_back::target::Target;
37 use rustc_data_structures::flock;
38 use llvm;
39
40 use std::path::{Path, PathBuf};
41 use std::cell::{self, Cell, RefCell};
42 use std::collections::HashMap;
43 use std::env;
44 use std::ffi::CString;
45 use std::rc::Rc;
46 use std::fmt;
47 use std::time::Duration;
48 use libc::c_int;
49
50 pub mod config;
51 pub mod filesearch;
52 pub mod search_paths;
53
54 // Represents the data associated with a compilation
55 // session for a single crate.
56 pub struct Session {
57     pub dep_graph: DepGraph,
58     pub target: config::Config,
59     pub host: Target,
60     pub opts: config::Options,
61     pub cstore: Rc<for<'a> CrateStore<'a>>,
62     pub parse_sess: ParseSess,
63     // For a library crate, this is always none
64     pub entry_fn: RefCell<Option<(NodeId, Span)>>,
65     pub entry_type: Cell<Option<config::EntryFnType>>,
66     pub plugin_registrar_fn: Cell<Option<ast::NodeId>>,
67     pub derive_registrar_fn: Cell<Option<ast::NodeId>>,
68     pub default_sysroot: Option<PathBuf>,
69     // The name of the root source file of the crate, in the local file system.
70     // The path is always expected to be absolute. `None` means that there is no
71     // source file.
72     pub local_crate_source_file: Option<PathBuf>,
73     pub working_dir: PathBuf,
74     pub lint_store: RefCell<lint::LintStore>,
75     pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
76     pub plugin_llvm_passes: RefCell<Vec<String>>,
77     pub mir_passes: RefCell<mir_pass::Passes>,
78     pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
79     pub crate_types: RefCell<Vec<config::CrateType>>,
80     pub dependency_formats: RefCell<dependency_format::Dependencies>,
81     // The crate_disambiguator is constructed out of all the `-C metadata`
82     // arguments passed to the compiler. Its value together with the crate-name
83     // forms a unique global identifier for the crate. It is used to allow
84     // multiple crates with the same name to coexist. See the
85     // trans::back::symbol_names module for more information.
86     pub crate_disambiguator: RefCell<token::InternedString>,
87     pub features: RefCell<feature_gate::Features>,
88
89     /// The maximum recursion limit for potentially infinitely recursive
90     /// operations such as auto-dereference and monomorphization.
91     pub recursion_limit: Cell<usize>,
92
93     /// The metadata::creader module may inject an allocator/panic_runtime
94     /// dependency if it didn't already find one, and this tracks what was
95     /// injected.
96     pub injected_allocator: Cell<Option<CrateNum>>,
97     pub injected_panic_runtime: Cell<Option<CrateNum>>,
98
99     /// Map from imported macro spans (which consist of
100     /// the localized span for the macro body) to the
101     /// macro name and defintion span in the source crate.
102     pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>,
103
104     incr_comp_session: RefCell<IncrCompSession>,
105
106     /// Some measurements that are being gathered during compilation.
107     pub perf_stats: PerfStats,
108
109     next_node_id: Cell<ast::NodeId>,
110 }
111
112 pub struct PerfStats {
113     // The accumulated time needed for computing the SVH of the crate
114     pub svh_time: Cell<Duration>,
115     // The accumulated time spent on computing incr. comp. hashes
116     pub incr_comp_hashes_time: Cell<Duration>,
117     // The number of incr. comp. hash computations performed
118     pub incr_comp_hashes_count: Cell<u64>,
119     // The accumulated time spent on computing symbol hashes
120     pub symbol_hash_time: Cell<Duration>,
121 }
122
123 impl Session {
124     pub fn local_crate_disambiguator(&self) -> token::InternedString {
125         self.crate_disambiguator.borrow().clone()
126     }
127     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
128                                                     sp: S,
129                                                     msg: &str)
130                                                     -> DiagnosticBuilder<'a>  {
131         self.diagnostic().struct_span_warn(sp, msg)
132     }
133     pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
134                                                               sp: S,
135                                                               msg: &str,
136                                                               code: &str)
137                                                               -> DiagnosticBuilder<'a>  {
138         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
139     }
140     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
141         self.diagnostic().struct_warn(msg)
142     }
143     pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
144                                                    sp: S,
145                                                    msg: &str)
146                                                    -> DiagnosticBuilder<'a>  {
147         self.diagnostic().struct_span_err(sp, msg)
148     }
149     pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
150                                                              sp: S,
151                                                              msg: &str,
152                                                              code: &str)
153                                                              -> DiagnosticBuilder<'a>  {
154         self.diagnostic().struct_span_err_with_code(sp, msg, code)
155     }
156     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
157         self.diagnostic().struct_err(msg)
158     }
159     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
160                                                      sp: S,
161                                                      msg: &str)
162                                                      -> DiagnosticBuilder<'a>  {
163         self.diagnostic().struct_span_fatal(sp, msg)
164     }
165     pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
166                                                                sp: S,
167                                                                msg: &str,
168                                                                code: &str)
169                                                                -> DiagnosticBuilder<'a>  {
170         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
171     }
172     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
173         self.diagnostic().struct_fatal(msg)
174     }
175
176     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
177         panic!(self.diagnostic().span_fatal(sp, msg))
178     }
179     pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) -> ! {
180         panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
181     }
182     pub fn fatal(&self, msg: &str) -> ! {
183         panic!(self.diagnostic().fatal(msg))
184     }
185     pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
186         if is_warning {
187             self.span_warn(sp, msg);
188         } else {
189             self.span_err(sp, msg);
190         }
191     }
192     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
193         self.diagnostic().span_err(sp, msg)
194     }
195     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
196         self.diagnostic().span_err_with_code(sp, &msg, code)
197     }
198     pub fn err(&self, msg: &str) {
199         self.diagnostic().err(msg)
200     }
201     pub fn err_count(&self) -> usize {
202         self.diagnostic().err_count()
203     }
204     pub fn has_errors(&self) -> bool {
205         self.diagnostic().has_errors()
206     }
207     pub fn abort_if_errors(&self) {
208         self.diagnostic().abort_if_errors();
209     }
210     pub fn track_errors<F, T>(&self, f: F) -> Result<T, usize>
211         where F: FnOnce() -> T
212     {
213         let old_count = self.err_count();
214         let result = f();
215         let errors = self.err_count() - old_count;
216         if errors == 0 {
217             Ok(result)
218         } else {
219             Err(errors)
220         }
221     }
222     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
223         self.diagnostic().span_warn(sp, msg)
224     }
225     pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
226         self.diagnostic().span_warn_with_code(sp, msg, code)
227     }
228     pub fn warn(&self, msg: &str) {
229         self.diagnostic().warn(msg)
230     }
231     pub fn opt_span_warn<S: Into<MultiSpan>>(&self, opt_sp: Option<S>, msg: &str) {
232         match opt_sp {
233             Some(sp) => self.span_warn(sp, msg),
234             None => self.warn(msg),
235         }
236     }
237     /// Delay a span_bug() call until abort_if_errors()
238     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
239         self.diagnostic().delay_span_bug(sp, msg)
240     }
241     pub fn note_without_error(&self, msg: &str) {
242         self.diagnostic().note_without_error(msg)
243     }
244     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
245         self.diagnostic().span_note_without_error(sp, msg)
246     }
247     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
248         self.diagnostic().span_unimpl(sp, msg)
249     }
250     pub fn unimpl(&self, msg: &str) -> ! {
251         self.diagnostic().unimpl(msg)
252     }
253     pub fn add_lint(&self,
254                     lint: &'static lint::Lint,
255                     id: ast::NodeId,
256                     sp: Span,
257                     msg: String) {
258         let lint_id = lint::LintId::of(lint);
259         let mut lints = self.lints.borrow_mut();
260         if let Some(arr) = lints.get_mut(&id) {
261             let tuple = (lint_id, sp, msg);
262             if !arr.contains(&tuple) {
263                 arr.push(tuple);
264             }
265             return;
266         }
267         lints.insert(id, vec!((lint_id, sp, msg)));
268     }
269     pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId {
270         let id = self.next_node_id.get();
271
272         match id.as_usize().checked_add(count) {
273             Some(next) => {
274                 self.next_node_id.set(ast::NodeId::new(next));
275             }
276             None => bug!("Input too large, ran out of node ids!")
277         }
278
279         id
280     }
281     pub fn next_node_id(&self) -> NodeId {
282         self.reserve_node_ids(1)
283     }
284     pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler {
285         &self.parse_sess.span_diagnostic
286     }
287     pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
288         self.parse_sess.codemap()
289     }
290     pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose }
291     pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes }
292     pub fn count_llvm_insns(&self) -> bool {
293         self.opts.debugging_opts.count_llvm_insns
294     }
295     pub fn time_llvm_passes(&self) -> bool {
296         self.opts.debugging_opts.time_llvm_passes
297     }
298     pub fn trans_stats(&self) -> bool { self.opts.debugging_opts.trans_stats }
299     pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats }
300     pub fn asm_comments(&self) -> bool { self.opts.debugging_opts.asm_comments }
301     pub fn no_verify(&self) -> bool { self.opts.debugging_opts.no_verify }
302     pub fn borrowck_stats(&self) -> bool { self.opts.debugging_opts.borrowck_stats }
303     pub fn print_llvm_passes(&self) -> bool {
304         self.opts.debugging_opts.print_llvm_passes
305     }
306     pub fn lto(&self) -> bool {
307         self.opts.cg.lto
308     }
309     pub fn no_landing_pads(&self) -> bool {
310         self.opts.debugging_opts.no_landing_pads ||
311             self.opts.cg.panic == PanicStrategy::Abort
312     }
313     pub fn unstable_options(&self) -> bool {
314         self.opts.debugging_opts.unstable_options
315     }
316     pub fn nonzeroing_move_hints(&self) -> bool {
317         self.opts.debugging_opts.enable_nonzeroing_move_hints
318     }
319
320     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
321         self.opts.debuginfo != DebugInfoLevel::NoDebugInfo ||
322         !self.target.target.options.eliminate_frame_pointer
323     }
324
325     /// Returns the symbol name for the registrar function,
326     /// given the crate Svh and the function DefIndex.
327     pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex)
328                                             -> String {
329         format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize())
330     }
331
332     pub fn generate_derive_registrar_symbol(&self,
333                                             svh: &Svh,
334                                             index: DefIndex) -> String {
335         format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize())
336     }
337
338     pub fn sysroot<'a>(&'a self) -> &'a Path {
339         match self.opts.maybe_sysroot {
340             Some (ref sysroot) => sysroot,
341             None => self.default_sysroot.as_ref()
342                         .expect("missing sysroot and default_sysroot in Session")
343         }
344     }
345     pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
346         filesearch::FileSearch::new(self.sysroot(),
347                                     &self.opts.target_triple,
348                                     &self.opts.search_paths,
349                                     kind)
350     }
351     pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
352         filesearch::FileSearch::new(
353             self.sysroot(),
354             config::host_triple(),
355             &self.opts.search_paths,
356             kind)
357     }
358
359     pub fn init_incr_comp_session(&self,
360                                   session_dir: PathBuf,
361                                   lock_file: flock::Lock) {
362         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
363
364         if let IncrCompSession::NotInitialized = *incr_comp_session { } else {
365             bug!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session)
366         }
367
368         *incr_comp_session = IncrCompSession::Active {
369             session_directory: session_dir,
370             lock_file: lock_file,
371         };
372     }
373
374     pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) {
375         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
376
377         if let IncrCompSession::Active { .. } = *incr_comp_session { } else {
378             bug!("Trying to finalize IncrCompSession `{:?}`", *incr_comp_session)
379         }
380
381         // Note: This will also drop the lock file, thus unlocking the directory
382         *incr_comp_session = IncrCompSession::Finalized {
383             session_directory: new_directory_path,
384         };
385     }
386
387     pub fn mark_incr_comp_session_as_invalid(&self) {
388         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
389
390         let session_directory = match *incr_comp_session {
391             IncrCompSession::Active { ref session_directory, .. } => {
392                 session_directory.clone()
393             }
394             _ => bug!("Trying to invalidate IncrCompSession `{:?}`",
395                       *incr_comp_session),
396         };
397
398         // Note: This will also drop the lock file, thus unlocking the directory
399         *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors {
400             session_directory: session_directory
401         };
402     }
403
404     pub fn incr_comp_session_dir(&self) -> cell::Ref<PathBuf> {
405         let incr_comp_session = self.incr_comp_session.borrow();
406         cell::Ref::map(incr_comp_session, |incr_comp_session| {
407             match *incr_comp_session {
408                 IncrCompSession::NotInitialized => {
409                     bug!("Trying to get session directory from IncrCompSession `{:?}`",
410                         *incr_comp_session)
411                 }
412                 IncrCompSession::Active { ref session_directory, .. } |
413                 IncrCompSession::Finalized { ref session_directory } |
414                 IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => {
415                     session_directory
416                 }
417             }
418         })
419     }
420
421     pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<PathBuf>> {
422         if self.opts.incremental.is_some() {
423             Some(self.incr_comp_session_dir())
424         } else {
425             None
426         }
427     }
428
429     pub fn print_perf_stats(&self) {
430         println!("Total time spent computing SVHs:               {}",
431                  duration_to_secs_str(self.perf_stats.svh_time.get()));
432         println!("Total time spent computing incr. comp. hashes: {}",
433                  duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
434         println!("Total number of incr. comp. hashes computed:   {}",
435                  self.perf_stats.incr_comp_hashes_count.get());
436         println!("Total time spent computing symbol hashes:      {}",
437                  duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
438     }
439 }
440
441 pub fn build_session(sopts: config::Options,
442                      dep_graph: &DepGraph,
443                      local_crate_source_file: Option<PathBuf>,
444                      registry: errors::registry::Registry,
445                      cstore: Rc<for<'a> CrateStore<'a>>)
446                      -> Session {
447     build_session_with_codemap(sopts,
448                                dep_graph,
449                                local_crate_source_file,
450                                registry,
451                                cstore,
452                                Rc::new(codemap::CodeMap::new()))
453 }
454
455 pub fn build_session_with_codemap(sopts: config::Options,
456                                   dep_graph: &DepGraph,
457                                   local_crate_source_file: Option<PathBuf>,
458                                   registry: errors::registry::Registry,
459                                   cstore: Rc<for<'a> CrateStore<'a>>,
460                                   codemap: Rc<codemap::CodeMap>)
461                                   -> Session {
462     // FIXME: This is not general enough to make the warning lint completely override
463     // normal diagnostic warnings, since the warning lint can also be denied and changed
464     // later via the source code.
465     let can_print_warnings = sopts.lint_opts
466         .iter()
467         .filter(|&&(ref key, _)| *key == "warnings")
468         .map(|&(_, ref level)| *level != lint::Allow)
469         .last()
470         .unwrap_or(true);
471     let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
472
473     let emitter: Box<Emitter> = match sopts.error_format {
474         config::ErrorOutputType::HumanReadable(color_config) => {
475             Box::new(EmitterWriter::stderr(color_config,
476                                            Some(codemap.clone())))
477         }
478         config::ErrorOutputType::Json => {
479             Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
480         }
481     };
482
483     let diagnostic_handler =
484         errors::Handler::with_emitter(can_print_warnings,
485                                       treat_err_as_bug,
486                                       emitter);
487
488     build_session_(sopts,
489                    dep_graph,
490                    local_crate_source_file,
491                    diagnostic_handler,
492                    codemap,
493                    cstore)
494 }
495
496 pub fn build_session_(sopts: config::Options,
497                       dep_graph: &DepGraph,
498                       local_crate_source_file: Option<PathBuf>,
499                       span_diagnostic: errors::Handler,
500                       codemap: Rc<codemap::CodeMap>,
501                       cstore: Rc<for<'a> CrateStore<'a>>)
502                       -> Session {
503     let host = match Target::search(config::host_triple()) {
504         Ok(t) => t,
505         Err(e) => {
506             panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
507     }
508     };
509     let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
510     let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
511     let default_sysroot = match sopts.maybe_sysroot {
512         Some(_) => None,
513         None => Some(filesearch::get_or_default_sysroot())
514     };
515
516     // Make the path absolute, if necessary
517     let local_crate_source_file = local_crate_source_file.map(|path|
518         if path.is_absolute() {
519             path.clone()
520         } else {
521             env::current_dir().unwrap().join(&path)
522         }
523     );
524
525     let sess = Session {
526         dep_graph: dep_graph.clone(),
527         target: target_cfg,
528         host: host,
529         opts: sopts,
530         cstore: cstore,
531         parse_sess: p_s,
532         // For a library crate, this is always none
533         entry_fn: RefCell::new(None),
534         entry_type: Cell::new(None),
535         plugin_registrar_fn: Cell::new(None),
536         derive_registrar_fn: Cell::new(None),
537         default_sysroot: default_sysroot,
538         local_crate_source_file: local_crate_source_file,
539         working_dir: env::current_dir().unwrap(),
540         lint_store: RefCell::new(lint::LintStore::new()),
541         lints: RefCell::new(NodeMap()),
542         plugin_llvm_passes: RefCell::new(Vec::new()),
543         mir_passes: RefCell::new(mir_pass::Passes::new()),
544         plugin_attributes: RefCell::new(Vec::new()),
545         crate_types: RefCell::new(Vec::new()),
546         dependency_formats: RefCell::new(FnvHashMap()),
547         crate_disambiguator: RefCell::new(token::intern("").as_str()),
548         features: RefCell::new(feature_gate::Features::new()),
549         recursion_limit: Cell::new(64),
550         next_node_id: Cell::new(NodeId::new(1)),
551         injected_allocator: Cell::new(None),
552         injected_panic_runtime: Cell::new(None),
553         imported_macro_spans: RefCell::new(HashMap::new()),
554         incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
555         perf_stats: PerfStats {
556             svh_time: Cell::new(Duration::from_secs(0)),
557             incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
558             incr_comp_hashes_count: Cell::new(0),
559             symbol_hash_time: Cell::new(Duration::from_secs(0)),
560         }
561     };
562
563     init_llvm(&sess);
564
565     sess
566 }
567
568 /// Holds data on the current incremental compilation session, if there is one.
569 #[derive(Debug)]
570 pub enum IncrCompSession {
571     // This is the state the session will be in until the incr. comp. dir is
572     // needed.
573     NotInitialized,
574     // This is the state during which the session directory is private and can
575     // be modified.
576     Active {
577         session_directory: PathBuf,
578         lock_file: flock::Lock,
579     },
580     // This is the state after the session directory has been finalized. In this
581     // state, the contents of the directory must not be modified any more.
582     Finalized {
583         session_directory: PathBuf,
584     },
585     // This is an error state that is reached when some compilation error has
586     // occurred. It indicates that the contents of the session directory must
587     // not be used, since they might be invalid.
588     InvalidBecauseOfErrors {
589         session_directory: PathBuf,
590     }
591 }
592
593 fn init_llvm(sess: &Session) {
594     unsafe {
595         // Before we touch LLVM, make sure that multithreading is enabled.
596         use std::sync::Once;
597         static INIT: Once = Once::new();
598         static mut POISONED: bool = false;
599         INIT.call_once(|| {
600             if llvm::LLVMStartMultithreaded() != 1 {
601                 // use an extra bool to make sure that all future usage of LLVM
602                 // cannot proceed despite the Once not running more than once.
603                 POISONED = true;
604             }
605
606             configure_llvm(sess);
607         });
608
609         if POISONED {
610             bug!("couldn't enable multi-threaded LLVM");
611         }
612     }
613 }
614
615 unsafe fn configure_llvm(sess: &Session) {
616     let mut llvm_c_strs = Vec::new();
617     let mut llvm_args = Vec::new();
618
619     {
620         let mut add = |arg: &str| {
621             let s = CString::new(arg).unwrap();
622             llvm_args.push(s.as_ptr());
623             llvm_c_strs.push(s);
624         };
625         add("rustc"); // fake program name
626         if sess.time_llvm_passes() { add("-time-passes"); }
627         if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
628
629         for arg in &sess.opts.cg.llvm_args {
630             add(&(*arg));
631         }
632     }
633
634     llvm::LLVMInitializePasses();
635
636     llvm::initialize_available_targets();
637
638     llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
639                                  llvm_args.as_ptr());
640 }
641
642 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
643     let emitter: Box<Emitter> = match output {
644         config::ErrorOutputType::HumanReadable(color_config) => {
645             Box::new(EmitterWriter::stderr(color_config,
646                                            None))
647         }
648         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
649     };
650     let handler = errors::Handler::with_emitter(true, false, emitter);
651     handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
652     panic!(errors::FatalError);
653 }
654
655 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
656     let emitter: Box<Emitter> = match output {
657         config::ErrorOutputType::HumanReadable(color_config) => {
658             Box::new(EmitterWriter::stderr(color_config,
659                                            None))
660         }
661         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
662     };
663     let handler = errors::Handler::with_emitter(true, false, emitter);
664     handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
665 }
666
667 // Err(0) means compilation was stopped, but no errors were found.
668 // This would be better as a dedicated enum, but using try! is so convenient.
669 pub type CompileResult = Result<(), usize>;
670
671 pub fn compile_result_from_err_count(err_count: usize) -> CompileResult {
672     if err_count == 0 {
673         Ok(())
674     } else {
675         Err(err_count)
676     }
677 }
678
679 #[cold]
680 #[inline(never)]
681 pub fn bug_fmt(file: &'static str, line: u32, args: fmt::Arguments) -> ! {
682     // this wrapper mostly exists so I don't have to write a fully
683     // qualified path of None::<Span> inside the bug!() macro defintion
684     opt_span_bug_fmt(file, line, None::<Span>, args);
685 }
686
687 #[cold]
688 #[inline(never)]
689 pub fn span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
690                                         line: u32,
691                                         span: S,
692                                         args: fmt::Arguments) -> ! {
693     opt_span_bug_fmt(file, line, Some(span), args);
694 }
695
696 fn opt_span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
697                                         line: u32,
698                                         span: Option<S>,
699                                         args: fmt::Arguments) -> ! {
700     tls::with_opt(move |tcx| {
701         let msg = format!("{}:{}: {}", file, line, args);
702         match (tcx, span) {
703             (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg),
704             (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
705             (None, _) => panic!(msg)
706         }
707     });
708     unreachable!();
709 }