Skip to content

Commit fd46c78

Browse files
committed
Add an --output option for specifying an error emitter
1 parent acfccc5 commit fd46c78

File tree

12 files changed

+135
-81
lines changed

12 files changed

+135
-81
lines changed

src/librustc/lint/context.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use self::TargetLint::*;
2828
use dep_graph::DepNode;
2929
use middle::privacy::AccessLevels;
3030
use middle::ty;
31-
use session::{early_error, Session};
31+
use session::{config, early_error, Session};
3232
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
3333
use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
3434
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
@@ -37,11 +37,12 @@ use util::nodemap::FnvHashMap;
3737

3838
use std::cell::RefCell;
3939
use std::cmp;
40+
use std::default::Default as StdDefault;
4041
use std::mem;
4142
use syntax::ast_util::{self, IdVisitingOperation};
4243
use syntax::attr::{self, AttrMetaMethods};
4344
use syntax::codemap::Span;
44-
use syntax::errors::{self, DiagnosticBuilder};
45+
use syntax::errors::DiagnosticBuilder;
4546
use syntax::parse::token::InternedString;
4647
use syntax::ast;
4748
use syntax::attr::ThinAttributesExt;
@@ -168,7 +169,7 @@ impl LintStore {
168169
match (sess, from_plugin) {
169170
// We load builtin lints first, so a duplicate is a compiler bug.
170171
// Use early_error when handling -W help with no crate.
171-
(None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
172+
(None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
172173
(Some(sess), false) => sess.bug(&msg[..]),
173174

174175
// A duplicate name from a plugin is a user error.
@@ -192,7 +193,7 @@ impl LintStore {
192193
match (sess, from_plugin) {
193194
// We load builtin lints first, so a duplicate is a compiler bug.
194195
// Use early_error when handling -W help with no crate.
195-
(None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
196+
(None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
196197
(Some(sess), false) => sess.bug(&msg[..]),
197198

198199
// A duplicate name from a plugin is a user error.

src/librustc/session/config.rs

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
pub use self::EntryFnType::*;
1515
pub use self::CrateType::*;
1616
pub use self::Passes::*;
17-
pub use self::OptLevel::*;
1817
pub use self::DebugInfoLevel::*;
1918

2019
use session::{early_error, early_warn, Session};
@@ -71,6 +70,18 @@ pub enum OutputType {
7170
DepInfo,
7271
}
7372

73+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74+
pub enum ErrorOutputType {
75+
Tty(ColorConfig),
76+
Json,
77+
}
78+
79+
impl Default for ErrorOutputType {
80+
fn default() -> ErrorOutputType {
81+
ErrorOutputType::Tty(ColorConfig::Auto)
82+
}
83+
}
84+
7485
impl OutputType {
7586
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
7687
match *self {
@@ -124,14 +135,14 @@ pub struct Options {
124135
pub test: bool,
125136
pub parse_only: bool,
126137
pub no_trans: bool,
138+
pub output: ErrorOutputType,
127139
pub treat_err_as_bug: bool,
128140
pub incremental_compilation: bool,
129141
pub dump_dep_graph: bool,
130142
pub no_analysis: bool,
131143
pub debugging_opts: DebuggingOptions,
132144
pub prints: Vec<PrintRequest>,
133145
pub cg: CodegenOptions,
134-
pub color: ColorConfig,
135146
pub externs: HashMap<String, Vec<String>>,
136147
pub crate_name: Option<String>,
137148
/// An optional name to use as the crate for std during std injection,
@@ -221,7 +232,7 @@ pub fn basic_options() -> Options {
221232
Options {
222233
crate_types: Vec::new(),
223234
gc: false,
224-
optimize: No,
235+
optimize: OptLevel::No,
225236
debuginfo: NoDebugInfo,
226237
lint_opts: Vec::new(),
227238
lint_cap: None,
@@ -241,7 +252,12 @@ pub fn basic_options() -> Options {
241252
debugging_opts: basic_debugging_options(),
242253
prints: Vec::new(),
243254
cg: basic_codegen_options(),
255+
<<<<<<< HEAD
244256
color: ColorConfig::Auto,
257+
=======
258+
output: ErrorOutputType::default(),
259+
show_span: None,
260+
>>>>>>> Add an --output option for specifying an error emitter
245261
externs: HashMap::new(),
246262
crate_name: None,
247263
alt_std_name: None,
@@ -308,7 +324,7 @@ macro_rules! options {
308324
$struct_name { $($opt: $init),* }
309325
}
310326

311-
pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name
327+
pub fn $buildfn(matches: &getopts::Matches, output: ErrorOutputType) -> $struct_name
312328
{
313329
let mut op = $defaultfn();
314330
for option in matches.opt_strs($prefix) {
@@ -322,17 +338,17 @@ macro_rules! options {
322338
if !setter(&mut op, value) {
323339
match (value, opt_type_desc) {
324340
(Some(..), None) => {
325-
early_error(color, &format!("{} option `{}` takes no \
341+
early_error(output, &format!("{} option `{}` takes no \
326342
value", $outputname, key))
327343
}
328344
(None, Some(type_desc)) => {
329-
early_error(color, &format!("{0} option `{1}` requires \
345+
early_error(output, &format!("{0} option `{1}` requires \
330346
{2} ({3} {1}=<value>)",
331347
$outputname, key,
332348
type_desc, $prefix))
333349
}
334350
(Some(value), Some(type_desc)) => {
335-
early_error(color, &format!("incorrect value `{}` for {} \
351+
early_error(output, &format!("incorrect value `{}` for {} \
336352
option `{}` - {} was expected",
337353
value, $outputname,
338354
key, type_desc))
@@ -344,7 +360,7 @@ macro_rules! options {
344360
break;
345361
}
346362
if !found {
347-
early_error(color, &format!("unknown {} option: `{}`",
363+
early_error(output, &format!("unknown {} option: `{}`",
348364
$outputname, key));
349365
}
350366
}
@@ -863,6 +879,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
863879
"NAME=PATH"),
864880
opt::opt("", "sysroot", "Override the system root", "PATH"),
865881
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
882+
opt::opt_u("", "output", "How errors and other mesasges are produced", "tty|json"),
866883
opt::opt("", "color", "Configure coloring of output:
867884
auto = colorize, if output goes to a tty (default);
868885
always = always colorize output;
@@ -905,15 +922,36 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
905922
None => ColorConfig::Auto,
906923

907924
Some(arg) => {
908-
early_error(ColorConfig::Auto, &format!("argument for --color must be auto, always \
909-
or never (instead was `{}`)",
910-
arg))
925+
early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
926+
always or never (instead was `{}`)",
927+
arg))
911928
}
912929
};
913930

931+
// We need the opts_present check because the driver will send us Matches
932+
// with only stable options if no unstable options are used. Since output is
933+
// unstable, it will not be present. We have to use opts_present not
934+
// opt_present because the latter will panic.
935+
let output = if matches.opts_present(&["output".to_owned()]) {
936+
match matches.opt_str("output").as_ref().map(|s| &s[..]) {
937+
Some("tty") => ErrorOutputType::Tty(color),
938+
Some("json") => ErrorOutputType::Json,
939+
940+
None => ErrorOutputType::default(),
941+
942+
Some(arg) => {
943+
early_error(ErrorOutputType::default(), &format!("argument for --output must be tty or \
944+
json (instead was `{}`)",
945+
arg))
946+
}
947+
}
948+
} else {
949+
ErrorOutputType::default()
950+
};
951+
914952
let unparsed_crate_types = matches.opt_strs("crate-type");
915953
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
916-
.unwrap_or_else(|e| early_error(color, &e[..]));
954+
.unwrap_or_else(|e| early_error(output, &e[..]));
917955

918956
let mut lint_opts = vec!();
919957
let mut describe_lints = false;
@@ -930,11 +968,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
930968

931969
let lint_cap = matches.opt_str("cap-lints").map(|cap| {
932970
lint::Level::from_str(&cap).unwrap_or_else(|| {
933-
early_error(color, &format!("unknown lint level: `{}`", cap))
971+
early_error(output, &format!("unknown lint level: `{}`", cap))
934972
})
935973
});
936974

937-
let debugging_opts = build_debugging_options(matches, color);
975+
let debugging_opts = build_debugging_options(matches, output);
938976

939977
let parse_only = debugging_opts.parse_only;
940978
let no_trans = debugging_opts.no_trans;
@@ -960,7 +998,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
960998
"link" => OutputType::Exe,
961999
"dep-info" => OutputType::DepInfo,
9621000
part => {
963-
early_error(color, &format!("unknown emission type: `{}`",
1001+
early_error(output, &format!("unknown emission type: `{}`",
9641002
part))
9651003
}
9661004
};
@@ -973,7 +1011,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
9731011
output_types.insert(OutputType::Exe, None);
9741012
}
9751013

976-
let mut cg = build_codegen_options(matches, color);
1014+
let mut cg = build_codegen_options(matches, output);
9771015

9781016
// Issue #30063: if user requests llvm-related output to one
9791017
// particular path, disable codegen-units.
@@ -985,11 +1023,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
9851023
}).collect();
9861024
if !incompatible.is_empty() {
9871025
for ot in &incompatible {
988-
early_warn(color, &format!("--emit={} with -o incompatible with \
1026+
early_warn(output, &format!("--emit={} with -o incompatible with \
9891027
-C codegen-units=N for N > 1",
9901028
ot.shorthand()));
9911029
}
992-
early_warn(color, "resetting to default -C codegen-units=1");
1030+
early_warn(output, "resetting to default -C codegen-units=1");
9931031
cg.codegen_units = 1;
9941032
}
9951033
}
@@ -1002,29 +1040,29 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10021040
let opt_level = {
10031041
if matches.opt_present("O") {
10041042
if cg.opt_level.is_some() {
1005-
early_error(color, "-O and -C opt-level both provided");
1043+
early_error(output, "-O and -C opt-level both provided");
10061044
}
1007-
Default
1045+
OptLevel::Default
10081046
} else {
10091047
match cg.opt_level {
1010-
None => No,
1011-
Some(0) => No,
1012-
Some(1) => Less,
1013-
Some(2) => Default,
1014-
Some(3) => Aggressive,
1048+
None => OptLevel::No,
1049+
Some(0) => OptLevel::No,
1050+
Some(1) => OptLevel::Less,
1051+
Some(2) => OptLevel::Default,
1052+
Some(3) => OptLevel::Aggressive,
10151053
Some(arg) => {
1016-
early_error(color, &format!("optimization level needs to be \
1054+
early_error(output, &format!("optimization level needs to be \
10171055
between 0-3 (instead was `{}`)",
10181056
arg));
10191057
}
10201058
}
10211059
}
10221060
};
1023-
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == No);
1061+
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
10241062
let gc = debugging_opts.gc;
10251063
let debuginfo = if matches.opt_present("g") {
10261064
if cg.debuginfo.is_some() {
1027-
early_error(color, "-g and -C debuginfo both provided");
1065+
early_error(output, "-g and -C debuginfo both provided");
10281066
}
10291067
FullDebugInfo
10301068
} else {
@@ -1033,7 +1071,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10331071
Some(1) => LimitedDebugInfo,
10341072
Some(2) => FullDebugInfo,
10351073
Some(arg) => {
1036-
early_error(color, &format!("debug info level needs to be between \
1074+
early_error(output, &format!("debug info level needs to be between \
10371075
0-2 (instead was `{}`)",
10381076
arg));
10391077
}
@@ -1042,7 +1080,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10421080

10431081
let mut search_paths = SearchPaths::new();
10441082
for s in &matches.opt_strs("L") {
1045-
search_paths.add_path(&s[..], color);
1083+
search_paths.add_path(&s[..], output);
10461084
}
10471085

10481086
let libs = matches.opt_strs("l").into_iter().map(|s| {
@@ -1054,7 +1092,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10541092
(Some(name), "framework") => (name, cstore::NativeFramework),
10551093
(Some(name), "static") => (name, cstore::NativeStatic),
10561094
(_, s) => {
1057-
early_error(color, &format!("unknown library kind `{}`, expected \
1095+
early_error(output, &format!("unknown library kind `{}`, expected \
10581096
one of dylib, framework, or static",
10591097
s));
10601098
}
@@ -1071,13 +1109,13 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10711109
"file-names" => PrintRequest::FileNames,
10721110
"sysroot" => PrintRequest::Sysroot,
10731111
req => {
1074-
early_error(color, &format!("unknown print request `{}`", req))
1112+
early_error(output, &format!("unknown print request `{}`", req))
10751113
}
10761114
}
10771115
}).collect::<Vec<_>>();
10781116

10791117
if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
1080-
early_warn(color, "-C remark will not show source locations without \
1118+
early_warn(output, "-C remark will not show source locations without \
10811119
--debuginfo");
10821120
}
10831121

@@ -1086,11 +1124,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10861124
let mut parts = arg.splitn(2, '=');
10871125
let name = match parts.next() {
10881126
Some(s) => s,
1089-
None => early_error(color, "--extern value must not be empty"),
1127+
None => early_error(output, "--extern value must not be empty"),
10901128
};
10911129
let location = match parts.next() {
10921130
Some(s) => s,
1093-
None => early_error(color, "--extern value must be of the format `foo=bar`"),
1131+
None => early_error(output, "--extern value must be of the format `foo=bar`"),
10941132
};
10951133

10961134
externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
@@ -1121,7 +1159,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
11211159
debugging_opts: debugging_opts,
11221160
prints: prints,
11231161
cg: cg,
1124-
color: color,
1162+
output: output,
11251163
externs: externs,
11261164
crate_name: crate_name,
11271165
alt_std_name: None,

0 commit comments

Comments
 (0)