Clean up config mess.

`parse_cfgspecs` and `parse_check_cfg` run very early, before the main
interner is running. They each use a short-lived interner and convert
all interned symbols to strings in their output data structures. Once
the main interner starts up, these data structures get converted into
new data structures that are identical except with the strings converted
to symbols.

All is not obvious from the current code, which is a mess, particularly
with inconsistent naming that obscures the parallel string/symbol data
structures. This commit clean things up a lot.

- The existing `CheckCfg` type is generic, allowing both
  `CheckCfg<String>` and `CheckCfg<Symbol>` forms. This is really
  useful, but it defaults to `String`. The commit removes the default so
  we have to use `CheckCfg<String>` and `CheckCfg<Symbol>` explicitly,
  which makes things clearer.

- Introduces `Cfg`, which is generic over `String` and `Symbol`, similar
  to `CheckCfg`.

- Renames some things.
  - `parse_cfgspecs` -> `parse_cfg`
  - `CfgSpecs` -> `Cfg<String>`, plus it's used in more places, rather
    than the underlying `FxHashSet` type.
  - `CrateConfig` -> `Cfg<Symbol>`.
  - `CrateCheckConfig` -> `CheckCfg<Symbol>`

- Adds some comments explaining the string-to-symbol conversions.

- `to_crate_check_config`, which converts `CheckCfg<String>` to
  `CheckCfg<Symbol>`, is inlined and removed and combined with the
  overly-general `CheckCfg::map_data` to produce
  `CheckCfg::<String>::intern`.

- `build_configuration` now does the `Cfg<String>`-to-`Cfg<Symbol>`
  conversion, so callers don't need to, which removes the need for
  `to_crate_config`.

The diff for two of the fields in `Config` is a good example of the
improved clarity:
```
-    pub crate_cfg: FxHashSet<(String, Option<String>)>,
-    pub crate_check_cfg: CheckCfg,
+    pub crate_cfg: Cfg<String>,
+    pub crate_check_cfg: CheckCfg<String>,
```
Compare that with the diff for the corresponding fields in `ParseSess`,
and the relationship to `Config` is much clearer than before:
```
-    pub config: CrateConfig,
-    pub check_config: CrateCheckConfig,
+    pub config: Cfg<Symbol>,
+    pub check_config: CheckCfg<Symbol>,
```
This commit is contained in:
Nicholas Nethercote 2023-10-27 15:58:02 +11:00
parent 75e415ba86
commit 5e54997157
8 changed files with 65 additions and 71 deletions

View File

@ -318,7 +318,7 @@ fn run_compiler(
return Ok(()); return Ok(());
} }
let cfg = interface::parse_cfgspecs(&early_error_handler, matches.opt_strs("cfg")); let cfg = interface::parse_cfg(&early_error_handler, matches.opt_strs("cfg"));
let check_cfg = interface::parse_check_cfg(&early_error_handler, matches.opt_strs("check-cfg")); let check_cfg = interface::parse_check_cfg(&early_error_handler, matches.opt_strs("check-cfg"));
let (odir, ofile) = make_output(&matches); let (odir, ofile) = make_output(&matches);
let mut config = interface::Config { let mut config = interface::Config {

View File

@ -15,7 +15,9 @@ use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt; use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack; use rustc_query_system::query::print_query_stack;
use rustc_session::config::{self, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames}; use rustc_session::config::{
self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames,
};
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_session::CompilerIO; use rustc_session::CompilerIO;
use rustc_session::Session; use rustc_session::Session;
@ -61,14 +63,13 @@ impl Compiler {
} }
} }
/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
pub fn parse_cfgspecs( pub fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg<String> {
handler: &EarlyErrorHandler, // This creates a short-lived `SessionGlobals`, containing an interner. The
cfgspecs: Vec<String>, // parsed values are converted from symbols to strings before exiting
) -> FxHashSet<(String, Option<String>)> { // because the symbols are meaningless once the interner is gone.
rustc_span::create_default_session_if_not_set_then(move |_| { rustc_span::create_default_session_if_not_set_then(move |_| {
cfgspecs cfgs.into_iter()
.into_iter()
.map(|s| { .map(|s| {
let sess = ParseSess::with_silent_emitter(Some(format!( let sess = ParseSess::with_silent_emitter(Some(format!(
"this error occurred on the command line: `--cfg={s}`" "this error occurred on the command line: `--cfg={s}`"
@ -121,12 +122,14 @@ pub fn parse_cfgspecs(
error!(r#"expected `key` or `key="value"`"#); error!(r#"expected `key` or `key="value"`"#);
} }
}) })
.collect::<FxHashSet<_>>() .collect::<Cfg<String>>()
}) })
} }
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg { pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg<String> {
// The comment about `SessionGlobals` and symbols in `parse_cfg` above
// applies here too.
rustc_span::create_default_session_if_not_set_then(move |_| { rustc_span::create_default_session_if_not_set_then(move |_| {
// If any --check-cfg is passed then exhaustive_values and exhaustive_names // If any --check-cfg is passed then exhaustive_values and exhaustive_names
// are enabled by default. // are enabled by default.
@ -374,8 +377,8 @@ pub struct Config {
pub opts: config::Options, pub opts: config::Options,
/// cfg! configuration in addition to the default ones /// cfg! configuration in addition to the default ones
pub crate_cfg: FxHashSet<(String, Option<String>)>, pub crate_cfg: Cfg<String>,
pub crate_check_cfg: CheckCfg, pub crate_check_cfg: CheckCfg<String>,
pub input: Input, pub input: Input,
pub output_dir: Option<PathBuf>, pub output_dir: Option<PathBuf>,

View File

@ -1,17 +1,16 @@
#![allow(rustc::bad_opt_access)] #![allow(rustc::bad_opt_access)]
use crate::interface::parse_cfgspecs; use crate::interface::parse_cfg;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::profiling::TimePassesFormat; use rustc_data_structures::profiling::TimePassesFormat;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
use rustc_session::config::rustc_optgroups; use rustc_session::config::rustc_optgroups;
use rustc_session::config::Cfg;
use rustc_session::config::DebugInfo; use rustc_session::config::DebugInfo;
use rustc_session::config::Input; use rustc_session::config::Input;
use rustc_session::config::InstrumentXRay; use rustc_session::config::InstrumentXRay;
use rustc_session::config::LinkSelfContained; use rustc_session::config::LinkSelfContained;
use rustc_session::config::Polonius; use rustc_session::config::Polonius;
use rustc_session::config::TraitSolver; use rustc_session::config::TraitSolver;
use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{build_configuration, build_session_options};
use rustc_session::config::{ use rustc_session::config::{
BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel, ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
@ -31,18 +30,18 @@ use rustc_span::FileName;
use rustc_span::SourceFileHashAlgorithm; use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel}; use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
type CfgSpecs = FxHashSet<(String, Option<String>)>; fn mk_session(
handler: &mut EarlyErrorHandler,
fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) { matches: getopts::Matches,
) -> (Session, Cfg<String>) {
let registry = registry::Registry::new(&[]); let registry = registry::Registry::new(&[]);
let sessopts = build_session_options(handler, &matches); let sessopts = build_session_options(handler, &matches);
let cfg = parse_cfgspecs(handler, matches.opt_strs("cfg")); let cfg = parse_cfg(handler, matches.opt_strs("cfg"));
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let io = CompilerIO { let io = CompilerIO {
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() }, input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@ -133,7 +132,7 @@ fn test_switch_implies_cfg_test() {
let matches = optgroups().parse(&["--test".to_string()]).unwrap(); let matches = optgroups().parse(&["--test".to_string()]).unwrap();
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches); let (sess, cfg) = mk_session(&mut handler, matches);
let cfg = build_configuration(&sess, to_crate_config(cfg)); let cfg = build_configuration(&sess, cfg);
assert!(cfg.contains(&(sym::test, None))); assert!(cfg.contains(&(sym::test, None)));
}); });
} }
@ -145,7 +144,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap(); let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
let (sess, cfg) = mk_session(&mut handler, matches); let (sess, cfg) = mk_session(&mut handler, matches);
let cfg = build_configuration(&sess, to_crate_config(cfg)); let cfg = build_configuration(&sess, cfg);
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test); let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
assert!(test_items.next().is_some()); assert!(test_items.next().is_some());
assert!(test_items.next().is_none()); assert!(test_items.next().is_none());

View File

@ -3,18 +3,17 @@ use info;
use libloading::Library; use libloading::Library;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::FxHashMap;
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
use rustc_data_structures::sync; use rustc_data_structures::sync;
use rustc_errors::registry::Registry; use rustc_errors::registry::Registry;
use rustc_parse::validate_attr; use rustc_parse::validate_attr;
use rustc_session as session; use rustc_session as session;
use rustc_session::config::CheckCfg; use rustc_session::config::{
use rustc_session::config::{self, CrateType}; self, Cfg, CheckCfg, CrateType, OutFileName, OutputFilenames, OutputTypes,
use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes}; };
use rustc_session::filesearch::sysroot_candidates; use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
use rustc_session::{filesearch, output, Session}; use rustc_session::{filesearch, output, Session};
use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -38,7 +37,7 @@ pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
/// This is performed by checking whether a set of permitted features /// This is performed by checking whether a set of permitted features
/// is available on the target machine, by querying the codegen backend. /// is available on the target machine, by querying the codegen backend.
pub fn add_configuration( pub fn add_configuration(
cfg: &mut CrateConfig, cfg: &mut Cfg<Symbol>,
sess: &mut Session, sess: &mut Session,
codegen_backend: &dyn CodegenBackend, codegen_backend: &dyn CodegenBackend,
) { ) {
@ -60,8 +59,8 @@ pub fn add_configuration(
pub fn create_session( pub fn create_session(
handler: &EarlyErrorHandler, handler: &EarlyErrorHandler,
sopts: config::Options, sopts: config::Options,
cfg: FxHashSet<(String, Option<String>)>, cfg: Cfg<String>,
check_cfg: CheckCfg, check_cfg: CheckCfg<String>,
locale_resources: &'static [&'static str], locale_resources: &'static [&'static str],
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
io: CompilerIO, io: CompilerIO,
@ -121,12 +120,13 @@ pub fn create_session(
codegen_backend.init(&sess); codegen_backend.init(&sess);
let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); let mut cfg = config::build_configuration(&sess, cfg);
add_configuration(&mut cfg, &mut sess, &*codegen_backend); add_configuration(&mut cfg, &mut sess, &*codegen_backend);
let mut check_cfg = config::to_crate_check_config(check_cfg); let mut check_cfg = check_cfg.intern();
check_cfg.fill_well_known(&sess.target); check_cfg.fill_well_known(&sess.target);
// These configs use symbols, rather than strings.
sess.parse_sess.config = cfg; sess.parse_sess.config = cfg;
sess.parse_sess.check_config = check_cfg; sess.parse_sess.check_config = check_cfg;

View File

@ -16,7 +16,6 @@ use rustc_target::spec::LinkSelfContainedComponents;
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo};
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
use crate::parse::{CrateCheckConfig, CrateConfig};
use rustc_feature::UnstableFeatures; use rustc_feature::UnstableFeatures;
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
use rustc_span::source_map::{FileName, FilePathMapping}; use rustc_span::source_map::{FileName, FilePathMapping};
@ -1248,8 +1247,8 @@ pub const fn default_lib_output() -> CrateType {
CrateType::Rlib CrateType::Rlib
} }
fn default_configuration(sess: &Session) -> CrateConfig { fn default_configuration(sess: &Session) -> Cfg<Symbol> {
// NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below. // NOTE: This should be kept in sync with `CheckCfg::<Symbol>::fill_well_known` below.
let end = &sess.target.endian; let end = &sess.target.endian;
let arch = &sess.target.arch; let arch = &sess.target.arch;
let wordsz = sess.target.pointer_width.to_string(); let wordsz = sess.target.pointer_width.to_string();
@ -1265,7 +1264,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
sess.emit_fatal(err); sess.emit_fatal(err);
}); });
let mut ret = CrateConfig::default(); let mut ret = Cfg::default();
ret.reserve(7); // the minimum number of insertions ret.reserve(7); // the minimum number of insertions
// Target bindings. // Target bindings.
ret.insert((sym::target_os, Some(Symbol::intern(os)))); ret.insert((sym::target_os, Some(Symbol::intern(os))));
@ -1358,15 +1357,14 @@ fn default_configuration(sess: &Session) -> CrateConfig {
ret ret
} }
/// Converts the crate `cfg!` configuration from `String` to `Symbol`. /// The parsed `--cfg` options that define the compilation environment of the
/// `rustc_interface::interface::Config` accepts this in the compiler configuration, /// crate, used to drive conditional compilation. `T` is always `String` or
/// but the symbol interner is not yet set up then, so we must convert it later. /// `Symbol`. Strings are used temporarily very early on. Once the the main
pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig { /// symbol interner is running, they are converted to symbols.
cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect() pub type Cfg<T> = FxHashSet<(T, Option<T>)>;
}
/// The parsed `--check-cfg` options /// The parsed `--check-cfg` options. The `<T>` structure is similar to `Cfg`.
pub struct CheckCfg<T = String> { pub struct CheckCfg<T> {
/// Is well known names activated /// Is well known names activated
pub exhaustive_names: bool, pub exhaustive_names: bool,
/// Is well known values activated /// Is well known values activated
@ -1385,8 +1383,8 @@ impl<T> Default for CheckCfg<T> {
} }
} }
impl<T> CheckCfg<T> { impl CheckCfg<String> {
fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> { pub fn intern(self) -> CheckCfg<Symbol> {
CheckCfg { CheckCfg {
exhaustive_names: self.exhaustive_names, exhaustive_names: self.exhaustive_names,
exhaustive_values: self.exhaustive_values, exhaustive_values: self.exhaustive_values,
@ -1395,10 +1393,10 @@ impl<T> CheckCfg<T> {
.into_iter() .into_iter()
.map(|(name, values)| { .map(|(name, values)| {
( (
f(name), Symbol::intern(&name),
match values { match values {
ExpectedValues::Some(values) => ExpectedValues::Some( ExpectedValues::Some(values) => ExpectedValues::Some(
values.into_iter().map(|b| b.map(|b| f(b))).collect(), values.into_iter().map(|b| b.map(|b| Symbol::intern(&b))).collect(),
), ),
ExpectedValues::Any => ExpectedValues::Any, ExpectedValues::Any => ExpectedValues::Any,
}, },
@ -1441,14 +1439,7 @@ impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
} }
} }
/// Converts the crate `--check-cfg` options from `String` to `Symbol`. impl CheckCfg<Symbol> {
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
/// but the symbol interner is not yet set up then, so we must convert it later.
pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
cfg.map_data(|s| Symbol::intern(&s))
}
impl CrateCheckConfig {
pub fn fill_well_known(&mut self, current_target: &Target) { pub fn fill_well_known(&mut self, current_target: &Target) {
if !self.exhaustive_values && !self.exhaustive_names { if !self.exhaustive_values && !self.exhaustive_names {
return; return;
@ -1588,7 +1579,13 @@ impl CrateCheckConfig {
} }
} }
pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig { pub fn build_configuration(sess: &Session, user_cfg: Cfg<String>) -> Cfg<Symbol> {
// We can now intern these strings.
let mut user_cfg: Cfg<Symbol> = user_cfg
.into_iter()
.map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
.collect();
// Combine the configuration requested by the session (command line) with // Combine the configuration requested by the session (command line) with
// some default and generated configuration items. // some default and generated configuration items.
let default_cfg = default_configuration(sess); let default_cfg = default_configuration(sess);

View File

@ -1,7 +1,7 @@
//! Contains `ParseSess` which holds state living beyond what one `Parser` might. //! Contains `ParseSess` which holds state living beyond what one `Parser` might.
//! It also serves as an input to the parser itself. //! It also serves as an input to the parser itself.
use crate::config::CheckCfg; use crate::config::{Cfg, CheckCfg};
use crate::errors::{ use crate::errors::{
CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError, CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError,
}; };
@ -25,11 +25,6 @@ use rustc_span::{Span, Symbol};
use rustc_ast::attr::AttrIdGenerator; use rustc_ast::attr::AttrIdGenerator;
use std::str; use std::str;
/// The set of keys (and, optionally, values) that define the compilation
/// environment of the crate, used to drive conditional compilation.
pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>;
pub type CrateCheckConfig = CheckCfg<Symbol>;
/// Collected spans during parsing for places where a certain feature was /// Collected spans during parsing for places where a certain feature was
/// used and should be feature gated accordingly in `check_crate`. /// used and should be feature gated accordingly in `check_crate`.
#[derive(Default)] #[derive(Default)]
@ -193,8 +188,8 @@ pub fn add_feature_diagnostics_for_issue(
pub struct ParseSess { pub struct ParseSess {
pub span_diagnostic: Handler, pub span_diagnostic: Handler,
pub unstable_features: UnstableFeatures, pub unstable_features: UnstableFeatures,
pub config: CrateConfig, pub config: Cfg<Symbol>,
pub check_config: CrateCheckConfig, pub check_config: CheckCfg<Symbol>,
pub edition: Edition, pub edition: Edition,
/// Places where raw identifiers were used. This is used to avoid complaining about idents /// Places where raw identifiers were used. This is used to avoid complaining about idents
/// clashing with keywords in new editions. /// clashing with keywords in new editions.
@ -237,8 +232,8 @@ impl ParseSess {
Self { Self {
span_diagnostic: handler, span_diagnostic: handler,
unstable_features: UnstableFeatures::from_environment(None), unstable_features: UnstableFeatures::from_environment(None),
config: FxHashSet::default(), config: Cfg::default(),
check_config: CrateCheckConfig::default(), check_config: CheckCfg::default(),
edition: ExpnId::root().expn_data().edition, edition: ExpnId::root().expn_data().edition,
raw_identifier_spans: Default::default(), raw_identifier_spans: Default::default(),
bad_unicode_identifiers: Lock::new(Default::default()), bad_unicode_identifiers: Lock::new(Default::default()),

View File

@ -255,7 +255,7 @@ pub(crate) fn create_config(
interface::Config { interface::Config {
opts: sessopts, opts: sessopts,
crate_cfg: interface::parse_cfgspecs(handler, cfgs), crate_cfg: interface::parse_cfg(handler, cfgs),
crate_check_cfg: interface::parse_check_cfg(handler, check_cfgs), crate_check_cfg: interface::parse_check_cfg(handler, check_cfgs),
input, input,
output_file: None, output_file: None,

View File

@ -92,7 +92,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
cfgs.push("doctest".to_owned()); cfgs.push("doctest".to_owned());
let config = interface::Config { let config = interface::Config {
opts: sessopts, opts: sessopts,
crate_cfg: interface::parse_cfgspecs(&early_error_handler, cfgs), crate_cfg: interface::parse_cfg(&early_error_handler, cfgs),
crate_check_cfg: interface::parse_check_cfg( crate_check_cfg: interface::parse_check_cfg(
&early_error_handler, &early_error_handler,
options.check_cfgs.clone(), options.check_cfgs.clone(),