diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 331843ab051..635930742fc 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -318,7 +318,7 @@ fn run_compiler( 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 (odir, ofile) = make_output(&matches); let mut config = interface::Config { diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 26d7d26c31c..7672523292b 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -15,7 +15,9 @@ use rustc_middle::{bug, ty}; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; 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::CompilerIO; use rustc_session::Session; @@ -61,14 +63,13 @@ impl Compiler { } } -/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. -pub fn parse_cfgspecs( - handler: &EarlyErrorHandler, - cfgspecs: Vec, -) -> FxHashSet<(String, Option)> { +/// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. +pub fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec) -> Cfg { + // This creates a short-lived `SessionGlobals`, containing an interner. The + // parsed values are converted from symbols to strings before exiting + // because the symbols are meaningless once the interner is gone. rustc_span::create_default_session_if_not_set_then(move |_| { - cfgspecs - .into_iter() + cfgs.into_iter() .map(|s| { let sess = ParseSess::with_silent_emitter(Some(format!( "this error occurred on the command line: `--cfg={s}`" @@ -121,12 +122,14 @@ pub fn parse_cfgspecs( error!(r#"expected `key` or `key="value"`"#); } }) - .collect::>() + .collect::>() }) } /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. -pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec) -> CheckCfg { +pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec) -> CheckCfg { + // The comment about `SessionGlobals` and symbols in `parse_cfg` above + // applies here too. rustc_span::create_default_session_if_not_set_then(move |_| { // If any --check-cfg is passed then exhaustive_values and exhaustive_names // are enabled by default. @@ -374,8 +377,8 @@ pub struct Config { pub opts: config::Options, /// cfg! configuration in addition to the default ones - pub crate_cfg: FxHashSet<(String, Option)>, - pub crate_check_cfg: CheckCfg, + pub crate_cfg: Cfg, + pub crate_check_cfg: CheckCfg, pub input: Input, pub output_dir: Option, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 444c184dc2d..26cd83ac968 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -1,17 +1,16 @@ #![allow(rustc::bad_opt_access)] -use crate::interface::parse_cfgspecs; - -use rustc_data_structures::fx::FxHashSet; +use crate::interface::parse_cfg; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::rustc_optgroups; +use rustc_session::config::Cfg; use rustc_session::config::DebugInfo; use rustc_session::config::Input; use rustc_session::config::InstrumentXRay; use rustc_session::config::LinkSelfContained; use rustc_session::config::Polonius; 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::{ BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel, @@ -31,18 +30,18 @@ use rustc_span::FileName; use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel}; use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; - use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; use std::sync::Arc; -type CfgSpecs = FxHashSet<(String, Option)>; - -fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) { +fn mk_session( + handler: &mut EarlyErrorHandler, + matches: getopts::Matches, +) -> (Session, Cfg) { let registry = registry::Registry::new(&[]); 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 io = CompilerIO { 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 mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); 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))); }); } @@ -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 mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); 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); assert!(test_items.next().is_some()); assert!(test_items.next().is_none()); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index d2455a036cc..4d0be65697a 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -3,18 +3,17 @@ use info; use libloading::Library; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; #[cfg(parallel_compiler)] use rustc_data_structures::sync; use rustc_errors::registry::Registry; use rustc_parse::validate_attr; use rustc_session as session; -use rustc_session::config::CheckCfg; -use rustc_session::config::{self, CrateType}; -use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes}; +use rustc_session::config::{ + self, Cfg, CheckCfg, CrateType, OutFileName, OutputFilenames, OutputTypes, +}; use rustc_session::filesearch::sysroot_candidates; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; -use rustc_session::parse::CrateConfig; use rustc_session::{filesearch, output, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; @@ -38,7 +37,7 @@ pub type MakeBackendFn = fn() -> Box; /// This is performed by checking whether a set of permitted features /// is available on the target machine, by querying the codegen backend. pub fn add_configuration( - cfg: &mut CrateConfig, + cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend, ) { @@ -60,8 +59,8 @@ pub fn add_configuration( pub fn create_session( handler: &EarlyErrorHandler, sopts: config::Options, - cfg: FxHashSet<(String, Option)>, - check_cfg: CheckCfg, + cfg: Cfg, + check_cfg: CheckCfg, locale_resources: &'static [&'static str], file_loader: Option>, io: CompilerIO, @@ -121,12 +120,13 @@ pub fn create_session( 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); - 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); + // These configs use symbols, rather than strings. sess.parse_sess.config = cfg; sess.parse_sess.check_config = check_cfg; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7aced414ed6..fef4dfba6d2 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -16,7 +16,6 @@ use rustc_target::spec::LinkSelfContainedComponents; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; -use crate::parse::{CrateCheckConfig, CrateConfig}; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::{FileName, FilePathMapping}; @@ -1248,8 +1247,8 @@ pub const fn default_lib_output() -> CrateType { CrateType::Rlib } -fn default_configuration(sess: &Session) -> CrateConfig { - // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below. +fn default_configuration(sess: &Session) -> Cfg { + // NOTE: This should be kept in sync with `CheckCfg::::fill_well_known` below. let end = &sess.target.endian; let arch = &sess.target.arch; let wordsz = sess.target.pointer_width.to_string(); @@ -1265,7 +1264,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { sess.emit_fatal(err); }); - let mut ret = CrateConfig::default(); + let mut ret = Cfg::default(); ret.reserve(7); // the minimum number of insertions // Target bindings. ret.insert((sym::target_os, Some(Symbol::intern(os)))); @@ -1358,15 +1357,14 @@ fn default_configuration(sess: &Session) -> CrateConfig { ret } -/// Converts the crate `cfg!` configuration from `String` to `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_config(cfg: FxHashSet<(String, Option)>) -> CrateConfig { - cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect() -} +/// The parsed `--cfg` options that define the compilation environment of the +/// crate, used to drive conditional compilation. `T` is always `String` or +/// `Symbol`. Strings are used temporarily very early on. Once the the main +/// symbol interner is running, they are converted to symbols. +pub type Cfg = FxHashSet<(T, Option)>; -/// The parsed `--check-cfg` options -pub struct CheckCfg { +/// The parsed `--check-cfg` options. The `` structure is similar to `Cfg`. +pub struct CheckCfg { /// Is well known names activated pub exhaustive_names: bool, /// Is well known values activated @@ -1385,8 +1383,8 @@ impl Default for CheckCfg { } } -impl CheckCfg { - fn map_data(self, f: impl Fn(T) -> O) -> CheckCfg { +impl CheckCfg { + pub fn intern(self) -> CheckCfg { CheckCfg { exhaustive_names: self.exhaustive_names, exhaustive_values: self.exhaustive_values, @@ -1395,10 +1393,10 @@ impl CheckCfg { .into_iter() .map(|(name, values)| { ( - f(name), + Symbol::intern(&name), match values { 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, }, @@ -1441,14 +1439,7 @@ impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues { } } -/// Converts the crate `--check-cfg` options from `String` to `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 { +impl CheckCfg { pub fn fill_well_known(&mut self, current_target: &Target) { if !self.exhaustive_values && !self.exhaustive_names { 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) -> Cfg { + // We can now intern these strings. + let mut user_cfg: Cfg = 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 // some default and generated configuration items. let default_cfg = default_configuration(sess); diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 316b9cc7acb..5b98ee5d992 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -1,7 +1,7 @@ //! Contains `ParseSess` which holds state living beyond what one `Parser` might. //! It also serves as an input to the parser itself. -use crate::config::CheckCfg; +use crate::config::{Cfg, CheckCfg}; use crate::errors::{ CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError, }; @@ -25,11 +25,6 @@ use rustc_span::{Span, Symbol}; use rustc_ast::attr::AttrIdGenerator; 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)>; -pub type CrateCheckConfig = CheckCfg; - /// Collected spans during parsing for places where a certain feature was /// used and should be feature gated accordingly in `check_crate`. #[derive(Default)] @@ -193,8 +188,8 @@ pub fn add_feature_diagnostics_for_issue( pub struct ParseSess { pub span_diagnostic: Handler, pub unstable_features: UnstableFeatures, - pub config: CrateConfig, - pub check_config: CrateCheckConfig, + pub config: Cfg, + pub check_config: CheckCfg, pub edition: Edition, /// Places where raw identifiers were used. This is used to avoid complaining about idents /// clashing with keywords in new editions. @@ -237,8 +232,8 @@ impl ParseSess { Self { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(None), - config: FxHashSet::default(), - check_config: CrateCheckConfig::default(), + config: Cfg::default(), + check_config: CheckCfg::default(), edition: ExpnId::root().expn_data().edition, raw_identifier_spans: Default::default(), bad_unicode_identifiers: Lock::new(Default::default()), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 94e557dcfdb..bcc61df7c4d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -255,7 +255,7 @@ pub(crate) fn create_config( interface::Config { 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), input, output_file: None, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 97913345e8f..c61c98e4de9 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -92,7 +92,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { cfgs.push("doctest".to_owned()); let config = interface::Config { 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( &early_error_handler, options.check_cfgs.clone(),