Auto merge of #85079 - petrochenkov:sessclean, r=davidtwco

rustc_session: Move more option building code from the `options!` macro

The moved code doesn't need to be generated by a macro, it can use a regular (generic) function and type aliases instead.

(The refactoring is salvaged from a branch with different now abandoned work.)
This commit is contained in:
bors 2021-05-10 12:26:46 +00:00
commit 544d124b81
4 changed files with 85 additions and 73 deletions

View File

@ -685,10 +685,10 @@ impl Default for Options {
target_triple: TargetTriple::from_triple(host_triple()),
test: false,
incremental: None,
debugging_opts: basic_debugging_options(),
debugging_opts: Default::default(),
prints: Vec::new(),
borrowck_mode: BorrowckMode::Migrate,
cg: basic_codegen_options(),
cg: Default::default(),
error_format: ErrorOutputType::default(),
externs: Externs(BTreeMap::new()),
extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
@ -1925,7 +1925,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
let mut debugging_opts = build_debugging_options(matches, error_format);
let mut debugging_opts = DebuggingOptions::build(matches, error_format);
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
if !debugging_opts.unstable_options && json_unused_externs {
@ -1938,7 +1938,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let output_types = parse_output_types(&debugging_opts, matches, error_format);
let mut cg = build_codegen_options(matches, error_format);
let mut cg = CodegenOptions::build(matches, error_format);
let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
&output_types,
matches,

View File

@ -210,9 +210,7 @@ top_level_options!(
/// generated code to parse an option into its respective field in the struct. There are a few
/// hand-written parsers for parsing specific types of values in this module.
macro_rules! options {
($struct_name:ident, $setter_name:ident, $defaultfn:ident,
$buildfn:ident, $prefix:expr, $outputname:expr,
$stat:ident,
($struct_name:ident, $stat:ident, $prefix:expr, $outputname:expr,
$($( #[$attr:meta] )* $opt:ident : $t:ty = (
$init:expr,
$parse:ident,
@ -223,50 +221,20 @@ macro_rules! options {
#[derive(Clone)]
pub struct $struct_name { $(pub $opt: $t),* }
pub fn $defaultfn() -> $struct_name {
$struct_name { $( $( #[$attr] )* $opt: $init),* }
}
pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
{
let mut op = $defaultfn();
for option in matches.opt_strs($prefix) {
let (key, value) = match option.split_once('=') {
None => (option, None),
Some((k, v)) => (k.to_string(), Some(v)),
};
let option_to_lookup = key.replace("-", "_");
let mut found = false;
for &(candidate, setter, type_desc, _) in $stat {
if option_to_lookup != candidate { continue }
if !setter(&mut op, value) {
match value {
None => {
early_error(error_format, &format!("{0} option `{1}` requires \
{2} ({3} {1}=<value>)",
$outputname, key,
type_desc, $prefix))
}
Some(value) => {
early_error(error_format, &format!("incorrect value `{}` for {} \
option `{}` - {} was expected",
value, $outputname,
key, type_desc))
}
}
}
found = true;
break;
}
if !found {
early_error(error_format, &format!("unknown {} option: `{}`",
$outputname, key));
}
impl Default for $struct_name {
fn default() -> $struct_name {
$struct_name { $( $( #[$attr] )* $opt: $init),* }
}
return op;
}
impl $struct_name {
pub fn build(
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> $struct_name {
build_options(matches, $stat, $prefix, $outputname, error_format)
}
fn dep_tracking_hash(&self, _for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
let mut sub_hashes = BTreeMap::new();
$({
@ -284,26 +252,76 @@ macro_rules! options {
}
}
pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
pub const $stat: &[(&str, $setter_name, &str, &str)] =
&[ $( (stringify!($opt), $crate::options::parse::$opt, $crate::options::desc::$parse, $desc) ),* ];
// Sometimes different options need to build a common structure.
// That structure can kept in one of the options' fields, the others become dummy.
macro_rules! redirect_field {
($cg:ident.link_arg) => { $cg.link_args };
($cg:ident.pre_link_arg) => { $cg.pre_link_args };
($cg:ident.$field:ident) => { $cg.$field };
}
pub const $stat: OptionDescrs<$struct_name> =
&[ $( (stringify!($opt), $opt, desc::$parse, $desc) ),* ];
$(
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
$crate::options::parse::$parse(&mut redirect_field!(cg.$opt), v)
fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
parse::$parse(&mut redirect_field!(cg.$opt), v)
}
)*
) }
// Sometimes different options need to build a common structure.
// That structure can be kept in one of the options' fields, the others become dummy.
macro_rules! redirect_field {
($cg:ident.link_arg) => {
$cg.link_args
};
($cg:ident.pre_link_arg) => {
$cg.pre_link_args
};
($cg:ident.$field:ident) => {
$cg.$field
};
}
type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)];
fn build_options<O: Default>(
matches: &getopts::Matches,
descrs: OptionDescrs<O>,
prefix: &str,
outputname: &str,
error_format: ErrorOutputType,
) -> O {
let mut op = O::default();
for option in matches.opt_strs(prefix) {
let (key, value) = match option.split_once('=') {
None => (option, None),
Some((k, v)) => (k.to_string(), Some(v)),
};
let option_to_lookup = key.replace("-", "_");
match descrs.iter().find(|(name, ..)| *name == option_to_lookup) {
Some((_, setter, type_desc, _)) => {
if !setter(&mut op, value) {
match value {
None => early_error(
error_format,
&format!(
"{0} option `{1}` requires {2} ({3} {1}=<value>)",
outputname, key, type_desc, prefix
),
),
Some(value) => early_error(
error_format,
&format!(
"incorrect value `{}` for {} option `{}` - {} was expected",
value, outputname, key, type_desc
),
),
}
}
}
None => early_error(error_format, &format!("unknown {} option: `{}`", outputname, key)),
}
}
return op;
}
#[allow(non_upper_case_globals)]
mod desc {
pub const parse_no_flag: &str = "no value";
@ -847,9 +865,8 @@ mod parse {
}
}
options! {CodegenOptions, CodegenSetter, basic_codegen_options,
build_codegen_options, "C", "codegen",
CG_OPTIONS,
options! {
CodegenOptions, CG_OPTIONS, "C", "codegen",
// This list is in alphabetical order.
//
@ -957,9 +974,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
// - src/doc/rustc/src/codegen-options/index.md
}
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
build_debugging_options, "Z", "debugging",
DB_OPTIONS,
options! {
DebuggingOptions, DB_OPTIONS, "Z", "debugging",
// This list is in alphabetical order.
//

View File

@ -7,10 +7,7 @@ use std::str::FromStr;
use rustc_data_structures::fx::FxHashMap;
use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType};
use rustc_session::config::{
build_codegen_options, build_debugging_options, get_cmd_lint_options, host_triple,
nightly_options,
};
use rustc_session::config::{get_cmd_lint_options, host_triple, nightly_options};
use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
use rustc_session::getopts;
use rustc_session::lint::Level;
@ -360,8 +357,8 @@ impl Options {
config::parse_json(&matches);
let error_format = config::parse_error_format(&matches, color, json_rendered);
let codegen_options = build_codegen_options(matches, error_format);
let debugging_opts = build_debugging_options(matches, error_format);
let codegen_options = CodegenOptions::build(matches, error_format);
let debugging_opts = DebuggingOptions::build(matches, error_format);
let diag = new_handler(error_format, None, &debugging_opts);

View File

@ -76,7 +76,6 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
externs: options.externs.clone(),
unstable_features: options.render_options.unstable_features,
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions { ..config::basic_debugging_options() },
edition: options.edition,
target_triple: options.target.clone(),
crate_name: options.crate_name.clone(),