Rollup merge of #23274 - rprichard:fix-21715, r=pnkfelix

* Consumers of handle_options assume the unstable options are defined in
   the getopts::Matches value if -Z unstable-options is set, but that's not
   the case if there weren't any actual unstable options. Fix this by
   always reparsing options when -Z unstable-options is set.

 * If both argument parsing attempts fail, print the error from the second
   attempt rather than the first. The error from the first is very poor
   whenever unstable options are present. e.g.:

       $ rustc hello.rs -Z unstable-options --show-span
       error: Unrecognized option: 'show-span'.
       $ rustc hello.rs -Z unstable-options --pretty --pretty
       error: Unrecognized option: 'pretty'.
       $ rustc hello.rs -Z unstable-options --pretty --bad-option
       error: Unrecognized option: 'pretty'.

 * On the second parse, add a separate pass to reject unstable options if
   -Z unstable-options wasn't specified.

Fixes #21715.
r? @pnkfelix
This commit is contained in:
Manish Goregaokar 2015-03-12 09:14:38 +05:30
commit e4e5640a6e
1 changed files with 43 additions and 25 deletions

View File

@ -686,39 +686,57 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
return None;
}
let matches =
match getopts::getopts(&args[..], &config::optgroups()) {
Ok(m) => m,
Err(f_stable_attempt) => {
// redo option parsing, including unstable options this time,
// in anticipation that the mishandled option was one of the
// unstable ones.
let all_groups : Vec<getopts::OptGroup>
= config::rustc_optgroups().into_iter().map(|x|x.opt_group).collect();
match getopts::getopts(&args, &all_groups) {
Ok(m_unstable) => {
let r = m_unstable.opt_strs("Z");
let include_unstable_options = r.iter().any(|x| *x == "unstable-options");
if include_unstable_options {
m_unstable
fn allows_unstable_options(matches: &getopts::Matches) -> bool {
let r = matches.opt_strs("Z");
r.iter().any(|x| *x == "unstable-options")
}
fn parse_all_options(args: &Vec<String>) -> getopts::Matches {
let all_groups : Vec<getopts::OptGroup>
= config::rustc_optgroups().into_iter().map(|x|x.opt_group).collect();
match getopts::getopts(&args[..], &all_groups) {
Ok(m) => {
if !allows_unstable_options(&m) {
// If -Z unstable-options was not specified, verify that
// no unstable options were present.
for opt in config::rustc_optgroups().into_iter().filter(|x| !x.is_stable()) {
let opt_name = if !opt.opt_group.long_name.is_empty() {
&opt.opt_group.long_name
} else {
early_error(&f_stable_attempt.to_string());
&opt.opt_group.short_name
};
if m.opt_present(opt_name) {
early_error(&format!("use of unstable option '{}' requires \
-Z unstable-options", opt_name));
}
}
Err(_) => {
// ignore the error from the unstable attempt; just
// pass the error we got from the first try.
early_error(&f_stable_attempt.to_string());
}
}
m
}
};
Err(f) => early_error(&f.to_string())
}
}
let r = matches.opt_strs("Z");
let include_unstable_options = r.iter().any(|x| *x == "unstable-options");
// As a speed optimization, first try to parse the command-line using just
// the stable options.
let matches = match getopts::getopts(&args[..], &config::optgroups()) {
Ok(ref m) if allows_unstable_options(m) => {
// If -Z unstable-options was specified, redo parsing with the
// unstable options to ensure that unstable options are defined
// in the returned getopts::Matches.
parse_all_options(&args)
}
Ok(m) => m,
Err(_) => {
// redo option parsing, including unstable options this time,
// in anticipation that the mishandled option was one of the
// unstable ones.
parse_all_options(&args)
}
};
if matches.opt_present("h") || matches.opt_present("help") {
usage(matches.opt_present("verbose"), include_unstable_options);
usage(matches.opt_present("verbose"), allows_unstable_options(&matches));
return None;
}