use dep_graph::DepNode;
use middle::privacy::AccessLevels;
use middle::ty;
-use session::{early_error, Session};
+use session::{config, early_error, Session};
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
use std::cell::RefCell;
use std::cmp;
+use std::default::Default as StdDefault;
use std::mem;
use syntax::ast_util::{self, IdVisitingOperation};
use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::Span;
-use syntax::errors::{self, DiagnosticBuilder};
+use syntax::errors::DiagnosticBuilder;
use syntax::parse::token::InternedString;
use syntax::ast;
use syntax::attr::ThinAttributesExt;
match (sess, from_plugin) {
// We load builtin lints first, so a duplicate is a compiler bug.
// Use early_error when handling -W help with no crate.
- (None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
+ (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
(Some(sess), false) => sess.bug(&msg[..]),
// A duplicate name from a plugin is a user error.
match (sess, from_plugin) {
// We load builtin lints first, so a duplicate is a compiler bug.
// Use early_error when handling -W help with no crate.
- (None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
+ (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
(Some(sess), false) => sess.bug(&msg[..]),
// A duplicate name from a plugin is a user error.
pub use self::EntryFnType::*;
pub use self::CrateType::*;
pub use self::Passes::*;
-pub use self::OptLevel::*;
pub use self::DebugInfoLevel::*;
use session::{early_error, early_warn, Session};
DepInfo,
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ErrorOutputType {
+ Tty(ColorConfig),
+ Json,
+}
+
+impl Default for ErrorOutputType {
+ fn default() -> ErrorOutputType {
+ ErrorOutputType::Tty(ColorConfig::Auto)
+ }
+}
+
impl OutputType {
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
match *self {
pub test: bool,
pub parse_only: bool,
pub no_trans: bool,
+ pub output: ErrorOutputType,
pub treat_err_as_bug: bool,
pub incremental_compilation: bool,
pub dump_dep_graph: bool,
pub debugging_opts: DebuggingOptions,
pub prints: Vec<PrintRequest>,
pub cg: CodegenOptions,
- pub color: ColorConfig,
pub externs: HashMap<String, Vec<String>>,
pub crate_name: Option<String>,
/// An optional name to use as the crate for std during std injection,
Options {
crate_types: Vec::new(),
gc: false,
- optimize: No,
+ optimize: OptLevel::No,
debuginfo: NoDebugInfo,
lint_opts: Vec::new(),
lint_cap: None,
debugging_opts: basic_debugging_options(),
prints: Vec::new(),
cg: basic_codegen_options(),
+<<<<<<< HEAD
color: ColorConfig::Auto,
+=======
+ output: ErrorOutputType::default(),
+ show_span: None,
+>>>>>>> Add an --output option for specifying an error emitter
externs: HashMap::new(),
crate_name: None,
alt_std_name: None,
$struct_name { $($opt: $init),* }
}
- pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
+ pub fn $buildfn(matches: &getopts::Matches, output: ErrorOutputType) -> $struct_name
{
let mut op = $defaultfn();
for option in matches.opt_strs($prefix) {
if !setter(&mut op, value) {
match (value, opt_type_desc) {
(Some(..), None) => {
- early_error(color, &format!("{} option `{}` takes no \
+ early_error(output, &format!("{} option `{}` takes no \
value", $outputname, key))
}
(None, Some(type_desc)) => {
- early_error(color, &format!("{0} option `{1}` requires \
+ early_error(output, &format!("{0} option `{1}` requires \
{2} ({3} {1}=<value>)",
$outputname, key,
type_desc, $prefix))
}
(Some(value), Some(type_desc)) => {
- early_error(color, &format!("incorrect value `{}` for {} \
+ early_error(output, &format!("incorrect value `{}` for {} \
option `{}` - {} was expected",
value, $outputname,
key, type_desc))
break;
}
if !found {
- early_error(color, &format!("unknown {} option: `{}`",
+ early_error(output, &format!("unknown {} option: `{}`",
$outputname, key));
}
}
"NAME=PATH"),
opt::opt("", "sysroot", "Override the system root", "PATH"),
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
+ opt::opt_u("", "output", "How errors and other mesasges are produced", "tty|json"),
opt::opt("", "color", "Configure coloring of output:
auto = colorize, if output goes to a tty (default);
always = always colorize output;
None => ColorConfig::Auto,
Some(arg) => {
- early_error(ColorConfig::Auto, &format!("argument for --color must be auto, always \
- or never (instead was `{}`)",
- arg))
+ early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
+ always or never (instead was `{}`)",
+ arg))
}
};
+ // We need the opts_present check because the driver will send us Matches
+ // with only stable options if no unstable options are used. Since output is
+ // unstable, it will not be present. We have to use opts_present not
+ // opt_present because the latter will panic.
+ let output = if matches.opts_present(&["output".to_owned()]) {
+ match matches.opt_str("output").as_ref().map(|s| &s[..]) {
+ Some("tty") => ErrorOutputType::Tty(color),
+ Some("json") => ErrorOutputType::Json,
+
+ None => ErrorOutputType::default(),
+
+ Some(arg) => {
+ early_error(ErrorOutputType::default(), &format!("argument for --output must be tty or \
+ json (instead was `{}`)",
+ arg))
+ }
+ }
+ } else {
+ ErrorOutputType::default()
+ };
+
let unparsed_crate_types = matches.opt_strs("crate-type");
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
- .unwrap_or_else(|e| early_error(color, &e[..]));
+ .unwrap_or_else(|e| early_error(output, &e[..]));
let mut lint_opts = vec!();
let mut describe_lints = false;
let lint_cap = matches.opt_str("cap-lints").map(|cap| {
lint::Level::from_str(&cap).unwrap_or_else(|| {
- early_error(color, &format!("unknown lint level: `{}`", cap))
+ early_error(output, &format!("unknown lint level: `{}`", cap))
})
});
- let debugging_opts = build_debugging_options(matches, color);
+ let debugging_opts = build_debugging_options(matches, output);
let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans;
"link" => OutputType::Exe,
"dep-info" => OutputType::DepInfo,
part => {
- early_error(color, &format!("unknown emission type: `{}`",
+ early_error(output, &format!("unknown emission type: `{}`",
part))
}
};
output_types.insert(OutputType::Exe, None);
}
- let mut cg = build_codegen_options(matches, color);
+ let mut cg = build_codegen_options(matches, output);
// Issue #30063: if user requests llvm-related output to one
// particular path, disable codegen-units.
}).collect();
if !incompatible.is_empty() {
for ot in &incompatible {
- early_warn(color, &format!("--emit={} with -o incompatible with \
+ early_warn(output, &format!("--emit={} with -o incompatible with \
-C codegen-units=N for N > 1",
ot.shorthand()));
}
- early_warn(color, "resetting to default -C codegen-units=1");
+ early_warn(output, "resetting to default -C codegen-units=1");
cg.codegen_units = 1;
}
}
let opt_level = {
if matches.opt_present("O") {
if cg.opt_level.is_some() {
- early_error(color, "-O and -C opt-level both provided");
+ early_error(output, "-O and -C opt-level both provided");
}
- Default
+ OptLevel::Default
} else {
match cg.opt_level {
- None => No,
- Some(0) => No,
- Some(1) => Less,
- Some(2) => Default,
- Some(3) => Aggressive,
+ None => OptLevel::No,
+ Some(0) => OptLevel::No,
+ Some(1) => OptLevel::Less,
+ Some(2) => OptLevel::Default,
+ Some(3) => OptLevel::Aggressive,
Some(arg) => {
- early_error(color, &format!("optimization level needs to be \
+ early_error(output, &format!("optimization level needs to be \
between 0-3 (instead was `{}`)",
arg));
}
}
}
};
- let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == No);
+ let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
let gc = debugging_opts.gc;
let debuginfo = if matches.opt_present("g") {
if cg.debuginfo.is_some() {
- early_error(color, "-g and -C debuginfo both provided");
+ early_error(output, "-g and -C debuginfo both provided");
}
FullDebugInfo
} else {
Some(1) => LimitedDebugInfo,
Some(2) => FullDebugInfo,
Some(arg) => {
- early_error(color, &format!("debug info level needs to be between \
+ early_error(output, &format!("debug info level needs to be between \
0-2 (instead was `{}`)",
arg));
}
let mut search_paths = SearchPaths::new();
for s in &matches.opt_strs("L") {
- search_paths.add_path(&s[..], color);
+ search_paths.add_path(&s[..], output);
}
let libs = matches.opt_strs("l").into_iter().map(|s| {
(Some(name), "framework") => (name, cstore::NativeFramework),
(Some(name), "static") => (name, cstore::NativeStatic),
(_, s) => {
- early_error(color, &format!("unknown library kind `{}`, expected \
+ early_error(output, &format!("unknown library kind `{}`, expected \
one of dylib, framework, or static",
s));
}
"file-names" => PrintRequest::FileNames,
"sysroot" => PrintRequest::Sysroot,
req => {
- early_error(color, &format!("unknown print request `{}`", req))
+ early_error(output, &format!("unknown print request `{}`", req))
}
}
}).collect::<Vec<_>>();
if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
- early_warn(color, "-C remark will not show source locations without \
+ early_warn(output, "-C remark will not show source locations without \
--debuginfo");
}
let mut parts = arg.splitn(2, '=');
let name = match parts.next() {
Some(s) => s,
- None => early_error(color, "--extern value must not be empty"),
+ None => early_error(output, "--extern value must not be empty"),
};
let location = match parts.next() {
Some(s) => s,
- None => early_error(color, "--extern value must be of the format `foo=bar`"),
+ None => early_error(output, "--extern value must be of the format `foo=bar`"),
};
externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
debugging_opts: debugging_opts,
prints: prints,
cg: cg,
- color: color,
+ output: output,
externs: externs,
crate_name: crate_name,
alt_std_name: None,
use syntax::ast::{NodeId, NodeIdAssigner, Name};
use syntax::codemap::Span;
use syntax::errors::{self, DiagnosticBuilder};
-use syntax::errors::emitter::{Emitter, BasicEmitter};
+use syntax::errors::emitter::{Emitter, BasicEmitter, EmitterWriter};
+use syntax::errors::json::JsonEmitter;
use syntax::diagnostics;
use syntax::feature_gate;
use syntax::parse;
let treat_err_as_bug = sopts.treat_err_as_bug;
let codemap = Rc::new(codemap::CodeMap::new());
+ let emitter: Box<Emitter> = match sopts.output {
+ config::ErrorOutputType::Tty(color_config) => {
+ Box::new(EmitterWriter::stderr(color_config, Some(registry), codemap.clone()))
+ }
+ config::ErrorOutputType::Json => {
+ Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
+ }
+ };
+
let diagnostic_handler =
- errors::Handler::new(sopts.color,
- Some(registry),
- can_print_warnings,
- treat_err_as_bug,
- codemap.clone());
+ errors::Handler::with_emitter(can_print_warnings,
+ treat_err_as_bug,
+ emitter);
build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore)
}
sess
}
-pub fn early_error(color: errors::ColorConfig, msg: &str) -> ! {
- let mut emitter = BasicEmitter::stderr(color);
+pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
+ let mut emitter: Box<Emitter> = match output {
+ config::ErrorOutputType::Tty(color_config) => Box::new(BasicEmitter::stderr(color_config)),
+ config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
+ };
emitter.emit(None, msg, None, errors::Level::Fatal);
panic!(errors::FatalError);
}
-pub fn early_warn(color: errors::ColorConfig, msg: &str) {
- let mut emitter = BasicEmitter::stderr(color);
+pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
+ let mut emitter: Box<Emitter> = match output {
+ config::ErrorOutputType::Tty(color_config) => Box::new(BasicEmitter::stderr(color_config)),
+ config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
+ };
emitter.emit(None, msg, None, errors::Level::Warning);
}
use std::slice;
use std::path::{Path, PathBuf};
-use session::early_error;
-use syntax::errors;
+use session::{early_error, config};
#[derive(Clone, Debug)]
pub struct SearchPaths {
SearchPaths { paths: Vec::new() }
}
- pub fn add_path(&mut self, path: &str, color: errors::ColorConfig) {
+ pub fn add_path(&mut self, path: &str, output: config::ErrorOutputType) {
let (kind, path) = if path.starts_with("native=") {
(PathKind::Native, &path["native=".len()..])
} else if path.starts_with("crate=") {
(PathKind::All, path)
};
if path.is_empty() {
- early_error(color, "empty search path given via `-L`");
+ early_error(output, "empty search path given via `-L`");
}
self.paths.push((kind, PathBuf::from(path)));
}
use rustc_trans::back::link;
use rustc_trans::save;
use rustc::session::{config, Session, build_session};
-use rustc::session::config::{Input, PrintRequest, OutputType};
+use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
use rustc::middle::cstore::CrateStore;
use rustc::lint::Lint;
use rustc::lint;
use std::cmp::max;
use std::cmp::Ordering::Equal;
+use std::default::Default;
use std::env;
use std::io::{self, Read, Write};
use std::iter::repeat;
let descriptions = diagnostics_registry();
- do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.color));
+ do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.output));
let (odir, ofile) = make_output(&matches);
let (input, input_file_path) = match make_input(&matches.free) {
fn early_callback(&mut self,
_: &getopts::Matches,
_: &diagnostics::registry::Registry,
- _: errors::ColorConfig)
+ _: ErrorOutputType)
-> Compilation {
Compilation::Continue
}
fn early_callback(&mut self,
matches: &getopts::Matches,
descriptions: &diagnostics::registry::Registry,
- color: errors::ColorConfig)
+ output: ErrorOutputType)
-> Compilation {
match matches.opt_str("explain") {
Some(ref code) => {
print!("{}", &description[1..]);
}
None => {
- early_error(color, &format!("no extended information for {}", code));
+ early_error(output, &format!("no extended information for {}", code));
}
}
return Compilation::Stop;
if should_stop == Compilation::Stop {
return None;
}
- early_error(sopts.color, "no input filename given");
+ early_error(sopts.output, "no input filename given");
}
1 => panic!("make_input should have provided valid inputs"),
- _ => early_error(sopts.color, "multiple input filenames provided"),
+ _ => early_error(sopts.output, "multiple input filenames provided"),
}
None
println!("{}", String::from_utf8(v).unwrap());
}
&Input::Str(_) => {
- early_error(sess.opts.color, "cannot list metadata for stdin");
+ early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
}
}
return Compilation::Stop;
PrintRequest::CrateName => {
let input = match input {
Some(input) => input,
- None => early_error(sess.opts.color, "no input file provided"),
+ None => early_error(ErrorOutputType::default(), "no input file provided"),
};
let attrs = attrs.as_ref().unwrap();
let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
&opt.opt_group.short_name
};
if m.opt_present(opt_name) {
- early_error(errors::ColorConfig::Auto,
+ early_error(ErrorOutputType::default(),
&format!("use of unstable option '{}' requires -Z \
unstable-options",
opt_name));
}
m
}
- Err(f) => early_error(errors::ColorConfig::Auto, &f.to_string()),
+ Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
}
}
// GNU-style linkers support optimization with -O. GNU ld doesn't
// need a numeric argument, but other linkers do.
- if self.sess.opts.optimize == config::Default ||
- self.sess.opts.optimize == config::Aggressive {
+ if self.sess.opts.optimize == config::OptLevel::Default ||
+ self.sess.opts.optimize == config::OptLevel::Aggressive {
self.cmd.arg("-Wl,-O1");
}
}
fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
match optimize {
- config::No => llvm::CodeGenLevelNone,
- config::Less => llvm::CodeGenLevelLess,
- config::Default => llvm::CodeGenLevelDefault,
- config::Aggressive => llvm::CodeGenLevelAggressive,
+ config::OptLevel::No => llvm::CodeGenLevelNone,
+ config::OptLevel::Less => llvm::CodeGenLevelLess,
+ config::OptLevel::Default => llvm::CodeGenLevelDefault,
+ config::OptLevel::Aggressive => llvm::CodeGenLevelAggressive,
}
}
// slp vectorization at O3. Otherwise configure other optimization aspects
// of this pass manager builder.
self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
- (sess.opts.optimize == config::Default ||
- sess.opts.optimize == config::Aggressive);
+ (sess.opts.optimize == config::OptLevel::Default ||
+ sess.opts.optimize == config::OptLevel::Aggressive);
self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
- sess.opts.optimize == config::Aggressive;
+ sess.opts.optimize == config::OptLevel::Aggressive;
- self.merge_functions = sess.opts.optimize == config::Default ||
- sess.opts.optimize == config::Aggressive;
+ self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
+ sess.opts.optimize == config::OptLevel::Aggressive;
}
}
emit: F)
where F: FnOnce(&'blk CrateContext<'blk, 'tcx>, machine::llsize, ValueRef)
{
- if ccx.sess().opts.optimize == config::No {
+ if ccx.sess().opts.optimize == config::OptLevel::No {
return;
}
compile_unit_name,
work_dir.as_ptr(),
producer.as_ptr(),
- cx.sess().opts.optimize != config::No,
+ cx.sess().opts.optimize != config::OptLevel::No,
flags.as_ptr() as *const _,
0,
split_name.as_ptr() as *const _)
true,
scope_line as c_uint,
FlagPrototyped as c_uint,
- cx.sess().opts.optimize != config::No,
+ cx.sess().opts.optimize != config::OptLevel::No,
llfn,
template_parameters,
ptr::null_mut())
file_metadata,
loc.line as c_uint,
type_metadata,
- cx.sess().opts.optimize != config::No,
+ cx.sess().opts.optimize != config::OptLevel::No,
0,
address_operations.as_ptr(),
address_operations.len() as c_uint,
/// maximum number of lines we will print for each error; arbitrary.
const MAX_LINES: usize = 6;
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ColorConfig {
Auto,
Always,
}
impl Handler {
+ // TODO remove
pub fn new(color_config: ColorConfig,
registry: Option<diagnostics::registry::Registry>,
can_emit_warnings: bool,