diff options
Diffstat (limited to 'compiler/rustc_session/src/config.rs')
-rw-r--r-- | compiler/rustc_session/src/config.rs | 335 |
1 files changed, 189 insertions, 146 deletions
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 79eb31bb1..6c8c8e484 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -421,7 +421,7 @@ pub enum TrimmedDefPaths { GoodPath, } -#[derive(Clone, Hash)] +#[derive(Clone, Hash, Debug)] pub enum ResolveDocLinks { /// Do not resolve doc links. None, @@ -518,6 +518,12 @@ pub struct ExternEntry { /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to /// suppress `unused-crate-dependencies` warnings. pub nounused_dep: bool, + /// If the extern entry is not referenced in the crate, force it to be resolved anyway. + /// + /// Allows a dependency satisfying, for instance, a missing panic handler to be injected + /// without modifying source: + /// `--extern force:extras=/path/to/lib/libstd.rlib` + pub force: bool, } #[derive(Clone, Debug)] @@ -556,7 +562,13 @@ impl Externs { impl ExternEntry { fn new(location: ExternLocation) -> ExternEntry { - ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false } + ExternEntry { + location, + is_private_dep: false, + add_prelude: false, + nounused_dep: false, + force: false, + } } pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> { @@ -587,6 +599,7 @@ pub enum PrintRequest { StackProtectorStrategies, LinkArgs, SplitDebuginfo, + DeploymentTarget, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -1036,9 +1049,20 @@ fn default_configuration(sess: &Session) -> CrateConfig { ret.insert((sym::sanitize, Some(symbol))); } + if sess.is_sanitizer_cfi_generalize_pointers_enabled() { + ret.insert((sym::sanitizer_cfi_generalize_pointers, None)); + } + + if sess.is_sanitizer_cfi_normalize_integers_enabled() { + ret.insert((sym::sanitizer_cfi_normalize_integers, None)); + } + if sess.opts.debug_assertions { ret.insert((sym::debug_assertions, None)); } + if sess.overflow_checks() { + ret.insert((sym::overflow_checks, None)); + } // JUSTIFICATION: before wrapper fn is available #[allow(rustc::bad_opt_access)] if sess.opts.crate_types.contains(&CrateType::ProcMacro) { @@ -1056,37 +1080,76 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig /// The parsed `--check-cfg` options pub struct CheckCfg<T = String> { - /// The set of all `names()`, if None no name checking is performed - pub names_valid: Option<FxHashSet<T>>, + /// Is well known names activated + pub exhaustive_names: bool, /// Is well known values activated - pub well_known_values: bool, - /// The set of all `values()` - pub values_valid: FxHashMap<T, FxHashSet<T>>, + pub exhaustive_values: bool, + /// All the expected values for a config name + pub expecteds: FxHashMap<T, ExpectedValues<T>>, } impl<T> Default for CheckCfg<T> { fn default() -> Self { CheckCfg { - names_valid: Default::default(), - values_valid: Default::default(), - well_known_values: false, + exhaustive_names: false, + exhaustive_values: false, + expecteds: FxHashMap::default(), } } } impl<T> CheckCfg<T> { - fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> { + fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> { CheckCfg { - names_valid: self - .names_valid - .as_ref() - .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()), - values_valid: self - .values_valid - .iter() - .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect())) + exhaustive_names: self.exhaustive_names, + exhaustive_values: self.exhaustive_values, + expecteds: self + .expecteds + .into_iter() + .map(|(name, values)| { + ( + f(name), + match values { + ExpectedValues::Some(values) => ExpectedValues::Some( + values.into_iter().map(|b| b.map(|b| f(b))).collect(), + ), + ExpectedValues::Any => ExpectedValues::Any, + }, + ) + }) .collect(), - well_known_values: self.well_known_values, + } + } +} + +pub enum ExpectedValues<T> { + Some(FxHashSet<Option<T>>), + Any, +} + +impl<T: Eq + Hash> ExpectedValues<T> { + fn insert(&mut self, value: T) -> bool { + match self { + ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)), + ExpectedValues::Any => false, + } + } +} + +impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> { + fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { + match self { + ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)), + ExpectedValues::Any => {} + } + } +} + +impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> { + fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { + match self { + ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))), + ExpectedValues::Any => {} } } } @@ -1095,58 +1158,27 @@ impl<T> CheckCfg<T> { /// `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)) + cfg.map_data(|s| Symbol::intern(&s)) } impl CrateCheckConfig { - /// Fills a `CrateCheckConfig` with well-known configuration names. - fn fill_well_known_names(&mut self) { - // NOTE: This should be kept in sync with `default_configuration` and - // `fill_well_known_values` - const WELL_KNOWN_NAMES: &[Symbol] = &[ - // rustc - sym::unix, - sym::windows, - sym::target_os, - sym::target_family, - sym::target_arch, - sym::target_endian, - sym::target_pointer_width, - sym::target_env, - sym::target_abi, - sym::target_vendor, - sym::target_thread_local, - sym::target_has_atomic_load_store, - sym::target_has_atomic, - sym::target_has_atomic_equal_alignment, - sym::target_feature, - sym::panic, - sym::sanitize, - sym::debug_assertions, - sym::proc_macro, - sym::test, - sym::feature, - // rustdoc - sym::doc, - sym::doctest, - // miri - sym::miri, - ]; - - // We only insert well-known names if `names()` was activated - if let Some(names_valid) = &mut self.names_valid { - names_valid.extend(WELL_KNOWN_NAMES); - } - } - - /// Fills a `CrateCheckConfig` with well-known configuration values. - fn fill_well_known_values(&mut self, current_target: &Target) { - if !self.well_known_values { + pub fn fill_well_known(&mut self, current_target: &Target) { + if !self.exhaustive_values && !self.exhaustive_names { return; } - // NOTE: This should be kept in sync with `default_configuration` and - // `fill_well_known_names` + let no_values = || { + let mut values = FxHashSet::default(); + values.insert(None); + ExpectedValues::Some(values) + }; + + let empty_values = || { + let values = FxHashSet::default(); + ExpectedValues::Some(values) + }; + + // NOTE: This should be kept in sync with `default_configuration` let panic_values = &PanicStrategy::all(); @@ -1166,6 +1198,9 @@ impl CrateCheckConfig { // Unknown possible values: // - `feature` // - `target_feature` + for name in [sym::feature, sym::target_feature] { + self.expecteds.entry(name).or_insert(ExpectedValues::Any); + } // No-values for name in [ @@ -1177,22 +1212,26 @@ impl CrateCheckConfig { sym::windows, sym::proc_macro, sym::debug_assertions, + sym::overflow_checks, sym::target_thread_local, ] { - self.values_valid.entry(name).or_default(); + self.expecteds.entry(name).or_insert_with(no_values); } // Pre-defined values - self.values_valid.entry(sym::panic).or_default().extend(panic_values); - self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values); - self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values); - self.values_valid + self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values); + self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values); + self.expecteds + .entry(sym::target_has_atomic) + .or_insert_with(no_values) + .extend(atomic_values); + self.expecteds .entry(sym::target_has_atomic_load_store) - .or_default() + .or_insert_with(no_values) .extend(atomic_values); - self.values_valid + self.expecteds .entry(sym::target_has_atomic_equal_alignment) - .or_default() + .or_insert_with(no_values) .extend(atomic_values); // Target specific values @@ -1210,47 +1249,50 @@ impl CrateCheckConfig { // Initialize (if not already initialized) for &e in VALUES { - self.values_valid.entry(e).or_default(); + let entry = self.expecteds.entry(e); + if !self.exhaustive_values { + entry.or_insert(ExpectedValues::Any); + } else { + entry.or_insert_with(empty_values); + } } - // Get all values map at once otherwise it would be costly. - // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). - let [ - values_target_os, - values_target_family, - values_target_arch, - values_target_endian, - values_target_env, - values_target_abi, - values_target_vendor, - values_target_pointer_width, - ] = self - .values_valid - .get_many_mut(VALUES) - .expect("unable to get all the check-cfg values buckets"); - - for target in TARGETS - .iter() - .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) - .chain(iter::once(current_target.clone())) - { - values_target_os.insert(Symbol::intern(&target.options.os)); - values_target_family - .extend(target.options.families.iter().map(|family| Symbol::intern(family))); - values_target_arch.insert(Symbol::intern(&target.arch)); - values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); - values_target_env.insert(Symbol::intern(&target.options.env)); - values_target_abi.insert(Symbol::intern(&target.options.abi)); - values_target_vendor.insert(Symbol::intern(&target.options.vendor)); - values_target_pointer_width.insert(sym::integer(target.pointer_width)); + if self.exhaustive_values { + // Get all values map at once otherwise it would be costly. + // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). + let [ + values_target_os, + values_target_family, + values_target_arch, + values_target_endian, + values_target_env, + values_target_abi, + values_target_vendor, + values_target_pointer_width, + ] = self + .expecteds + .get_many_mut(VALUES) + .expect("unable to get all the check-cfg values buckets"); + + for target in TARGETS + .iter() + .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) + .chain(iter::once(current_target.clone())) + { + values_target_os.insert(Symbol::intern(&target.options.os)); + values_target_family.extend( + target.options.families.iter().map(|family| Symbol::intern(family)), + ); + values_target_arch.insert(Symbol::intern(&target.arch)); + values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); + values_target_env.insert(Symbol::intern(&target.options.env)); + values_target_abi.insert(Symbol::intern(&target.options.abi)); + values_target_vendor.insert(Symbol::intern(&target.options.vendor)); + values_target_pointer_width.insert(sym::integer(target.pointer_width)); + } } } } - - pub fn fill_well_known(&mut self, current_target: &Target) { - self.fill_well_known_names(); - self.fill_well_known_values(current_target); - } } pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig { @@ -1277,7 +1319,7 @@ pub(super) fn build_target_config( let (target, target_warnings) = target_result.unwrap_or_else(|e| { early_error( opts.error_format, - &format!( + format!( "Error loading target specification: {}. \ Run `rustc --print target-list` for a list of built-in targets", e @@ -1285,15 +1327,14 @@ pub(super) fn build_target_config( ) }); for warning in target_warnings.warning_messages() { - early_warn(opts.error_format, &warning) + early_warn(opts.error_format, warning) } if !matches!(target.pointer_width, 16 | 32 | 64) { early_error( opts.error_format, - &format!( - "target specification was invalid: \ - unrecognized target-pointer-width {}", + format!( + "target specification was invalid: unrecognized target-pointer-width {}", target.pointer_width ), ) @@ -1400,7 +1441,8 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { vec![ opt::flag_s("h", "help", "Display this message"), - opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"), + opt::multi_s("", "cfg", "Configure the compilation environment. + SPEC supports the syntax `NAME[=\"VALUE\"]`.", "SPEC"), opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"), opt::multi_s( "L", @@ -1443,7 +1485,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\ target-list|target-cpus|target-features|relocation-models|code-models|\ tls-models|target-spec-json|all-target-specs-json|native-static-libs|\ - stack-protector-strategies|link-args]", + stack-protector-strategies|link-args|deployment-target]", ), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), @@ -1556,7 +1598,7 @@ pub fn get_cmd_lint_options( let lint_cap = matches.opt_str("cap-lints").map(|cap| { lint::Level::from_str(&cap) - .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`"))) + .unwrap_or_else(|| early_error(error_format, format!("unknown lint level: `{cap}`"))) }); (lint_opts, describe_lints, lint_cap) @@ -1573,7 +1615,7 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { Some(arg) => early_error( ErrorOutputType::default(), - &format!( + format!( "argument for `--color` must be auto, \ always or never (instead was `{arg}`)" ), @@ -1648,7 +1690,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { "future-incompat" => json_future_incompat = true, s => early_error( ErrorOutputType::default(), - &format!("unknown `--json` option `{s}`"), + format!("unknown `--json` option `{s}`"), ), } } @@ -1686,7 +1728,7 @@ pub fn parse_error_format( Some(arg) => early_error( ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), - &format!( + format!( "argument for `--error-format` must be `human`, `json` or \ `short` (instead was `{arg}`)" ), @@ -1720,7 +1762,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| { early_error( ErrorOutputType::default(), - &format!( + format!( "argument for `--edition` must be one of: \ {EDITION_NAME_LIST}. (instead was `{arg}`)" ), @@ -1739,7 +1781,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { } else { format!("edition {edition} is unstable and only available with -Z unstable-options") }; - early_error(ErrorOutputType::default(), &msg) + early_error(ErrorOutputType::default(), msg) } edition @@ -1784,7 +1826,7 @@ fn parse_output_types( let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { early_error( error_format, - &format!( + format!( "unknown emission type: `{shorthand}` - expected one of: {display}", display = OutputType::shorthands_display(), ), @@ -1823,7 +1865,7 @@ fn should_override_cgus_and_disable_thinlto( for ot in &incompatible { early_warn( error_format, - &format!( + format!( "`--emit={ot}` with `-o` incompatible with \ `-C codegen-units=N` for N > 1", ), @@ -1865,7 +1907,7 @@ fn collect_print_requests( error_format: ErrorOutputType, ) -> Vec<PrintRequest> { let mut prints = Vec::<PrintRequest>::new(); - if cg.target_cpu.as_ref().map_or(false, |s| s == "help") { + if cg.target_cpu.as_ref().is_some_and(|s| s == "help") { prints.push(PrintRequest::TargetCPUs); cg.target_cpu = None; }; @@ -1893,6 +1935,7 @@ fn collect_print_requests( ("all-target-specs-json", PrintRequest::AllTargetSpecs), ("link-args", PrintRequest::LinkArgs), ("split-debuginfo", PrintRequest::SplitDebuginfo), + ("deployment-target", PrintRequest::DeploymentTarget), ]; prints.extend(matches.opt_strs("print").into_iter().map(|req| { @@ -1926,7 +1969,7 @@ fn collect_print_requests( let prints = prints.join(", "); early_error( error_format, - &format!("unknown print request `{req}`. Valid print requests are: {prints}"), + format!("unknown print request `{req}`. Valid print requests are: {prints}"), ); } } @@ -1943,7 +1986,7 @@ pub fn parse_target_triple( Some(target) if target.ends_with(".json") => { let path = Path::new(&target); TargetTriple::from_path(path).unwrap_or_else(|_| { - early_error(error_format, &format!("target file {path:?} does not exist")) + early_error(error_format, format!("target file {path:?} does not exist")) }) } Some(target) => TargetTriple::TargetTriple(target), @@ -1984,7 +2027,7 @@ fn parse_opt_level( arg => { early_error( error_format, - &format!( + format!( "optimization level needs to be \ between 0-3, s or z (instead was `{arg}`)" ), @@ -2015,7 +2058,7 @@ pub(crate) fn parse_assert_incr_state( Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), Some(s) => { - early_error(error_format, &format!("unexpected incremental state assertion value: {s}")) + early_error(error_format, format!("unexpected incremental state assertion value: {s}")) } None => None, } @@ -2042,13 +2085,13 @@ fn parse_native_lib_kind( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_error(error_format, &format!("library kind `link-arg` is unstable{why}")) + early_error(error_format, format!("library kind `link-arg` is unstable{why}")) } NativeLibKind::LinkArg } _ => early_error( error_format, - &format!( + format!( "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg" ), ), @@ -2083,16 +2126,13 @@ fn parse_native_lib_modifiers( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_error( - error_format, - &format!("linking modifier `{modifier}` is unstable{why}"), - ) + early_error(error_format, format!("linking modifier `{modifier}` is unstable{why}")) } }; let assign_modifier = |dst: &mut Option<bool>| { if dst.is_some() { let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); - early_error(error_format, &msg) + early_error(error_format, msg) } else { *dst = Some(value); } @@ -2129,7 +2169,7 @@ fn parse_native_lib_modifiers( // string, like `modifiers = ""`. _ => early_error( error_format, - &format!( + format!( "unknown linking modifier `{modifier}`, expected one \ of: bundle, verbatim, whole-archive, as-needed" ), @@ -2235,6 +2275,7 @@ pub fn parse_externs( let mut is_private_dep = false; let mut add_prelude = true; let mut nounused_dep = false; + let mut force = false; if let Some(opts) = options { if !is_unstable_enabled { early_error( @@ -2257,7 +2298,8 @@ pub fn parse_externs( } } "nounused" => nounused_dep = true, - _ => early_error(error_format, &format!("unknown --extern option `{opt}`")), + "force" => force = true, + _ => early_error(error_format, format!("unknown --extern option `{opt}`")), } } } @@ -2267,6 +2309,8 @@ pub fn parse_externs( entry.is_private_dep |= is_private_dep; // likewise `nounused` entry.nounused_dep |= nounused_dep; + // and `force` + entry.force |= force; // If any flag is missing `noprelude`, then add to the prelude. entry.add_prelude |= add_prelude; } @@ -2321,7 +2365,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let unparsed_crate_types = matches.opt_strs("crate-type"); let crate_types = parse_crate_types_from_list(unparsed_crate_types) - .unwrap_or_else(|e| early_error(error_format, &e)); + .unwrap_or_else(|e| early_error(error_format, e)); let mut unstable_opts = UnstableOptions::build(matches, error_format); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -2549,7 +2593,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }; let working_dir = std::env::current_dir().unwrap_or_else(|e| { - early_error(error_format, &format!("Current directory is invalid: {e}")); + early_error(error_format, format!("Current directory is invalid: {e}")); }); let remap = FilePathMapping::new(remap_path_prefix.clone()); @@ -2621,7 +2665,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "mir-cfg" => MirCFG, name => early_error( efmt, - &format!( + format!( "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ @@ -2699,7 +2743,7 @@ pub mod nightly_options { if opt.name != "Z" && !has_z_unstable_option { early_error( ErrorOutputType::default(), - &format!( + format!( "the `-Z unstable-options` flag must also be passed to enable \ the flag `{}`", opt.name @@ -2712,11 +2756,10 @@ pub mod nightly_options { match opt.stability { OptionStability::Unstable => { let msg = format!( - "the option `{}` is only accepted on the \ - nightly compiler", + "the option `{}` is only accepted on the nightly compiler", opt.name ); - early_error(ErrorOutputType::default(), &msg); + early_error(ErrorOutputType::default(), msg); } OptionStability::Stable => {} } |