提交 71f39c1a 编写于 作者: B Barosl Lee

Respect `--color` when printing early errors

Currently, `early_error` and `early_warn` in `librustc::session` always
use `ColorConfig::Auto`. Modify them to follow the color configuration
set by the `--color` option.

As colored output is also printed during the early stage, parsing the
`--color` option should be done as early as possible. However, there are
still some cases when the output needs to be colored before knowing the
exact color settings. In these cases, it will be defaulted to
`ColorConfig::Auto`, which is the same as before.

Fixes #27879.
上级 e195aa84
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
use syntax::visit::{Visitor, FnKind}; use syntax::visit::{Visitor, FnKind};
use syntax::parse::token::InternedString; use syntax::parse::token::InternedString;
use syntax::{ast, ast_util, visit}; use syntax::{ast, ast_util, visit};
use syntax::diagnostic;
/// Information about the registered lints. /// Information about the registered lints.
/// ///
...@@ -141,7 +142,7 @@ pub fn register_pass(&mut self, sess: Option<&Session>, ...@@ -141,7 +142,7 @@ pub fn register_pass(&mut self, sess: Option<&Session>,
match (sess, from_plugin) { match (sess, from_plugin) {
// We load builtin lints first, so a duplicate is a compiler bug. // We load builtin lints first, so a duplicate is a compiler bug.
// Use early_error when handling -W help with no crate. // Use early_error when handling -W help with no crate.
(None, _) => early_error(&msg[..]), (None, _) => early_error(diagnostic::Auto, &msg[..]),
(Some(sess), false) => sess.bug(&msg[..]), (Some(sess), false) => sess.bug(&msg[..]),
// A duplicate name from a plugin is a user error. // A duplicate name from a plugin is a user error.
...@@ -166,7 +167,7 @@ pub fn register_group(&mut self, sess: Option<&Session>, ...@@ -166,7 +167,7 @@ pub fn register_group(&mut self, sess: Option<&Session>,
match (sess, from_plugin) { match (sess, from_plugin) {
// We load builtin lints first, so a duplicate is a compiler bug. // We load builtin lints first, so a duplicate is a compiler bug.
// Use early_error when handling -W help with no crate. // Use early_error when handling -W help with no crate.
(None, _) => early_error(&msg[..]), (None, _) => early_error(diagnostic::Auto, &msg[..]),
(Some(sess), false) => sess.bug(&msg[..]), (Some(sess), false) => sess.bug(&msg[..]),
// A duplicate name from a plugin is a user error. // A duplicate name from a plugin is a user error.
......
...@@ -288,7 +288,7 @@ pub fn $defaultfn() -> $struct_name { ...@@ -288,7 +288,7 @@ pub fn $defaultfn() -> $struct_name {
$struct_name { $($opt: $init),* } $struct_name { $($opt: $init),* }
} }
pub fn $buildfn(matches: &getopts::Matches) -> $struct_name pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
{ {
let mut op = $defaultfn(); let mut op = $defaultfn();
for option in matches.opt_strs($prefix) { for option in matches.opt_strs($prefix) {
...@@ -302,20 +302,20 @@ pub fn $buildfn(matches: &getopts::Matches) -> $struct_name ...@@ -302,20 +302,20 @@ pub fn $buildfn(matches: &getopts::Matches) -> $struct_name
if !setter(&mut op, value) { if !setter(&mut op, value) {
match (value, opt_type_desc) { match (value, opt_type_desc) {
(Some(..), None) => { (Some(..), None) => {
early_error(&format!("{} option `{}` takes no \ early_error(color, &format!("{} option `{}` takes no \
value", $outputname, key)) value", $outputname, key))
} }
(None, Some(type_desc)) => { (None, Some(type_desc)) => {
early_error(&format!("{0} option `{1}` requires \ early_error(color, &format!("{0} option `{1}` requires \
{2} ({3} {1}=<value>)", {2} ({3} {1}=<value>)",
$outputname, key, $outputname, key,
type_desc, $prefix)) type_desc, $prefix))
} }
(Some(value), Some(type_desc)) => { (Some(value), Some(type_desc)) => {
early_error(&format!("incorrect value `{}` for {} \ early_error(color, &format!("incorrect value `{}` for {} \
option `{}` - {} was expected", option `{}` - {} was expected",
value, $outputname, value, $outputname,
key, type_desc)) key, type_desc))
} }
(None, None) => unreachable!() (None, None) => unreachable!()
} }
...@@ -324,8 +324,8 @@ pub fn $buildfn(matches: &getopts::Matches) -> $struct_name ...@@ -324,8 +324,8 @@ pub fn $buildfn(matches: &getopts::Matches) -> $struct_name
break; break;
} }
if !found { if !found {
early_error(&format!("unknown {} option: `{}`", early_error(color, &format!("unknown {} option: `{}`",
$outputname, key)); $outputname, key));
} }
} }
return op; return op;
...@@ -850,9 +850,23 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig { ...@@ -850,9 +850,23 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
} }
pub fn build_session_options(matches: &getopts::Matches) -> Options { pub fn build_session_options(matches: &getopts::Matches) -> Options {
let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
Some("auto") => Auto,
Some("always") => Always,
Some("never") => Never,
None => Auto,
Some(arg) => {
early_error(Auto, &format!("argument for --color must be auto, always \
or never (instead was `{}`)",
arg))
}
};
let unparsed_crate_types = matches.opt_strs("crate-type"); let unparsed_crate_types = matches.opt_strs("crate-type");
let crate_types = parse_crate_types_from_list(unparsed_crate_types) let crate_types = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(&e[..])); .unwrap_or_else(|e| early_error(color, &e[..]));
let mut lint_opts = vec!(); let mut lint_opts = vec!();
let mut describe_lints = false; let mut describe_lints = false;
...@@ -869,11 +883,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -869,11 +883,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let lint_cap = matches.opt_str("cap-lints").map(|cap| { let lint_cap = matches.opt_str("cap-lints").map(|cap| {
lint::Level::from_str(&cap).unwrap_or_else(|| { lint::Level::from_str(&cap).unwrap_or_else(|| {
early_error(&format!("unknown lint level: `{}`", cap)) early_error(color, &format!("unknown lint level: `{}`", cap))
}) })
}); });
let debugging_opts = build_debugging_options(matches); let debugging_opts = build_debugging_options(matches, color);
let parse_only = debugging_opts.parse_only; let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans; let no_trans = debugging_opts.no_trans;
...@@ -897,8 +911,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -897,8 +911,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
"link" => OutputTypeExe, "link" => OutputTypeExe,
"dep-info" => OutputTypeDepInfo, "dep-info" => OutputTypeDepInfo,
_ => { _ => {
early_error(&format!("unknown emission type: `{}`", early_error(color, &format!("unknown emission type: `{}`",
part)) part))
} }
}; };
output_types.push(output_type) output_types.push(output_type)
...@@ -911,7 +925,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -911,7 +925,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
output_types.push(OutputTypeExe); output_types.push(OutputTypeExe);
} }
let cg = build_codegen_options(matches); let cg = build_codegen_options(matches, color);
let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
let target = matches.opt_str("target").unwrap_or( let target = matches.opt_str("target").unwrap_or(
...@@ -919,7 +933,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -919,7 +933,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let opt_level = { let opt_level = {
if matches.opt_present("O") { if matches.opt_present("O") {
if cg.opt_level.is_some() { if cg.opt_level.is_some() {
early_error("-O and -C opt-level both provided"); early_error(color, "-O and -C opt-level both provided");
} }
Default Default
} else { } else {
...@@ -930,9 +944,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -930,9 +944,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
Some(2) => Default, Some(2) => Default,
Some(3) => Aggressive, Some(3) => Aggressive,
Some(arg) => { Some(arg) => {
early_error(&format!("optimization level needs to be \ early_error(color, &format!("optimization level needs to be \
between 0-3 (instead was `{}`)", between 0-3 (instead was `{}`)",
arg)); arg));
} }
} }
} }
...@@ -941,7 +955,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -941,7 +955,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let gc = debugging_opts.gc; let gc = debugging_opts.gc;
let debuginfo = if matches.opt_present("g") { let debuginfo = if matches.opt_present("g") {
if cg.debuginfo.is_some() { if cg.debuginfo.is_some() {
early_error("-g and -C debuginfo both provided"); early_error(color, "-g and -C debuginfo both provided");
} }
FullDebugInfo FullDebugInfo
} else { } else {
...@@ -950,16 +964,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -950,16 +964,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
Some(1) => LimitedDebugInfo, Some(1) => LimitedDebugInfo,
Some(2) => FullDebugInfo, Some(2) => FullDebugInfo,
Some(arg) => { Some(arg) => {
early_error(&format!("debug info level needs to be between \ early_error(color, &format!("debug info level needs to be between \
0-2 (instead was `{}`)", 0-2 (instead was `{}`)",
arg)); arg));
} }
} }
}; };
let mut search_paths = SearchPaths::new(); let mut search_paths = SearchPaths::new();
for s in &matches.opt_strs("L") { for s in &matches.opt_strs("L") {
search_paths.add_path(&s[..]); search_paths.add_path(&s[..], color);
} }
let libs = matches.opt_strs("l").into_iter().map(|s| { let libs = matches.opt_strs("l").into_iter().map(|s| {
...@@ -971,9 +985,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -971,9 +985,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
(Some(name), "framework") => (name, cstore::NativeFramework), (Some(name), "framework") => (name, cstore::NativeFramework),
(Some(name), "static") => (name, cstore::NativeStatic), (Some(name), "static") => (name, cstore::NativeStatic),
(_, s) => { (_, s) => {
early_error(&format!("unknown library kind `{}`, expected \ early_error(color, &format!("unknown library kind `{}`, expected \
one of dylib, framework, or static", one of dylib, framework, or static",
s)); s));
} }
}; };
(name.to_string(), kind) (name.to_string(), kind)
...@@ -989,40 +1003,26 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ...@@ -989,40 +1003,26 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
"file-names" => PrintRequest::FileNames, "file-names" => PrintRequest::FileNames,
"sysroot" => PrintRequest::Sysroot, "sysroot" => PrintRequest::Sysroot,
req => { req => {
early_error(&format!("unknown print request `{}`", req)) early_error(color, &format!("unknown print request `{}`", req))
} }
} }
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
if !cg.remark.is_empty() && debuginfo == NoDebugInfo { if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
early_warn("-C remark will not show source locations without \ early_warn(color, "-C remark will not show source locations without \
--debuginfo"); --debuginfo");
} }
let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
Some("auto") => Auto,
Some("always") => Always,
Some("never") => Never,
None => Auto,
Some(arg) => {
early_error(&format!("argument for --color must be auto, always \
or never (instead was `{}`)",
arg))
}
};
let mut externs = HashMap::new(); let mut externs = HashMap::new();
for arg in &matches.opt_strs("extern") { for arg in &matches.opt_strs("extern") {
let mut parts = arg.splitn(2, '='); let mut parts = arg.splitn(2, '=');
let name = match parts.next() { let name = match parts.next() {
Some(s) => s, Some(s) => s,
None => early_error("--extern value must not be empty"), None => early_error(color, "--extern value must not be empty"),
}; };
let location = match parts.next() { let location = match parts.next() {
Some(s) => s, Some(s) => s,
None => early_error("--extern value must be of the format `foo=bar`"), None => early_error(color, "--extern value must be of the format `foo=bar`"),
}; };
externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string()); externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
......
...@@ -473,13 +473,13 @@ pub fn expect<T, M>(sess: &Session, opt: Option<T>, msg: M) -> T where ...@@ -473,13 +473,13 @@ pub fn expect<T, M>(sess: &Session, opt: Option<T>, msg: M) -> T where
diagnostic::expect(sess.diagnostic(), opt, msg) diagnostic::expect(sess.diagnostic(), opt, msg)
} }
pub fn early_error(msg: &str) -> ! { pub fn early_error(color: diagnostic::ColorConfig, msg: &str) -> ! {
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); let mut emitter = diagnostic::EmitterWriter::stderr(color, None);
emitter.emit(None, msg, None, diagnostic::Fatal); emitter.emit(None, msg, None, diagnostic::Fatal);
panic!(diagnostic::FatalError); panic!(diagnostic::FatalError);
} }
pub fn early_warn(msg: &str) { pub fn early_warn(color: diagnostic::ColorConfig, msg: &str) {
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); let mut emitter = diagnostic::EmitterWriter::stderr(color, None);
emitter.emit(None, msg, None, diagnostic::Warning); emitter.emit(None, msg, None, diagnostic::Warning);
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
use std::slice; use std::slice;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use session::early_error; use session::early_error;
use syntax::diagnostic;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SearchPaths { pub struct SearchPaths {
...@@ -37,7 +38,7 @@ pub fn new() -> SearchPaths { ...@@ -37,7 +38,7 @@ pub fn new() -> SearchPaths {
SearchPaths { paths: Vec::new() } SearchPaths { paths: Vec::new() }
} }
pub fn add_path(&mut self, path: &str) { pub fn add_path(&mut self, path: &str, color: diagnostic::ColorConfig) {
let (kind, path) = if path.starts_with("native=") { let (kind, path) = if path.starts_with("native=") {
(PathKind::Native, &path["native=".len()..]) (PathKind::Native, &path["native=".len()..])
} else if path.starts_with("crate=") { } else if path.starts_with("crate=") {
...@@ -52,7 +53,7 @@ pub fn add_path(&mut self, path: &str) { ...@@ -52,7 +53,7 @@ pub fn add_path(&mut self, path: &str) {
(PathKind::All, path) (PathKind::All, path)
}; };
if path.is_empty() { if path.is_empty() {
early_error("empty search path given via `-L`"); early_error(color, "empty search path given via `-L`");
} }
self.paths.push((kind, PathBuf::from(path))); self.paths.push((kind, PathBuf::from(path)));
} }
......
...@@ -117,11 +117,11 @@ pub fn run_compiler<'a>(args: &[String], ...@@ -117,11 +117,11 @@ pub fn run_compiler<'a>(args: &[String],
None => return None => return
}; };
let descriptions = diagnostics_registry(); let sopts = config::build_session_options(&matches);
do_or_return!(callbacks.early_callback(&matches, &descriptions)); let descriptions = diagnostics_registry();
let sopts = config::build_session_options(&matches); do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.color));
let (odir, ofile) = make_output(&matches); let (odir, ofile) = make_output(&matches);
let (input, input_file_path) = match make_input(&matches.free) { let (input, input_file_path) = match make_input(&matches.free) {
...@@ -205,7 +205,8 @@ pub trait CompilerCalls<'a> { ...@@ -205,7 +205,8 @@ pub trait CompilerCalls<'a> {
// else (e.g., selecting input and output). // else (e.g., selecting input and output).
fn early_callback(&mut self, fn early_callback(&mut self,
_: &getopts::Matches, _: &getopts::Matches,
_: &diagnostics::registry::Registry) _: &diagnostics::registry::Registry,
_: diagnostic::ColorConfig)
-> Compilation { -> Compilation {
Compilation::Continue Compilation::Continue
} }
...@@ -277,7 +278,8 @@ fn parse_pretty(&mut self, ...@@ -277,7 +278,8 @@ fn parse_pretty(&mut self,
impl<'a> CompilerCalls<'a> for RustcDefaultCalls { impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
fn early_callback(&mut self, fn early_callback(&mut self,
matches: &getopts::Matches, matches: &getopts::Matches,
descriptions: &diagnostics::registry::Registry) descriptions: &diagnostics::registry::Registry,
color: diagnostic::ColorConfig)
-> Compilation { -> Compilation {
match matches.opt_str("explain") { match matches.opt_str("explain") {
Some(ref code) => { Some(ref code) => {
...@@ -287,7 +289,7 @@ fn early_callback(&mut self, ...@@ -287,7 +289,7 @@ fn early_callback(&mut self,
print!("{}", &description[1..]); print!("{}", &description[1..]);
} }
None => { None => {
early_error(&format!("no extended information for {}", code)); early_error(color, &format!("no extended information for {}", code));
} }
} }
return Compilation::Stop; return Compilation::Stop;
...@@ -319,10 +321,10 @@ fn no_input(&mut self, ...@@ -319,10 +321,10 @@ fn no_input(&mut self,
if should_stop == Compilation::Stop { if should_stop == Compilation::Stop {
return None; return None;
} }
early_error("no input filename given"); early_error(sopts.color, "no input filename given");
} }
1 => panic!("make_input should have provided valid inputs"), 1 => panic!("make_input should have provided valid inputs"),
_ => early_error("multiple input filenames provided") _ => early_error(sopts.color, "multiple input filenames provided")
} }
None None
...@@ -414,7 +416,7 @@ pub fn list_metadata(sess: &Session, ...@@ -414,7 +416,7 @@ pub fn list_metadata(sess: &Session,
println!("{}", String::from_utf8(v).unwrap()); println!("{}", String::from_utf8(v).unwrap());
} }
&Input::Str(_) => { &Input::Str(_) => {
early_error("cannot list metadata for stdin"); early_error(sess.opts.color, "cannot list metadata for stdin");
} }
} }
return Compilation::Stop; return Compilation::Stop;
...@@ -441,7 +443,7 @@ fn print_crate_info(sess: &Session, ...@@ -441,7 +443,7 @@ fn print_crate_info(sess: &Session,
PrintRequest::CrateName => { PrintRequest::CrateName => {
let input = match input { let input = match input {
Some(input) => input, Some(input) => input,
None => early_error("no input file provided"), None => early_error(sess.opts.color, "no input file provided"),
}; };
let attrs = attrs.as_ref().unwrap(); let attrs = attrs.as_ref().unwrap();
let t_outputs = driver::build_output_filenames(input, let t_outputs = driver::build_output_filenames(input,
...@@ -701,14 +703,15 @@ fn parse_all_options(args: &Vec<String>) -> getopts::Matches { ...@@ -701,14 +703,15 @@ fn parse_all_options(args: &Vec<String>) -> getopts::Matches {
&opt.opt_group.short_name &opt.opt_group.short_name
}; };
if m.opt_present(opt_name) { if m.opt_present(opt_name) {
early_error(&format!("use of unstable option '{}' requires \ early_error(diagnostic::Auto, &format!("use of unstable option '{}' \
-Z unstable-options", opt_name)); requires -Z unstable-options",
opt_name));
} }
} }
} }
m m
} }
Err(f) => early_error(&f.to_string()) Err(f) => early_error(diagnostic::Auto, &f.to_string())
} }
} }
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
use serialize::Decodable; use serialize::Decodable;
use serialize::json::{self, Json}; use serialize::json::{self, Json};
use rustc::session::search_paths::SearchPaths; use rustc::session::search_paths::SearchPaths;
use syntax::diagnostic;
// reexported from `clean` so it can be easily updated with the mod itself // reexported from `clean` so it can be easily updated with the mod itself
pub use clean::SCHEMA_VERSION; pub use clean::SCHEMA_VERSION;
...@@ -227,7 +228,7 @@ pub fn main_args(args: &[String]) -> isize { ...@@ -227,7 +228,7 @@ pub fn main_args(args: &[String]) -> isize {
let mut libs = SearchPaths::new(); let mut libs = SearchPaths::new();
for s in &matches.opt_strs("L") { for s in &matches.opt_strs("L") {
libs.add_path(s); libs.add_path(s, diagnostic::Auto);
} }
let externs = match parse_externs(&matches) { let externs = match parse_externs(&matches) {
Ok(ex) => ex, Ok(ex) => ex,
...@@ -362,7 +363,7 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche ...@@ -362,7 +363,7 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
// First, parse the crate and extract all relevant information. // First, parse the crate and extract all relevant information.
let mut paths = SearchPaths::new(); let mut paths = SearchPaths::new();
for s in &matches.opt_strs("L") { for s in &matches.opt_strs("L") {
paths.add_path(s); paths.add_path(s, diagnostic::Auto);
} }
let cfgs = matches.opt_strs("cfg"); let cfgs = matches.opt_strs("cfg");
let triple = matches.opt_str("target"); let triple = matches.opt_str("target");
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
use rustc::session::Session; use rustc::session::Session;
use rustc::session::config::{self, Input}; use rustc::session::config::{self, Input};
use rustc_driver::{driver, CompilerCalls, Compilation}; use rustc_driver::{driver, CompilerCalls, Compilation};
use syntax::diagnostics; use syntax::{diagnostics, diagnostic};
use std::path::PathBuf; use std::path::PathBuf;
...@@ -34,7 +34,8 @@ struct TestCalls { ...@@ -34,7 +34,8 @@ struct TestCalls {
impl<'a> CompilerCalls<'a> for TestCalls { impl<'a> CompilerCalls<'a> for TestCalls {
fn early_callback(&mut self, fn early_callback(&mut self,
_: &getopts::Matches, _: &getopts::Matches,
_: &diagnostics::registry::Registry) _: &diagnostics::registry::Registry,
_: diagnostic::ColorConfig)
-> Compilation { -> Compilation {
self.count *= 2; self.count *= 2;
Compilation::Continue Compilation::Continue
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册