]> git.lizzy.rs Git - rust.git/blob - src/librustc/session/mod.rs
36dc8eabc89f2509b446ec4f3abba132e42e4641
[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 lint;
12 use middle::cstore::CrateStore;
13 use middle::dependency_format;
14 use session::search_paths::PathKind;
15 use util::nodemap::{NodeMap, FnvHashMap};
16 use mir::transform as mir_pass;
17
18 use syntax::ast::{NodeId, NodeIdAssigner, Name};
19 use syntax::codemap::{Span, MultiSpan};
20 use syntax::errors::{self, DiagnosticBuilder};
21 use syntax::errors::emitter::{Emitter, BasicEmitter, EmitterWriter};
22 use syntax::errors::json::JsonEmitter;
23 use syntax::diagnostics;
24 use syntax::feature_gate;
25 use syntax::parse;
26 use syntax::parse::ParseSess;
27 use syntax::{ast, codemap};
28 use syntax::feature_gate::AttributeType;
29
30 use rustc_back::target::Target;
31
32 use std::path::{Path, PathBuf};
33 use std::cell::{Cell, RefCell};
34 use std::collections::{HashMap, HashSet};
35 use std::env;
36 use std::rc::Rc;
37
38 pub mod config;
39 pub mod filesearch;
40 pub mod search_paths;
41
42 // Represents the data associated with a compilation
43 // session for a single crate.
44 pub struct Session {
45     pub target: config::Config,
46     pub host: Target,
47     pub opts: config::Options,
48     pub cstore: Rc<for<'a> CrateStore<'a>>,
49     pub parse_sess: ParseSess,
50     // For a library crate, this is always none
51     pub entry_fn: RefCell<Option<(NodeId, Span)>>,
52     pub entry_type: Cell<Option<config::EntryFnType>>,
53     pub plugin_registrar_fn: Cell<Option<ast::NodeId>>,
54     pub default_sysroot: Option<PathBuf>,
55     // The name of the root source file of the crate, in the local file system.
56     // The path is always expected to be absolute. `None` means that there is no
57     // source file.
58     pub local_crate_source_file: Option<PathBuf>,
59     pub working_dir: PathBuf,
60     pub lint_store: RefCell<lint::LintStore>,
61     pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
62     pub plugin_llvm_passes: RefCell<Vec<String>>,
63     pub mir_passes: RefCell<mir_pass::Passes>,
64     pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
65     pub crate_types: RefCell<Vec<config::CrateType>>,
66     pub dependency_formats: RefCell<dependency_format::Dependencies>,
67     // The crate_disambiguator is constructed out of all the `-C metadata`
68     // arguments passed to the compiler. Its value together with the crate-name
69     // forms a unique global identifier for the crate. It is used to allow
70     // multiple crates with the same name to coexist. See the
71     // trans::back::symbol_names module for more information.
72     pub crate_disambiguator: RefCell<String>,
73     pub features: RefCell<feature_gate::Features>,
74
75     /// The maximum recursion limit for potentially infinitely recursive
76     /// operations such as auto-dereference and monomorphization.
77     pub recursion_limit: Cell<usize>,
78
79     /// The metadata::creader module may inject an allocator dependency if it
80     /// didn't already find one, and this tracks what was injected.
81     pub injected_allocator: Cell<Option<ast::CrateNum>>,
82
83     /// Names of all bang-style macros and syntax extensions
84     /// available in this crate
85     pub available_macros: RefCell<HashSet<Name>>,
86
87     /// Map from imported macro spans (which consist of
88     /// the localized span for the macro body) to the
89     /// macro name and defintion span in the source crate.
90     pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>,
91
92     next_node_id: Cell<ast::NodeId>,
93 }
94
95 impl Session {
96     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
97                                                     sp: S,
98                                                     msg: &str)
99                                                     -> DiagnosticBuilder<'a>  {
100         self.diagnostic().struct_span_warn(sp, msg)
101     }
102     pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
103                                                               sp: S,
104                                                               msg: &str,
105                                                               code: &str)
106                                                               -> DiagnosticBuilder<'a>  {
107         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
108     }
109     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
110         self.diagnostic().struct_warn(msg)
111     }
112     pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
113                                                    sp: S,
114                                                    msg: &str)
115                                                    -> DiagnosticBuilder<'a>  {
116         match split_msg_into_multilines(msg) {
117             Some(ref msg) => self.diagnostic().struct_span_err(sp, msg),
118             None => self.diagnostic().struct_span_err(sp, msg),
119         }
120     }
121     pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
122                                                              sp: S,
123                                                              msg: &str,
124                                                              code: &str)
125                                                              -> DiagnosticBuilder<'a>  {
126         match split_msg_into_multilines(msg) {
127             Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code),
128             None => self.diagnostic().struct_span_err_with_code(sp, msg, code),
129         }
130     }
131     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
132         self.diagnostic().struct_err(msg)
133     }
134     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
135                                                      sp: S,
136                                                      msg: &str)
137                                                      -> DiagnosticBuilder<'a>  {
138         self.diagnostic().struct_span_fatal(sp, msg)
139     }
140     pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
141                                                                sp: S,
142                                                                msg: &str,
143                                                                code: &str)
144                                                                -> DiagnosticBuilder<'a>  {
145         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
146     }
147     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
148         self.diagnostic().struct_fatal(msg)
149     }
150
151     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
152         panic!(self.diagnostic().span_fatal(sp, msg))
153     }
154     pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) -> ! {
155         panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
156     }
157     pub fn fatal(&self, msg: &str) -> ! {
158         panic!(self.diagnostic().fatal(msg))
159     }
160     pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
161         if is_warning {
162             self.span_warn(sp, msg);
163         } else {
164             self.span_err(sp, msg);
165         }
166     }
167     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
168         match split_msg_into_multilines(msg) {
169             Some(msg) => self.diagnostic().span_err(sp, &msg),
170             None => self.diagnostic().span_err(sp, msg)
171         }
172     }
173     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
174         match split_msg_into_multilines(msg) {
175             Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code),
176             None => self.diagnostic().span_err_with_code(sp, msg, code)
177         }
178     }
179     pub fn err(&self, msg: &str) {
180         self.diagnostic().err(msg)
181     }
182     pub fn err_count(&self) -> usize {
183         self.diagnostic().err_count()
184     }
185     pub fn has_errors(&self) -> bool {
186         self.diagnostic().has_errors()
187     }
188     pub fn abort_if_errors(&self) {
189         self.diagnostic().abort_if_errors();
190     }
191     pub fn track_errors<F, T>(&self, f: F) -> Result<T, usize>
192         where F: FnOnce() -> T
193     {
194         let old_count = self.err_count();
195         let result = f();
196         let errors = self.err_count() - old_count;
197         if errors == 0 {
198             Ok(result)
199         } else {
200             Err(errors)
201         }
202     }
203     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
204         self.diagnostic().span_warn(sp, msg)
205     }
206     pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
207         self.diagnostic().span_warn_with_code(sp, msg, code)
208     }
209     pub fn warn(&self, msg: &str) {
210         self.diagnostic().warn(msg)
211     }
212     pub fn opt_span_warn<S: Into<MultiSpan>>(&self, opt_sp: Option<S>, msg: &str) {
213         match opt_sp {
214             Some(sp) => self.span_warn(sp, msg),
215             None => self.warn(msg),
216         }
217     }
218     pub fn opt_span_bug<S: Into<MultiSpan>>(&self, opt_sp: Option<S>, msg: &str) -> ! {
219         match opt_sp {
220             Some(sp) => self.span_bug(sp, msg),
221             None => self.bug(msg),
222         }
223     }
224     /// Delay a span_bug() call until abort_if_errors()
225     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
226         self.diagnostic().delay_span_bug(sp, msg)
227     }
228     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
229         self.diagnostic().span_bug(sp, msg)
230     }
231     pub fn bug(&self, msg: &str) -> ! {
232         self.diagnostic().bug(msg)
233     }
234     pub fn note_without_error(&self, msg: &str) {
235         self.diagnostic().note_without_error(msg)
236     }
237     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
238         self.diagnostic().span_note_without_error(sp, msg)
239     }
240     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
241         self.diagnostic().span_unimpl(sp, msg)
242     }
243     pub fn unimpl(&self, msg: &str) -> ! {
244         self.diagnostic().unimpl(msg)
245     }
246     pub fn add_lint(&self,
247                     lint: &'static lint::Lint,
248                     id: ast::NodeId,
249                     sp: Span,
250                     msg: String) {
251         let lint_id = lint::LintId::of(lint);
252         let mut lints = self.lints.borrow_mut();
253         match lints.get_mut(&id) {
254             Some(arr) => { arr.push((lint_id, sp, msg)); return; }
255             None => {}
256         }
257         lints.insert(id, vec!((lint_id, sp, msg)));
258     }
259     pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
260         let id = self.next_node_id.get();
261
262         match id.checked_add(count) {
263             Some(next) => self.next_node_id.set(next),
264             None => self.bug("Input too large, ran out of node ids!")
265         }
266
267         id
268     }
269     pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler {
270         &self.parse_sess.span_diagnostic
271     }
272     pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
273         self.parse_sess.codemap()
274     }
275     // This exists to help with refactoring to eliminate impossible
276     // cases later on
277     pub fn impossible_case<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
278         self.span_bug(sp, &format!("impossible case reached: {}", msg));
279     }
280     pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose }
281     pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes }
282     pub fn count_llvm_insns(&self) -> bool {
283         self.opts.debugging_opts.count_llvm_insns
284     }
285     pub fn count_type_sizes(&self) -> bool {
286         self.opts.debugging_opts.count_type_sizes
287     }
288     pub fn time_llvm_passes(&self) -> bool {
289         self.opts.debugging_opts.time_llvm_passes
290     }
291     pub fn trans_stats(&self) -> bool { self.opts.debugging_opts.trans_stats }
292     pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats }
293     pub fn asm_comments(&self) -> bool { self.opts.debugging_opts.asm_comments }
294     pub fn no_verify(&self) -> bool { self.opts.debugging_opts.no_verify }
295     pub fn borrowck_stats(&self) -> bool { self.opts.debugging_opts.borrowck_stats }
296     pub fn print_llvm_passes(&self) -> bool {
297         self.opts.debugging_opts.print_llvm_passes
298     }
299     pub fn lto(&self) -> bool {
300         self.opts.cg.lto
301     }
302     pub fn no_landing_pads(&self) -> bool {
303         self.opts.debugging_opts.no_landing_pads
304     }
305     pub fn unstable_options(&self) -> bool {
306         self.opts.debugging_opts.unstable_options
307     }
308     pub fn print_enum_sizes(&self) -> bool {
309         self.opts.debugging_opts.print_enum_sizes
310     }
311     pub fn nonzeroing_move_hints(&self) -> bool {
312         self.opts.debugging_opts.enable_nonzeroing_move_hints
313     }
314     pub fn sysroot<'a>(&'a self) -> &'a Path {
315         match self.opts.maybe_sysroot {
316             Some (ref sysroot) => sysroot,
317             None => self.default_sysroot.as_ref()
318                         .expect("missing sysroot and default_sysroot in Session")
319         }
320     }
321     pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
322         filesearch::FileSearch::new(self.sysroot(),
323                                     &self.opts.target_triple,
324                                     &self.opts.search_paths,
325                                     kind)
326     }
327     pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
328         filesearch::FileSearch::new(
329             self.sysroot(),
330             config::host_triple(),
331             &self.opts.search_paths,
332             kind)
333     }
334 }
335
336 impl NodeIdAssigner for Session {
337     fn next_node_id(&self) -> NodeId {
338         self.reserve_node_ids(1)
339     }
340
341     fn peek_node_id(&self) -> NodeId {
342         self.next_node_id.get().checked_add(1).unwrap()
343     }
344 }
345
346 fn split_msg_into_multilines(msg: &str) -> Option<String> {
347     // Conditions for enabling multi-line errors:
348     if !msg.contains("mismatched types") &&
349         !msg.contains("type mismatch resolving") &&
350         !msg.contains("if and else have incompatible types") &&
351         !msg.contains("if may be missing an else clause") &&
352         !msg.contains("match arms have incompatible types") &&
353         !msg.contains("structure constructor specifies a structure of type") &&
354         !msg.contains("has an incompatible type for trait") {
355             return None
356     }
357     let first = msg.match_indices("expected").filter(|s| {
358         s.0 > 0 && (msg.char_at_reverse(s.0) == ' ' ||
359                     msg.char_at_reverse(s.0) == '(')
360     }).map(|(a, b)| (a - 1, a + b.len()));
361     let second = msg.match_indices("found").filter(|s| {
362         msg.char_at_reverse(s.0) == ' '
363     }).map(|(a, b)| (a - 1, a + b.len()));
364
365     let mut new_msg = String::new();
366     let mut head = 0;
367
368     // Insert `\n` before expected and found.
369     for (pos1, pos2) in first.zip(second) {
370         new_msg = new_msg +
371         // A `(` may be preceded by a space and it should be trimmed
372                   msg[head..pos1.0].trim_right() + // prefix
373                   "\n" +                           // insert before first
374                   &msg[pos1.0..pos1.1] +           // insert what first matched
375                   &msg[pos1.1..pos2.0] +           // between matches
376                   "\n   " +                        // insert before second
377         //           123
378         // `expected` is 3 char longer than `found`. To align the types,
379         // `found` gets 3 spaces prepended.
380                   &msg[pos2.0..pos2.1];            // insert what second matched
381
382         head = pos2.1;
383     }
384
385     let mut tail = &msg[head..];
386     let third = tail.find("(values differ")
387                    .or(tail.find("(lifetime"))
388                    .or(tail.find("(cyclic type of infinite size"));
389     // Insert `\n` before any remaining messages which match.
390     if let Some(pos) = third {
391         // The end of the message may just be wrapped in `()` without
392         // `expected`/`found`.  Push this also to a new line and add the
393         // final tail after.
394         new_msg = new_msg +
395         // `(` is usually preceded by a space and should be trimmed.
396                   tail[..pos].trim_right() + // prefix
397                   "\n" +                     // insert before paren
398                   &tail[pos..];              // append the tail
399
400         tail = "";
401     }
402
403     new_msg.push_str(tail);
404     return Some(new_msg);
405 }
406
407 pub fn build_session(sopts: config::Options,
408                      local_crate_source_file: Option<PathBuf>,
409                      registry: diagnostics::registry::Registry,
410                      cstore: Rc<for<'a> CrateStore<'a>>)
411                      -> Session {
412     // FIXME: This is not general enough to make the warning lint completely override
413     // normal diagnostic warnings, since the warning lint can also be denied and changed
414     // later via the source code.
415     let can_print_warnings = sopts.lint_opts
416         .iter()
417         .filter(|&&(ref key, _)| *key == "warnings")
418         .map(|&(_, ref level)| *level != lint::Allow)
419         .last()
420         .unwrap_or(true);
421     let treat_err_as_bug = sopts.treat_err_as_bug;
422
423     let codemap = Rc::new(codemap::CodeMap::new());
424     let emitter: Box<Emitter> = match sopts.error_format {
425         config::ErrorOutputType::HumanReadable(color_config) => {
426             Box::new(EmitterWriter::stderr(color_config, Some(registry), codemap.clone()))
427         }
428         config::ErrorOutputType::Json => {
429             Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
430         }
431     };
432
433     let diagnostic_handler =
434         errors::Handler::with_emitter(can_print_warnings,
435                                       treat_err_as_bug,
436                                       emitter);
437
438     build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore)
439 }
440
441 pub fn build_session_(sopts: config::Options,
442                       local_crate_source_file: Option<PathBuf>,
443                       span_diagnostic: errors::Handler,
444                       codemap: Rc<codemap::CodeMap>,
445                       cstore: Rc<for<'a> CrateStore<'a>>)
446                       -> Session {
447     let host = match Target::search(config::host_triple()) {
448         Ok(t) => t,
449         Err(e) => {
450             panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
451     }
452     };
453     let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
454     let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
455     let default_sysroot = match sopts.maybe_sysroot {
456         Some(_) => None,
457         None => Some(filesearch::get_or_default_sysroot())
458     };
459
460     // Make the path absolute, if necessary
461     let local_crate_source_file = local_crate_source_file.map(|path|
462         if path.is_absolute() {
463             path.clone()
464         } else {
465             env::current_dir().unwrap().join(&path)
466         }
467     );
468
469     let sess = Session {
470         target: target_cfg,
471         host: host,
472         opts: sopts,
473         cstore: cstore,
474         parse_sess: p_s,
475         // For a library crate, this is always none
476         entry_fn: RefCell::new(None),
477         entry_type: Cell::new(None),
478         plugin_registrar_fn: Cell::new(None),
479         default_sysroot: default_sysroot,
480         local_crate_source_file: local_crate_source_file,
481         working_dir: env::current_dir().unwrap(),
482         lint_store: RefCell::new(lint::LintStore::new()),
483         lints: RefCell::new(NodeMap()),
484         plugin_llvm_passes: RefCell::new(Vec::new()),
485         mir_passes: RefCell::new(mir_pass::Passes::new()),
486         plugin_attributes: RefCell::new(Vec::new()),
487         crate_types: RefCell::new(Vec::new()),
488         dependency_formats: RefCell::new(FnvHashMap()),
489         crate_disambiguator: RefCell::new(String::new()),
490         features: RefCell::new(feature_gate::Features::new()),
491         recursion_limit: Cell::new(64),
492         next_node_id: Cell::new(1),
493         injected_allocator: Cell::new(None),
494         available_macros: RefCell::new(HashSet::new()),
495         imported_macro_spans: RefCell::new(HashMap::new()),
496     };
497
498     sess
499 }
500
501 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
502     let mut emitter: Box<Emitter> = match output {
503         config::ErrorOutputType::HumanReadable(color_config) => {
504             Box::new(BasicEmitter::stderr(color_config))
505         }
506         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
507     };
508     emitter.emit(None, msg, None, errors::Level::Fatal);
509     panic!(errors::FatalError);
510 }
511
512 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
513     let mut emitter: Box<Emitter> = match output {
514         config::ErrorOutputType::HumanReadable(color_config) => {
515             Box::new(BasicEmitter::stderr(color_config))
516         }
517         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
518     };
519     emitter.emit(None, msg, None, errors::Level::Warning);
520 }
521
522 // Err(0) means compilation was stopped, but no errors were found.
523 // This would be better as a dedicated enum, but using try! is so convenient.
524 pub type CompileResult = Result<(), usize>;
525
526 pub fn compile_result_from_err_count(err_count: usize) -> CompileResult {
527     if err_count == 0 {
528         Ok(())
529     } else {
530         Err(err_count)
531     }
532 }