]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 | //! The Rust compiler. | |
12 | //! | |
13 | //! # Note | |
14 | //! | |
15 | //! This API is completely unstable and subject to change. | |
16 | ||
17 | #![crate_name = "rustc_driver"] | |
18 | #![unstable] | |
19 | #![staged_api] | |
20 | #![crate_type = "dylib"] | |
21 | #![crate_type = "rlib"] | |
22 | #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", | |
23 | html_favicon_url = "http://www.rust-lang.org/favicon.ico", | |
24 | html_root_url = "http://doc.rust-lang.org/nightly/")] | |
25 | ||
26 | #![allow(unknown_features)] | |
27 | #![feature(quote)] | |
28 | #![feature(slicing_syntax, unsafe_destructor)] | |
29 | #![feature(box_syntax)] | |
30 | #![feature(rustc_diagnostic_macros)] | |
31 | #![allow(unknown_features)] #![feature(int_uint)] | |
32 | ||
33 | extern crate arena; | |
34 | extern crate flate; | |
35 | extern crate getopts; | |
36 | extern crate graphviz; | |
37 | extern crate libc; | |
38 | extern crate rustc; | |
39 | extern crate rustc_back; | |
40 | extern crate rustc_borrowck; | |
41 | extern crate rustc_resolve; | |
42 | extern crate rustc_trans; | |
43 | extern crate rustc_typeck; | |
44 | extern crate serialize; | |
45 | extern crate "rustc_llvm" as llvm; | |
46 | #[macro_use] extern crate log; | |
47 | #[macro_use] extern crate syntax; | |
48 | ||
49 | pub use syntax::diagnostic; | |
50 | ||
51 | use rustc_trans::back::link; | |
52 | use rustc::session::{config, Session, build_session}; | |
53 | use rustc::session::config::{Input, PrintRequest, UnstableFeatures}; | |
54 | use rustc::lint::Lint; | |
55 | use rustc::lint; | |
56 | use rustc::metadata; | |
57 | use rustc::metadata::creader::CrateOrString::Str; | |
58 | use rustc::DIAGNOSTICS; | |
59 | ||
60 | use std::cmp::Ordering::Equal; | |
61 | use std::io; | |
62 | use std::iter::repeat; | |
63 | use std::os; | |
64 | use std::sync::mpsc::channel; | |
65 | use std::thread; | |
66 | ||
67 | use rustc::session::early_error; | |
68 | ||
69 | use syntax::ast; | |
70 | use syntax::parse; | |
71 | use syntax::diagnostic::Emitter; | |
72 | use syntax::diagnostics; | |
73 | ||
74 | #[cfg(test)] | |
75 | pub mod test; | |
76 | ||
77 | pub mod driver; | |
78 | pub mod pretty; | |
79 | ||
80 | pub fn run(args: Vec<String>) -> int { | |
81 | monitor(move |:| run_compiler(args.as_slice())); | |
82 | 0 | |
83 | } | |
84 | ||
85 | static BUG_REPORT_URL: &'static str = | |
86 | "http://doc.rust-lang.org/complement-bugreport.html"; | |
87 | ||
88 | fn run_compiler(args: &[String]) { | |
89 | let matches = match handle_options(args.to_vec()) { | |
90 | Some(matches) => matches, | |
91 | None => return | |
92 | }; | |
93 | ||
94 | let descriptions = diagnostics::registry::Registry::new(&DIAGNOSTICS); | |
95 | match matches.opt_str("explain") { | |
96 | Some(ref code) => { | |
97 | match descriptions.find_description(&code[]) { | |
98 | Some(ref description) => { | |
99 | println!("{}", description); | |
100 | } | |
101 | None => { | |
102 | early_error(&format!("no extended information for {}", code)[]); | |
103 | } | |
104 | } | |
105 | return; | |
106 | }, | |
107 | None => () | |
108 | } | |
109 | ||
110 | let sopts = config::build_session_options(&matches); | |
111 | let odir = matches.opt_str("out-dir").map(|o| Path::new(o)); | |
112 | let ofile = matches.opt_str("o").map(|o| Path::new(o)); | |
113 | let (input, input_file_path) = match matches.free.len() { | |
114 | 0u => { | |
115 | if sopts.describe_lints { | |
116 | let mut ls = lint::LintStore::new(); | |
117 | ls.register_builtin(None); | |
118 | describe_lints(&ls, false); | |
119 | return; | |
120 | } | |
121 | let sess = build_session(sopts, None, descriptions); | |
122 | if print_crate_info(&sess, None, &odir, &ofile) { | |
123 | return; | |
124 | } | |
125 | early_error("no input filename given"); | |
126 | } | |
127 | 1u => { | |
128 | let ifile = &matches.free[0][]; | |
129 | if ifile == "-" { | |
130 | let contents = io::stdin().read_to_end().unwrap(); | |
131 | let src = String::from_utf8(contents).unwrap(); | |
132 | (Input::Str(src), None) | |
133 | } else { | |
134 | (Input::File(Path::new(ifile)), Some(Path::new(ifile))) | |
135 | } | |
136 | } | |
137 | _ => early_error("multiple input filenames provided") | |
138 | }; | |
139 | ||
140 | let mut sopts = sopts; | |
141 | sopts.unstable_features = get_unstable_features_setting(); | |
142 | ||
143 | let mut sess = build_session(sopts, input_file_path, descriptions); | |
144 | ||
145 | let cfg = config::build_configuration(&sess); | |
146 | if print_crate_info(&sess, Some(&input), &odir, &ofile) { | |
147 | return | |
148 | } | |
149 | ||
150 | let pretty = matches.opt_default("pretty", "normal").map(|a| { | |
151 | // stable pretty-print variants only | |
152 | pretty::parse_pretty(&sess, a.as_slice(), false) | |
153 | }); | |
154 | let pretty = if pretty.is_none() && | |
155 | sess.unstable_options() { | |
156 | matches.opt_str("xpretty").map(|a| { | |
157 | // extended with unstable pretty-print variants | |
158 | pretty::parse_pretty(&sess, a.as_slice(), true) | |
159 | }) | |
160 | } else { | |
161 | pretty | |
162 | }; | |
163 | ||
164 | match pretty.into_iter().next() { | |
165 | Some((ppm, opt_uii)) => { | |
166 | pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile); | |
167 | return; | |
168 | } | |
169 | None => {/* continue */ } | |
170 | } | |
171 | ||
172 | if sess.unstable_options() { | |
173 | sess.opts.show_span = matches.opt_str("show-span"); | |
174 | } | |
175 | ||
176 | let r = matches.opt_strs("Z"); | |
177 | if r.contains(&("ls".to_string())) { | |
178 | match input { | |
179 | Input::File(ref ifile) => { | |
180 | let mut stdout = io::stdout(); | |
181 | list_metadata(&sess, &(*ifile), &mut stdout).unwrap(); | |
182 | } | |
183 | Input::Str(_) => { | |
184 | early_error("can not list metadata for stdin"); | |
185 | } | |
186 | } | |
187 | return; | |
188 | } | |
189 | ||
190 | let plugins = sess.opts.debugging_opts.extra_plugins.clone(); | |
191 | driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins)); | |
192 | } | |
193 | ||
194 | pub fn get_unstable_features_setting() -> UnstableFeatures { | |
195 | // Whether this is a feature-staged build, i.e. on the beta or stable channel | |
196 | let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); | |
197 | // The secret key needed to get through the rustc build itself by | |
198 | // subverting the unstable features lints | |
199 | let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY"); | |
200 | // The matching key to the above, only known by the build system | |
201 | let bootstrap_provided_key = os::getenv("RUSTC_BOOTSTRAP_KEY"); | |
202 | match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) { | |
203 | (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat, | |
204 | (true, _, _) => UnstableFeatures::Disallow, | |
205 | (false, _, _) => UnstableFeatures::Default | |
206 | } | |
207 | } | |
208 | ||
209 | /// Returns a version string such as "0.12.0-dev". | |
210 | pub fn release_str() -> Option<&'static str> { | |
211 | option_env!("CFG_RELEASE") | |
212 | } | |
213 | ||
214 | /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built. | |
215 | pub fn commit_hash_str() -> Option<&'static str> { | |
216 | option_env!("CFG_VER_HASH") | |
217 | } | |
218 | ||
219 | /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string. | |
220 | pub fn commit_date_str() -> Option<&'static str> { | |
221 | option_env!("CFG_VER_DATE") | |
222 | } | |
223 | ||
224 | /// Prints version information and returns None on success or an error | |
225 | /// message on panic. | |
226 | pub fn version(binary: &str, matches: &getopts::Matches) { | |
227 | let verbose = matches.opt_present("verbose"); | |
228 | ||
229 | println!("{} {}", binary, option_env!("CFG_VERSION").unwrap_or("unknown version")); | |
230 | if verbose { | |
231 | fn unw(x: Option<&str>) -> &str { x.unwrap_or("unknown") } | |
232 | println!("binary: {}", binary); | |
233 | println!("commit-hash: {}", unw(commit_hash_str())); | |
234 | println!("commit-date: {}", unw(commit_date_str())); | |
235 | println!("host: {}", config::host_triple()); | |
236 | println!("release: {}", unw(release_str())); | |
237 | } | |
238 | } | |
239 | ||
240 | fn usage(verbose: bool, include_unstable_options: bool) { | |
241 | let groups = if verbose { | |
242 | config::rustc_optgroups() | |
243 | } else { | |
244 | config::rustc_short_optgroups() | |
245 | }; | |
246 | let groups : Vec<_> = groups.into_iter() | |
247 | .filter(|x| include_unstable_options || x.is_stable()) | |
248 | .map(|x|x.opt_group) | |
249 | .collect(); | |
250 | let message = format!("Usage: rustc [OPTIONS] INPUT"); | |
251 | let extra_help = if verbose { | |
252 | "" | |
253 | } else { | |
254 | "\n --help -v Print the full set of options rustc accepts" | |
255 | }; | |
256 | println!("{}\n\ | |
257 | Additional help: | |
258 | -C help Print codegen options | |
259 | -W help Print 'lint' options and default settings | |
260 | -Z help Print internal options for debugging rustc{}\n", | |
261 | getopts::usage(message.as_slice(), groups.as_slice()), | |
262 | extra_help); | |
263 | } | |
264 | ||
265 | fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) { | |
266 | println!(" | |
267 | Available lint options: | |
268 | -W <foo> Warn about <foo> | |
269 | -A <foo> Allow <foo> | |
270 | -D <foo> Deny <foo> | |
271 | -F <foo> Forbid <foo> (deny, and deny all overrides) | |
272 | ||
273 | "); | |
274 | ||
275 | fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> { | |
276 | let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect(); | |
277 | lints.sort_by(|x: &&Lint, y: &&Lint| { | |
278 | match x.default_level.cmp(&y.default_level) { | |
279 | // The sort doesn't case-fold but it's doubtful we care. | |
280 | Equal => x.name.cmp(y.name), | |
281 | r => r, | |
282 | } | |
283 | }); | |
284 | lints | |
285 | } | |
286 | ||
287 | fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>) | |
288 | -> Vec<(&'static str, Vec<lint::LintId>)> { | |
289 | let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect(); | |
290 | lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>), | |
291 | &(y, _): &(&'static str, Vec<lint::LintId>)| { | |
292 | x.cmp(y) | |
293 | }); | |
294 | lints | |
295 | } | |
296 | ||
297 | let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints() | |
298 | .iter().cloned().partition(|&(_, p)| p); | |
299 | let plugin = sort_lints(plugin); | |
300 | let builtin = sort_lints(builtin); | |
301 | ||
302 | let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups() | |
303 | .iter().cloned().partition(|&(_, _, p)| p); | |
304 | let plugin_groups = sort_lint_groups(plugin_groups); | |
305 | let builtin_groups = sort_lint_groups(builtin_groups); | |
306 | ||
307 | let max_name_len = plugin.iter().chain(builtin.iter()) | |
308 | .map(|&s| s.name.width(true)) | |
309 | .max().unwrap_or(0); | |
310 | let padded = |&: x: &str| { | |
311 | let mut s = repeat(" ").take(max_name_len - x.chars().count()) | |
312 | .collect::<String>(); | |
313 | s.push_str(x); | |
314 | s | |
315 | }; | |
316 | ||
317 | println!("Lint checks provided by rustc:\n"); | |
318 | println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); | |
319 | println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); | |
320 | ||
321 | let print_lints = |&: lints: Vec<&Lint>| { | |
322 | for lint in lints.into_iter() { | |
323 | let name = lint.name_lower().replace("_", "-"); | |
324 | println!(" {} {:7.7} {}", | |
325 | padded(&name[]), lint.default_level.as_str(), lint.desc); | |
326 | } | |
327 | println!("\n"); | |
328 | }; | |
329 | ||
330 | print_lints(builtin); | |
331 | ||
332 | ||
333 | ||
334 | let max_name_len = plugin_groups.iter().chain(builtin_groups.iter()) | |
335 | .map(|&(s, _)| s.width(true)) | |
336 | .max().unwrap_or(0); | |
337 | let padded = |&: x: &str| { | |
338 | let mut s = repeat(" ").take(max_name_len - x.chars().count()) | |
339 | .collect::<String>(); | |
340 | s.push_str(x); | |
341 | s | |
342 | }; | |
343 | ||
344 | println!("Lint groups provided by rustc:\n"); | |
345 | println!(" {} {}", padded("name"), "sub-lints"); | |
346 | println!(" {} {}", padded("----"), "---------"); | |
347 | ||
348 | let print_lint_groups = |&: lints: Vec<(&'static str, Vec<lint::LintId>)>| { | |
349 | for (name, to) in lints.into_iter() { | |
350 | let name = name.chars().map(|x| x.to_lowercase()) | |
351 | .collect::<String>().replace("_", "-"); | |
352 | let desc = to.into_iter().map(|x| x.as_str().replace("_", "-")) | |
353 | .collect::<Vec<String>>().connect(", "); | |
354 | println!(" {} {}", | |
355 | padded(&name[]), desc); | |
356 | } | |
357 | println!("\n"); | |
358 | }; | |
359 | ||
360 | print_lint_groups(builtin_groups); | |
361 | ||
362 | match (loaded_plugins, plugin.len(), plugin_groups.len()) { | |
363 | (false, 0, _) | (false, _, 0) => { | |
364 | println!("Compiler plugins can provide additional lints and lint groups. To see a \ | |
365 | listing of these, re-run `rustc -W help` with a crate filename."); | |
366 | } | |
367 | (false, _, _) => panic!("didn't load lint plugins but got them anyway!"), | |
368 | (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), | |
369 | (true, l, g) => { | |
370 | if l > 0 { | |
371 | println!("Lint checks provided by plugins loaded by this crate:\n"); | |
372 | print_lints(plugin); | |
373 | } | |
374 | if g > 0 { | |
375 | println!("Lint groups provided by plugins loaded by this crate:\n"); | |
376 | print_lint_groups(plugin_groups); | |
377 | } | |
378 | } | |
379 | } | |
380 | } | |
381 | ||
382 | fn describe_debug_flags() { | |
383 | println!("\nAvailable debug options:\n"); | |
384 | for &(name, _, opt_type_desc, desc) in config::DB_OPTIONS.iter() { | |
385 | let (width, extra) = match opt_type_desc { | |
386 | Some(..) => (21, "=val"), | |
387 | None => (25, "") | |
388 | }; | |
389 | println!(" -Z {:>width$}{} -- {}", name.replace("_", "-"), | |
390 | extra, desc, width=width); | |
391 | } | |
392 | } | |
393 | ||
394 | fn describe_codegen_flags() { | |
395 | println!("\nAvailable codegen options:\n"); | |
396 | for &(name, _, opt_type_desc, desc) in config::CG_OPTIONS.iter() { | |
397 | let (width, extra) = match opt_type_desc { | |
398 | Some(..) => (21, "=val"), | |
399 | None => (25, "") | |
400 | }; | |
401 | println!(" -C {:>width$}{} -- {}", name.replace("_", "-"), | |
402 | extra, desc, width=width); | |
403 | } | |
404 | } | |
405 | ||
406 | /// Process command line options. Emits messages as appropriate. If compilation | |
407 | /// should continue, returns a getopts::Matches object parsed from args, otherwise | |
408 | /// returns None. | |
409 | pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> { | |
410 | // Throw away the first argument, the name of the binary | |
411 | let _binary = args.remove(0); | |
412 | ||
413 | if args.is_empty() { | |
414 | // user did not write `-v` nor `-Z unstable-options`, so do not | |
415 | // include that extra information. | |
416 | usage(false, false); | |
417 | return None; | |
418 | } | |
419 | ||
420 | let matches = | |
421 | match getopts::getopts(&args[], &config::optgroups()[]) { | |
422 | Ok(m) => m, | |
423 | Err(f_stable_attempt) => { | |
424 | // redo option parsing, including unstable options this time, | |
425 | // in anticipation that the mishandled option was one of the | |
426 | // unstable ones. | |
427 | let all_groups : Vec<getopts::OptGroup> | |
428 | = config::rustc_optgroups().into_iter().map(|x|x.opt_group).collect(); | |
429 | match getopts::getopts(args.as_slice(), all_groups.as_slice()) { | |
430 | Ok(m_unstable) => { | |
431 | let r = m_unstable.opt_strs("Z"); | |
432 | let include_unstable_options = r.iter().any(|x| *x == "unstable-options"); | |
433 | if include_unstable_options { | |
434 | m_unstable | |
435 | } else { | |
436 | early_error(f_stable_attempt.to_string().as_slice()); | |
437 | } | |
438 | } | |
439 | Err(_) => { | |
440 | // ignore the error from the unstable attempt; just | |
441 | // pass the error we got from the first try. | |
442 | early_error(f_stable_attempt.to_string().as_slice()); | |
443 | } | |
444 | } | |
445 | } | |
446 | }; | |
447 | ||
448 | let r = matches.opt_strs("Z"); | |
449 | let include_unstable_options = r.iter().any(|x| *x == "unstable-options"); | |
450 | ||
451 | if matches.opt_present("h") || matches.opt_present("help") { | |
452 | usage(matches.opt_present("verbose"), include_unstable_options); | |
453 | return None; | |
454 | } | |
455 | ||
456 | // Don't handle -W help here, because we might first load plugins. | |
457 | ||
458 | let r = matches.opt_strs("Z"); | |
459 | if r.iter().any(|x| *x == "help") { | |
460 | describe_debug_flags(); | |
461 | return None; | |
462 | } | |
463 | ||
464 | let cg_flags = matches.opt_strs("C"); | |
465 | if cg_flags.iter().any(|x| *x == "help") { | |
466 | describe_codegen_flags(); | |
467 | return None; | |
468 | } | |
469 | ||
470 | if cg_flags.contains(&"passes=list".to_string()) { | |
471 | unsafe { ::llvm::LLVMRustPrintPasses(); } | |
472 | return None; | |
473 | } | |
474 | ||
475 | if matches.opt_present("version") { | |
476 | version("rustc", &matches); | |
477 | return None; | |
478 | } | |
479 | ||
480 | Some(matches) | |
481 | } | |
482 | ||
483 | fn print_crate_info(sess: &Session, | |
484 | input: Option<&Input>, | |
485 | odir: &Option<Path>, | |
486 | ofile: &Option<Path>) | |
487 | -> bool { | |
488 | if sess.opts.prints.len() == 0 { return false } | |
489 | ||
490 | let attrs = input.map(|input| parse_crate_attrs(sess, input)); | |
491 | for req in sess.opts.prints.iter() { | |
492 | match *req { | |
493 | PrintRequest::Sysroot => println!("{}", sess.sysroot().display()), | |
494 | PrintRequest::FileNames | | |
495 | PrintRequest::CrateName => { | |
496 | let input = match input { | |
497 | Some(input) => input, | |
498 | None => early_error("no input file provided"), | |
499 | }; | |
500 | let attrs = attrs.as_ref().unwrap().as_slice(); | |
501 | let t_outputs = driver::build_output_filenames(input, | |
502 | odir, | |
503 | ofile, | |
504 | attrs, | |
505 | sess); | |
506 | let id = link::find_crate_name(Some(sess), attrs.as_slice(), | |
507 | input); | |
508 | if *req == PrintRequest::CrateName { | |
509 | println!("{}", id); | |
510 | continue | |
511 | } | |
512 | let crate_types = driver::collect_crate_types(sess, attrs); | |
513 | let metadata = driver::collect_crate_metadata(sess, attrs); | |
514 | *sess.crate_metadata.borrow_mut() = metadata; | |
515 | for &style in crate_types.iter() { | |
516 | let fname = link::filename_for_input(sess, style, | |
517 | id.as_slice(), | |
518 | &t_outputs.with_extension("")); | |
519 | println!("{}", fname.filename_display()); | |
520 | } | |
521 | } | |
522 | } | |
523 | } | |
524 | return true; | |
525 | } | |
526 | ||
527 | fn parse_crate_attrs(sess: &Session, input: &Input) -> | |
528 | Vec<ast::Attribute> { | |
529 | let result = match *input { | |
530 | Input::File(ref ifile) => { | |
531 | parse::parse_crate_attrs_from_file(ifile, | |
532 | Vec::new(), | |
533 | &sess.parse_sess) | |
534 | } | |
535 | Input::Str(ref src) => { | |
536 | parse::parse_crate_attrs_from_source_str( | |
537 | driver::anon_src().to_string(), | |
538 | src.to_string(), | |
539 | Vec::new(), | |
540 | &sess.parse_sess) | |
541 | } | |
542 | }; | |
543 | result.into_iter().collect() | |
544 | } | |
545 | ||
546 | pub fn list_metadata(sess: &Session, path: &Path, | |
547 | out: &mut io::Writer) -> io::IoResult<()> { | |
548 | metadata::loader::list_file_metadata(sess.target.target.options.is_like_osx, path, out) | |
549 | } | |
550 | ||
551 | /// Run a procedure which will detect panics in the compiler and print nicer | |
552 | /// error messages rather than just failing the test. | |
553 | /// | |
554 | /// The diagnostic emitter yielded to the procedure should be used for reporting | |
555 | /// errors of the compiler. | |
556 | pub fn monitor<F:FnOnce()+Send>(f: F) { | |
557 | static STACK_SIZE: uint = 8 * 1024 * 1024; // 8MB | |
558 | ||
559 | let (tx, rx) = channel(); | |
560 | let w = io::ChanWriter::new(tx); | |
561 | let mut r = io::ChanReader::new(rx); | |
562 | ||
563 | let mut cfg = thread::Builder::new().name("rustc".to_string()); | |
564 | ||
565 | // FIXME: Hacks on hacks. If the env is trying to override the stack size | |
566 | // then *don't* set it explicitly. | |
567 | if os::getenv("RUST_MIN_STACK").is_none() { | |
568 | cfg = cfg.stack_size(STACK_SIZE); | |
569 | } | |
570 | ||
571 | match cfg.scoped(move || { std::io::stdio::set_stderr(box w); f() }).join() { | |
572 | Ok(()) => { /* fallthrough */ } | |
573 | Err(value) => { | |
574 | // Thread panicked without emitting a fatal diagnostic | |
575 | if !value.is::<diagnostic::FatalError>() { | |
576 | let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); | |
577 | ||
578 | // a .span_bug or .bug call has already printed what | |
579 | // it wants to print. | |
580 | if !value.is::<diagnostic::ExplicitBug>() { | |
581 | emitter.emit( | |
582 | None, | |
583 | "unexpected panic", | |
584 | None, | |
585 | diagnostic::Bug); | |
586 | } | |
587 | ||
588 | let xs = [ | |
589 | "the compiler unexpectedly panicked. this is a bug.".to_string(), | |
590 | format!("we would appreciate a bug report: {}", | |
591 | BUG_REPORT_URL), | |
592 | "run with `RUST_BACKTRACE=1` for a backtrace".to_string(), | |
593 | ]; | |
594 | for note in xs.iter() { | |
595 | emitter.emit(None, ¬e[], None, diagnostic::Note) | |
596 | } | |
597 | ||
598 | match r.read_to_string() { | |
599 | Ok(s) => println!("{}", s), | |
600 | Err(e) => { | |
601 | emitter.emit(None, | |
602 | &format!("failed to read internal \ | |
603 | stderr: {}", e)[], | |
604 | None, | |
605 | diagnostic::Error) | |
606 | } | |
607 | } | |
608 | } | |
609 | ||
610 | // Panic so the process returns a failure code, but don't pollute the | |
611 | // output with some unnecessary panic messages, we've already | |
612 | // printed everything that we needed to. | |
613 | io::stdio::set_stderr(box io::util::NullWriter); | |
614 | panic!(); | |
615 | } | |
616 | } | |
617 | } | |
618 | ||
619 | pub fn main() { | |
620 | let args = std::os::args(); | |
621 | let result = run(args); | |
622 | std::os::set_exit_status(result); | |
623 | } |