]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
1a4d82fc JJ |
11 | use lint; |
12 | use metadata::cstore::CStore; | |
13 | use metadata::filesearch; | |
14 | use session::search_paths::PathKind; | |
15 | use util::nodemap::NodeMap; | |
16 | ||
17 | use syntax::ast::NodeId; | |
18 | use syntax::codemap::Span; | |
19 | use syntax::diagnostic::{self, Emitter}; | |
20 | use syntax::diagnostics; | |
21 | use syntax::feature_gate; | |
22 | use syntax::parse; | |
23 | use syntax::parse::token; | |
24 | use syntax::parse::ParseSess; | |
25 | use syntax::{ast, codemap}; | |
26 | ||
85aaf69f SL |
27 | use rustc_back::target::Target; |
28 | ||
c34b1796 | 29 | use std::path::{Path, PathBuf}; |
1a4d82fc | 30 | use std::cell::{Cell, RefCell}; |
c34b1796 | 31 | use std::env; |
1a4d82fc JJ |
32 | |
33 | pub mod config; | |
34 | pub mod search_paths; | |
35 | ||
36 | // Represents the data associated with a compilation | |
37 | // session for a single crate. | |
38 | pub struct Session { | |
39 | pub target: config::Config, | |
85aaf69f | 40 | pub host: Target, |
1a4d82fc JJ |
41 | pub opts: config::Options, |
42 | pub cstore: CStore, | |
43 | pub parse_sess: ParseSess, | |
44 | // For a library crate, this is always none | |
45 | pub entry_fn: RefCell<Option<(NodeId, codemap::Span)>>, | |
46 | pub entry_type: Cell<Option<config::EntryFnType>>, | |
47 | pub plugin_registrar_fn: Cell<Option<ast::NodeId>>, | |
c34b1796 | 48 | pub default_sysroot: Option<PathBuf>, |
1a4d82fc JJ |
49 | // The name of the root source file of the crate, in the local file system. The path is always |
50 | // expected to be absolute. `None` means that there is no source file. | |
c34b1796 AL |
51 | pub local_crate_source_file: Option<PathBuf>, |
52 | pub working_dir: PathBuf, | |
1a4d82fc JJ |
53 | pub lint_store: RefCell<lint::LintStore>, |
54 | pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>, | |
9346a6ac | 55 | pub plugin_llvm_passes: RefCell<Vec<String>>, |
1a4d82fc JJ |
56 | pub crate_types: RefCell<Vec<config::CrateType>>, |
57 | pub crate_metadata: RefCell<Vec<String>>, | |
58 | pub features: RefCell<feature_gate::Features>, | |
59 | ||
60 | /// The maximum recursion limit for potentially infinitely recursive | |
61 | /// operations such as auto-dereference and monomorphization. | |
c34b1796 | 62 | pub recursion_limit: Cell<usize>, |
1a4d82fc JJ |
63 | |
64 | pub can_print_warnings: bool | |
65 | } | |
66 | ||
67 | impl Session { | |
68 | pub fn span_fatal(&self, sp: Span, msg: &str) -> ! { | |
c34b1796 AL |
69 | if self.opts.treat_err_as_bug { |
70 | self.span_bug(sp, msg); | |
71 | } | |
9346a6ac | 72 | panic!(self.diagnostic().span_fatal(sp, msg)) |
1a4d82fc | 73 | } |
85aaf69f | 74 | pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! { |
c34b1796 AL |
75 | if self.opts.treat_err_as_bug { |
76 | self.span_bug(sp, msg); | |
77 | } | |
9346a6ac | 78 | panic!(self.diagnostic().span_fatal_with_code(sp, msg, code)) |
85aaf69f | 79 | } |
1a4d82fc | 80 | pub fn fatal(&self, msg: &str) -> ! { |
c34b1796 AL |
81 | if self.opts.treat_err_as_bug { |
82 | self.bug(msg); | |
83 | } | |
1a4d82fc JJ |
84 | self.diagnostic().handler().fatal(msg) |
85 | } | |
86 | pub fn span_err(&self, sp: Span, msg: &str) { | |
c34b1796 AL |
87 | if self.opts.treat_err_as_bug { |
88 | self.span_bug(sp, msg); | |
89 | } | |
85aaf69f SL |
90 | match split_msg_into_multilines(msg) { |
91 | Some(msg) => self.diagnostic().span_err(sp, &msg[..]), | |
92 | None => self.diagnostic().span_err(sp, msg) | |
93 | } | |
1a4d82fc JJ |
94 | } |
95 | pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { | |
c34b1796 AL |
96 | if self.opts.treat_err_as_bug { |
97 | self.span_bug(sp, msg); | |
98 | } | |
85aaf69f SL |
99 | match split_msg_into_multilines(msg) { |
100 | Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code), | |
101 | None => self.diagnostic().span_err_with_code(sp, msg, code) | |
102 | } | |
1a4d82fc JJ |
103 | } |
104 | pub fn err(&self, msg: &str) { | |
c34b1796 AL |
105 | if self.opts.treat_err_as_bug { |
106 | self.bug(msg); | |
107 | } | |
1a4d82fc JJ |
108 | self.diagnostic().handler().err(msg) |
109 | } | |
c34b1796 | 110 | pub fn err_count(&self) -> usize { |
1a4d82fc JJ |
111 | self.diagnostic().handler().err_count() |
112 | } | |
113 | pub fn has_errors(&self) -> bool { | |
114 | self.diagnostic().handler().has_errors() | |
115 | } | |
116 | pub fn abort_if_errors(&self) { | |
117 | self.diagnostic().handler().abort_if_errors() | |
118 | } | |
119 | pub fn span_warn(&self, sp: Span, msg: &str) { | |
120 | if self.can_print_warnings { | |
121 | self.diagnostic().span_warn(sp, msg) | |
122 | } | |
123 | } | |
124 | pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) { | |
125 | if self.can_print_warnings { | |
126 | self.diagnostic().span_warn_with_code(sp, msg, code) | |
127 | } | |
128 | } | |
129 | pub fn warn(&self, msg: &str) { | |
130 | if self.can_print_warnings { | |
131 | self.diagnostic().handler().warn(msg) | |
132 | } | |
133 | } | |
134 | pub fn opt_span_warn(&self, opt_sp: Option<Span>, msg: &str) { | |
135 | match opt_sp { | |
136 | Some(sp) => self.span_warn(sp, msg), | |
137 | None => self.warn(msg), | |
138 | } | |
139 | } | |
140 | pub fn span_note(&self, sp: Span, msg: &str) { | |
141 | self.diagnostic().span_note(sp, msg) | |
142 | } | |
143 | pub fn span_end_note(&self, sp: Span, msg: &str) { | |
144 | self.diagnostic().span_end_note(sp, msg) | |
145 | } | |
9346a6ac AL |
146 | |
147 | /// Prints out a message with a suggested edit of the code. | |
148 | /// | |
149 | /// See `diagnostic::RenderSpan::Suggestion` for more information. | |
150 | pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { | |
151 | self.diagnostic().span_suggestion(sp, msg, suggestion) | |
152 | } | |
1a4d82fc JJ |
153 | pub fn span_help(&self, sp: Span, msg: &str) { |
154 | self.diagnostic().span_help(sp, msg) | |
155 | } | |
156 | pub fn fileline_note(&self, sp: Span, msg: &str) { | |
157 | self.diagnostic().fileline_note(sp, msg) | |
158 | } | |
85aaf69f SL |
159 | pub fn fileline_help(&self, sp: Span, msg: &str) { |
160 | self.diagnostic().fileline_help(sp, msg) | |
161 | } | |
1a4d82fc JJ |
162 | pub fn note(&self, msg: &str) { |
163 | self.diagnostic().handler().note(msg) | |
164 | } | |
165 | pub fn help(&self, msg: &str) { | |
9346a6ac | 166 | self.diagnostic().handler().help(msg) |
1a4d82fc JJ |
167 | } |
168 | pub fn opt_span_bug(&self, opt_sp: Option<Span>, msg: &str) -> ! { | |
169 | match opt_sp { | |
170 | Some(sp) => self.span_bug(sp, msg), | |
171 | None => self.bug(msg), | |
172 | } | |
173 | } | |
174 | pub fn span_bug(&self, sp: Span, msg: &str) -> ! { | |
175 | self.diagnostic().span_bug(sp, msg) | |
176 | } | |
177 | pub fn bug(&self, msg: &str) -> ! { | |
178 | self.diagnostic().handler().bug(msg) | |
179 | } | |
180 | pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { | |
181 | self.diagnostic().span_unimpl(sp, msg) | |
182 | } | |
183 | pub fn unimpl(&self, msg: &str) -> ! { | |
184 | self.diagnostic().handler().unimpl(msg) | |
185 | } | |
186 | pub fn add_lint(&self, | |
187 | lint: &'static lint::Lint, | |
188 | id: ast::NodeId, | |
189 | sp: Span, | |
190 | msg: String) { | |
191 | let lint_id = lint::LintId::of(lint); | |
192 | let mut lints = self.lints.borrow_mut(); | |
193 | match lints.get_mut(&id) { | |
194 | Some(arr) => { arr.push((lint_id, sp, msg)); return; } | |
195 | None => {} | |
196 | } | |
197 | lints.insert(id, vec!((lint_id, sp, msg))); | |
198 | } | |
199 | pub fn next_node_id(&self) -> ast::NodeId { | |
200 | self.parse_sess.next_node_id() | |
201 | } | |
202 | pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId { | |
203 | self.parse_sess.reserve_node_ids(count) | |
204 | } | |
205 | pub fn diagnostic<'a>(&'a self) -> &'a diagnostic::SpanHandler { | |
206 | &self.parse_sess.span_diagnostic | |
207 | } | |
208 | pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap { | |
209 | &self.parse_sess.span_diagnostic.cm | |
210 | } | |
211 | // This exists to help with refactoring to eliminate impossible | |
212 | // cases later on | |
213 | pub fn impossible_case(&self, sp: Span, msg: &str) -> ! { | |
214 | self.span_bug(sp, | |
c34b1796 | 215 | &format!("impossible case reached: {}", msg)); |
1a4d82fc JJ |
216 | } |
217 | pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose } | |
218 | pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes } | |
219 | pub fn count_llvm_insns(&self) -> bool { | |
220 | self.opts.debugging_opts.count_llvm_insns | |
221 | } | |
222 | pub fn count_type_sizes(&self) -> bool { | |
223 | self.opts.debugging_opts.count_type_sizes | |
224 | } | |
225 | pub fn time_llvm_passes(&self) -> bool { | |
226 | self.opts.debugging_opts.time_llvm_passes | |
227 | } | |
228 | pub fn trans_stats(&self) -> bool { self.opts.debugging_opts.trans_stats } | |
229 | pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats } | |
230 | pub fn asm_comments(&self) -> bool { self.opts.debugging_opts.asm_comments } | |
231 | pub fn no_verify(&self) -> bool { self.opts.debugging_opts.no_verify } | |
232 | pub fn borrowck_stats(&self) -> bool { self.opts.debugging_opts.borrowck_stats } | |
233 | pub fn print_llvm_passes(&self) -> bool { | |
234 | self.opts.debugging_opts.print_llvm_passes | |
235 | } | |
236 | pub fn lto(&self) -> bool { | |
237 | self.opts.cg.lto | |
238 | } | |
239 | pub fn no_landing_pads(&self) -> bool { | |
240 | self.opts.debugging_opts.no_landing_pads | |
241 | } | |
242 | pub fn unstable_options(&self) -> bool { | |
243 | self.opts.debugging_opts.unstable_options | |
244 | } | |
245 | pub fn print_enum_sizes(&self) -> bool { | |
246 | self.opts.debugging_opts.print_enum_sizes | |
247 | } | |
248 | pub fn sysroot<'a>(&'a self) -> &'a Path { | |
249 | match self.opts.maybe_sysroot { | |
250 | Some (ref sysroot) => sysroot, | |
251 | None => self.default_sysroot.as_ref() | |
252 | .expect("missing sysroot and default_sysroot in Session") | |
253 | } | |
254 | } | |
255 | pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch { | |
256 | filesearch::FileSearch::new(self.sysroot(), | |
c34b1796 | 257 | &self.opts.target_triple, |
1a4d82fc JJ |
258 | &self.opts.search_paths, |
259 | kind) | |
260 | } | |
261 | pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch { | |
262 | filesearch::FileSearch::new( | |
263 | self.sysroot(), | |
264 | config::host_triple(), | |
265 | &self.opts.search_paths, | |
266 | kind) | |
267 | } | |
268 | } | |
269 | ||
85aaf69f SL |
270 | fn split_msg_into_multilines(msg: &str) -> Option<String> { |
271 | // Conditions for enabling multi-line errors: | |
272 | if !msg.contains("mismatched types") && | |
273 | !msg.contains("type mismatch resolving") && | |
274 | !msg.contains("if and else have incompatible types") && | |
275 | !msg.contains("if may be missing an else clause") && | |
276 | !msg.contains("match arms have incompatible types") && | |
277 | !msg.contains("structure constructor specifies a structure of type") { | |
278 | return None | |
279 | } | |
280 | let first = msg.match_indices("expected").filter(|s| { | |
281 | s.0 > 0 && (msg.char_at_reverse(s.0) == ' ' || | |
282 | msg.char_at_reverse(s.0) == '(') | |
283 | }).map(|(a, b)| (a - 1, b)); | |
284 | let second = msg.match_indices("found").filter(|s| { | |
285 | msg.char_at_reverse(s.0) == ' ' | |
286 | }).map(|(a, b)| (a - 1, b)); | |
287 | ||
288 | let mut new_msg = String::new(); | |
289 | let mut head = 0; | |
290 | ||
291 | // Insert `\n` before expected and found. | |
292 | for (pos1, pos2) in first.zip(second) { | |
293 | new_msg = new_msg + | |
294 | // A `(` may be preceded by a space and it should be trimmed | |
295 | msg[head..pos1.0].trim_right() + // prefix | |
296 | "\n" + // insert before first | |
297 | &msg[pos1.0..pos1.1] + // insert what first matched | |
298 | &msg[pos1.1..pos2.0] + // between matches | |
299 | "\n " + // insert before second | |
300 | // 123 | |
301 | // `expected` is 3 char longer than `found`. To align the types, | |
302 | // `found` gets 3 spaces prepended. | |
303 | &msg[pos2.0..pos2.1]; // insert what second matched | |
304 | ||
305 | head = pos2.1; | |
306 | } | |
307 | ||
308 | let mut tail = &msg[head..]; | |
c34b1796 AL |
309 | let third = tail.find("(values differ") |
310 | .or(tail.find("(lifetime")) | |
311 | .or(tail.find("(cyclic type of infinite size")); | |
85aaf69f SL |
312 | // Insert `\n` before any remaining messages which match. |
313 | if let Some(pos) = third { | |
314 | // The end of the message may just be wrapped in `()` without | |
315 | // `expected`/`found`. Push this also to a new line and add the | |
316 | // final tail after. | |
317 | new_msg = new_msg + | |
318 | // `(` is usually preceded by a space and should be trimmed. | |
319 | tail[..pos].trim_right() + // prefix | |
320 | "\n" + // insert before paren | |
321 | &tail[pos..]; // append the tail | |
322 | ||
323 | tail = ""; | |
324 | } | |
325 | ||
326 | new_msg.push_str(tail); | |
327 | return Some(new_msg); | |
328 | } | |
329 | ||
1a4d82fc | 330 | pub fn build_session(sopts: config::Options, |
c34b1796 | 331 | local_crate_source_file: Option<PathBuf>, |
1a4d82fc JJ |
332 | registry: diagnostics::registry::Registry) |
333 | -> Session { | |
85aaf69f SL |
334 | // FIXME: This is not general enough to make the warning lint completely override |
335 | // normal diagnostic warnings, since the warning lint can also be denied and changed | |
336 | // later via the source code. | |
337 | let can_print_warnings = sopts.lint_opts | |
338 | .iter() | |
339 | .filter(|&&(ref key, _)| *key == "warnings") | |
340 | .map(|&(_, ref level)| *level != lint::Allow) | |
341 | .last() | |
342 | .unwrap_or(true); | |
343 | ||
1a4d82fc JJ |
344 | let codemap = codemap::CodeMap::new(); |
345 | let diagnostic_handler = | |
85aaf69f | 346 | diagnostic::default_handler(sopts.color, Some(registry), can_print_warnings); |
1a4d82fc JJ |
347 | let span_diagnostic_handler = |
348 | diagnostic::mk_span_handler(diagnostic_handler, codemap); | |
349 | ||
350 | build_session_(sopts, local_crate_source_file, span_diagnostic_handler) | |
351 | } | |
352 | ||
353 | pub fn build_session_(sopts: config::Options, | |
c34b1796 | 354 | local_crate_source_file: Option<PathBuf>, |
1a4d82fc JJ |
355 | span_diagnostic: diagnostic::SpanHandler) |
356 | -> Session { | |
85aaf69f SL |
357 | let host = match Target::search(config::host_triple()) { |
358 | Ok(t) => t, | |
359 | Err(e) => { | |
360 | span_diagnostic.handler() | |
361 | .fatal(&format!("Error loading host specification: {}", e)); | |
362 | } | |
363 | }; | |
1a4d82fc JJ |
364 | let target_cfg = config::build_target_config(&sopts, &span_diagnostic); |
365 | let p_s = parse::new_parse_sess_special_handler(span_diagnostic); | |
366 | let default_sysroot = match sopts.maybe_sysroot { | |
367 | Some(_) => None, | |
368 | None => Some(filesearch::get_or_default_sysroot()) | |
369 | }; | |
370 | ||
371 | // Make the path absolute, if necessary | |
372 | let local_crate_source_file = local_crate_source_file.map(|path| | |
373 | if path.is_absolute() { | |
374 | path.clone() | |
375 | } else { | |
85aaf69f | 376 | env::current_dir().unwrap().join(&path) |
1a4d82fc JJ |
377 | } |
378 | ); | |
379 | ||
380 | let can_print_warnings = sopts.lint_opts | |
381 | .iter() | |
382 | .filter(|&&(ref key, _)| *key == "warnings") | |
383 | .map(|&(_, ref level)| *level != lint::Allow) | |
384 | .last() | |
385 | .unwrap_or(true); | |
386 | ||
387 | let sess = Session { | |
388 | target: target_cfg, | |
85aaf69f | 389 | host: host, |
1a4d82fc JJ |
390 | opts: sopts, |
391 | cstore: CStore::new(token::get_ident_interner()), | |
392 | parse_sess: p_s, | |
393 | // For a library crate, this is always none | |
394 | entry_fn: RefCell::new(None), | |
395 | entry_type: Cell::new(None), | |
396 | plugin_registrar_fn: Cell::new(None), | |
397 | default_sysroot: default_sysroot, | |
398 | local_crate_source_file: local_crate_source_file, | |
85aaf69f | 399 | working_dir: env::current_dir().unwrap(), |
1a4d82fc | 400 | lint_store: RefCell::new(lint::LintStore::new()), |
85aaf69f | 401 | lints: RefCell::new(NodeMap()), |
9346a6ac | 402 | plugin_llvm_passes: RefCell::new(Vec::new()), |
1a4d82fc JJ |
403 | crate_types: RefCell::new(Vec::new()), |
404 | crate_metadata: RefCell::new(Vec::new()), | |
405 | features: RefCell::new(feature_gate::Features::new()), | |
406 | recursion_limit: Cell::new(64), | |
407 | can_print_warnings: can_print_warnings | |
408 | }; | |
409 | ||
1a4d82fc JJ |
410 | sess |
411 | } | |
412 | ||
413 | // Seems out of place, but it uses session, so I'm putting it here | |
414 | pub fn expect<T, M>(sess: &Session, opt: Option<T>, msg: M) -> T where | |
415 | M: FnOnce() -> String, | |
416 | { | |
417 | diagnostic::expect(sess.diagnostic(), opt, msg) | |
418 | } | |
419 | ||
420 | pub fn early_error(msg: &str) -> ! { | |
421 | let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); | |
422 | emitter.emit(None, msg, None, diagnostic::Fatal); | |
423 | panic!(diagnostic::FatalError); | |
424 | } | |
425 | ||
426 | pub fn early_warn(msg: &str) { | |
427 | let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); | |
428 | emitter.emit(None, msg, None, diagnostic::Warning); | |
429 | } |