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