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