summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_session/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_session/src')
-rw-r--r--compiler/rustc_session/src/config.rs335
-rw-r--r--compiler/rustc_session/src/cstore.rs11
-rw-r--r--compiler/rustc_session/src/errors.rs35
-rw-r--r--compiler/rustc_session/src/filesearch.rs4
-rw-r--r--compiler/rustc_session/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/options.rs33
-rw-r--r--compiler/rustc_session/src/parse.rs7
-rw-r--r--compiler/rustc_session/src/session.rs116
8 files changed, 340 insertions, 203 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 => {}
}
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index dd1721801..dc475e8c6 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -6,7 +6,8 @@ use crate::search_paths::PathKind;
use crate::utils::NativeLibKind;
use crate::Session;
use rustc_ast as ast;
-use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock};
+use rustc_data_structures::owned_slice::OwnedSlice;
+use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -203,11 +204,11 @@ pub enum ExternCrateSource {
/// metadata in library -- this trait just serves to decouple rustc_metadata from
/// the archive reader, which depends on LLVM.
pub trait MetadataLoader: std::fmt::Debug {
- fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>;
- fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>;
+ fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
+ fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
}
-pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync;
+pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;
/// A store of Rust crates, through which their metadata can be accessed.
///
@@ -252,7 +253,7 @@ pub trait CrateStore: std::fmt::Debug {
fn import_source_files(&self, sess: &Session, cnum: CrateNum);
}
-pub type CrateStoreDyn = dyn CrateStore + sync::Sync + sync::Send;
+pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend;
pub struct Untracked {
pub cstore: RwLock<Box<CrateStoreDyn>>,
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index bd32adbbd..546c0fa8e 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_ast::token;
use rustc_ast::util::literal::LitError;
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
use rustc_macros::Diagnostic;
-use rustc_span::{Span, Symbol};
+use rustc_span::{BytePos, Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
#[derive(Diagnostic)]
@@ -111,8 +111,24 @@ pub struct CannotMixAndMatchSanitizers {
pub struct CannotEnableCrtStaticLinux;
#[derive(Diagnostic)]
-#[diag(session_sanitizer_cfi_enabled)]
-pub struct SanitizerCfiEnabled;
+#[diag(session_sanitizer_cfi_requires_lto)]
+pub struct SanitizerCfiRequiresLto;
+
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_cfi_canonical_jump_tables_requires_cfi)]
+pub struct SanitizerCfiCanonicalJumpTablesRequiresCfi;
+
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_cfi_generalize_pointers_requires_cfi)]
+pub struct SanitizerCfiGeneralizePointersRequiresCfi;
+
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
+pub struct SanitizerCfiNormalizeIntegersRequiresCfi;
+
+#[derive(Diagnostic)]
+#[diag(session_split_lto_unit_requires_lto)]
+pub struct SplitLtoUnitRequiresLto;
#[derive(Diagnostic)]
#[diag(session_unstable_virtual_function_elimination)]
@@ -307,6 +323,13 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
pub span: Span,
}
+#[derive(Diagnostic)]
+#[diag(session_nul_in_c_str)]
+pub(crate) struct NulInCStr {
+ #[primary_span]
+ pub span: Span,
+}
+
pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
// Checks if `s` looks like i32 or u1234 etc.
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -385,6 +408,12 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
};
sess.emit_err(IntLiteralTooLarge { span, limit });
}
+ LitError::NulInCStr(range) => {
+ let lo = BytePos(span.lo().0 + range.start as u32 + 2);
+ let hi = BytePos(span.lo().0 + range.end as u32 + 2);
+ let span = span.with_lo(lo).with_hi(hi);
+ sess.emit_err(NulInCStr { span });
+ }
}
}
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 7fdbd48d5..3988416d0 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -135,13 +135,13 @@ fn current_dll_path() -> Result<PathBuf, String> {
use windows::{
core::PCWSTR,
- Win32::Foundation::HINSTANCE,
+ Win32::Foundation::HMODULE,
Win32::System::LibraryLoader::{
GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
},
};
- let mut module = HINSTANCE::default();
+ let mut module = HMODULE::default();
unsafe {
GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 968728905..590a68c66 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -19,7 +19,7 @@ pub mod errors;
extern crate tracing;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
pub mod cgu_reuse_tracker;
pub mod utils;
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 631dd0a21..2c4c4a7a6 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -329,21 +329,21 @@ fn build_options<O: Default>(
match value {
None => early_error(
error_format,
- &format!(
+ format!(
"{0} option `{1}` requires {2} ({3} {1}=<value>)",
outputname, key, type_desc, prefix
),
),
Some(value) => early_error(
error_format,
- &format!(
+ format!(
"incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected"
),
),
}
}
}
- None => early_error(error_format, &format!("unknown {outputname} option: `{key}`")),
+ None => early_error(error_format, format!("unknown {outputname} option: `{key}`")),
}
}
return op;
@@ -917,7 +917,7 @@ mod parse {
}
}
- let mut options = slot.get_or_insert_default();
+ let options = slot.get_or_insert_default();
let mut seen_always = false;
let mut seen_never = false;
let mut seen_ignore_loops = false;
@@ -1235,6 +1235,8 @@ options! {
line-tables-only, limited, or full; default: 0)"),
default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
"allow the linker to link its default libraries (default: no)"),
+ dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+ "import library generation tool (ignored except when targeting windows-gnu)"),
embed_bitcode: bool = (true, parse_bool, [TRACKED],
"emit bitcode in rlibs (default: yes)"),
extra_filename: String = (String::new(), parse_string, [UNTRACKED],
@@ -1391,8 +1393,6 @@ options! {
(default: no)"),
diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current output width for diagnostic truncation"),
- dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
- "import library generation tool (windows-gnu only)"),
dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
"emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
(default: no)"),
@@ -1452,9 +1452,9 @@ options! {
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
(default: no)"),
- flatten_format_args: bool = (false, parse_bool, [TRACKED],
+ flatten_format_args: bool = (true, parse_bool, [TRACKED],
"flatten nested format_args!() and literals into a simplified format_args!() call \
- (default: no)"),
+ (default: yes)"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable (default: no)"),
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
@@ -1555,9 +1555,12 @@ options! {
"emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
(default: no)"),
mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
- "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
+ "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the specified passes to be \
enabled, overriding all other checks. Passes that are not specified are enabled or \
disabled by other flags as usual."),
+ mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
+ "keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
+ (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
@@ -1659,6 +1662,12 @@ options! {
"immediately print bugs registered with `delay_span_bug` (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
+ sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
+ "enable canonical jump tables (default: yes)"),
+ sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "enable generalizing pointer types (default: no)"),
+ sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "enable normalizing integer types (default: no)"),
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
"enable origins tracking in MemorySanitizer"),
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
@@ -1704,11 +1713,17 @@ options! {
file which is ignored by the linker
`single`: sections which do not require relocation are written into object file but ignored
by the linker"),
+ split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "enable LTO unit splitting (default: no)"),
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
#[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
"control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
+ staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED],
+ "allow staticlibs to have rust dylib dependencies"),
+ staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED],
+ "prefer dynamic linking to static linking for staticlibs (default: no)"),
strict_init_checks: bool = (false, parse_bool, [TRACKED],
"control if mem::uninitialized and mem::zeroed panic on more UB"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 15e27952c..7b396dde9 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -214,8 +214,6 @@ pub struct ParseSess {
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
/// File paths accessed during the build.
pub file_depinfo: Lock<FxHashSet<Symbol>>,
- /// All the type ascriptions expressions that have had a suggestion for likely path typo.
- pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
/// Whether cfg(version) should treat the current release as incomplete
pub assume_incomplete_release: bool,
/// Spans passed to `proc_macro::quote_span`. Each span has a numerical
@@ -258,7 +256,6 @@ impl ParseSess {
reached_eof: AtomicBool::new(false),
env_depinfo: Default::default(),
file_depinfo: Default::default(),
- type_ascription_path_suggestions: Default::default(),
assume_incomplete_release: false,
proc_macro_quoted_spans: Default::default(),
attr_id_generator: AttrIdGenerator::new(),
@@ -292,7 +289,7 @@ impl ParseSess {
lint: &'static Lint,
span: impl Into<MultiSpan>,
node_id: NodeId,
- msg: &str,
+ msg: impl Into<DiagnosticMessage>,
) {
self.buffered_lints.with_lock(|buffered_lints| {
buffered_lints.push(BufferedEarlyLint {
@@ -310,7 +307,7 @@ impl ParseSess {
lint: &'static Lint,
span: impl Into<MultiSpan>,
node_id: NodeId,
- msg: &str,
+ msg: impl Into<DiagnosticMessage>,
diagnostic: BuiltinLintDiagnostics,
) {
self.buffered_lints.with_lock(|buffered_lints| {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 340bb158e..bbe52dbce 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -211,6 +211,9 @@ pub struct Session {
/// Set of enabled features for the current target, including unstable ones.
pub unstable_target_features: FxIndexSet<Symbol>,
+
+ /// The version of the rustc process, possibly including a commit hash and description.
+ pub cfg_version: &'static str,
}
pub struct PerfStats {
@@ -490,20 +493,6 @@ impl Session {
}
#[rustc_lint_diagnostics]
#[track_caller]
- pub fn span_err_or_warn<S: Into<MultiSpan>>(
- &self,
- is_warning: bool,
- sp: S,
- msg: impl Into<DiagnosticMessage>,
- ) {
- if is_warning {
- self.span_warn(sp, msg);
- } else {
- self.span_err(sp, msg);
- }
- }
- #[rustc_lint_diagnostics]
- #[track_caller]
pub fn span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -766,10 +755,30 @@ impl Session {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
}
+ pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(false)
+ }
+
+ pub fn is_sanitizer_cfi_canonical_jump_tables_enabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(true)
+ }
+
+ pub fn is_sanitizer_cfi_generalize_pointers_enabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_generalize_pointers == Some(true)
+ }
+
+ pub fn is_sanitizer_cfi_normalize_integers_enabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
+ }
+
pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
}
+ pub fn is_split_lto_unit_enabled(&self) -> bool {
+ self.opts.unstable_opts.split_lto_unit == Some(true)
+ }
+
/// Check whether this compile session and crate type use static crt.
pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
if !self.target.crt_static_respected {
@@ -811,7 +820,7 @@ impl Session {
}
pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
- format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64())
+ format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64())
}
pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
@@ -1190,6 +1199,7 @@ impl Session {
/// Returns the number of query threads that should be used for this
/// compilation
+ #[inline]
pub fn threads(&self) -> usize {
self.opts.unstable_opts.threads
}
@@ -1359,6 +1369,7 @@ pub fn build_session(
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
target_override: Option<Target>,
+ cfg_version: &'static str,
) -> Session {
// FIXME: This is not general enough to make the warning lint completely override
// normal diagnostic warnings, since the warning lint can also be denied and changed
@@ -1367,8 +1378,8 @@ pub fn build_session(
.lint_opts
.iter()
.rfind(|&(key, _)| *key == "warnings")
- .map_or(false, |&(_, level)| level == lint::Allow);
- let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
+ .is_some_and(|&(_, level)| level == lint::Allow);
+ let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow);
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
let sysroot = match &sopts.maybe_sysroot {
@@ -1379,10 +1390,10 @@ pub fn build_session(
let target_cfg = config::build_target_config(&sopts, target_override, &sysroot);
let host_triple = TargetTriple::from_triple(config::host_triple());
let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
- early_error(sopts.error_format, &format!("Error loading host specification: {e}"))
+ early_error(sopts.error_format, format!("Error loading host specification: {e}"))
});
for warning in target_warnings.warning_messages() {
- early_warn(sopts.error_format, &warning)
+ early_warn(sopts.error_format, warning)
}
let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
@@ -1424,7 +1435,7 @@ pub fn build_session(
match profiler {
Ok(profiler) => Some(Arc::new(profiler)),
Err(e) => {
- early_warn(sopts.error_format, &format!("failed to create profiler: {e}"));
+ early_warn(sopts.error_format, format!("failed to create profiler: {e}"));
None
}
}
@@ -1503,6 +1514,7 @@ pub fn build_session(
asm_arch,
target_features: Default::default(),
unstable_target_features: Default::default(),
+ cfg_version,
};
validate_commandline_args_with_session_available(&sess);
@@ -1581,17 +1593,16 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
sess.emit_err(errors::CannotEnableCrtStaticLinux);
}
- // LLVM CFI and VFE both require LTO.
- if sess.lto() != config::Lto::Fat {
- if sess.is_sanitizer_cfi_enabled() {
- sess.emit_err(errors::SanitizerCfiEnabled);
- }
- if sess.opts.unstable_opts.virtual_function_elimination {
- sess.emit_err(errors::UnstableVirtualFunctionElimination);
- }
+ // LLVM CFI requires LTO.
+ if sess.is_sanitizer_cfi_enabled()
+ && !(sess.lto() == config::Lto::Fat
+ || sess.lto() == config::Lto::Thin
+ || sess.opts.cg.linker_plugin_lto.enabled())
+ {
+ sess.emit_err(errors::SanitizerCfiRequiresLto);
}
- // LLVM CFI and KCFI are mutually exclusive
+ // LLVM CFI is incompatible with LLVM KCFI.
if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
sess.emit_err(errors::CannotMixAndMatchSanitizers {
first: "cfi".to_string(),
@@ -1599,6 +1610,43 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
});
}
+ // Canonical jump tables requires CFI.
+ if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
+ if !sess.is_sanitizer_cfi_enabled() {
+ sess.emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
+ }
+ }
+
+ // LLVM CFI pointer generalization requires CFI or KCFI.
+ if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
+ if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
+ sess.emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
+ }
+ }
+
+ // LLVM CFI integer normalization requires CFI or KCFI.
+ if sess.is_sanitizer_cfi_normalize_integers_enabled() {
+ if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
+ sess.emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
+ }
+ }
+
+ // LTO unit splitting requires LTO.
+ if sess.is_split_lto_unit_enabled()
+ && !(sess.lto() == config::Lto::Fat
+ || sess.lto() == config::Lto::Thin
+ || sess.opts.cg.linker_plugin_lto.enabled())
+ {
+ sess.emit_err(errors::SplitLtoUnitRequiresLto);
+ }
+
+ // VFE requires LTO.
+ if sess.lto() != config::Lto::Fat {
+ if sess.opts.unstable_opts.virtual_function_elimination {
+ sess.emit_err(errors::UnstableVirtualFunctionElimination);
+ }
+ }
+
if sess.opts.unstable_opts.stack_protector != StackProtector::None {
if !sess.target.options.supports_stack_protector {
sess.emit_warning(errors::StackProtectorNotSupportedForTarget {
@@ -1684,18 +1732,22 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
+#[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
+pub fn early_error_no_abort(
+ output: config::ErrorOutputType,
+ msg: impl Into<DiagnosticMessage>,
+) -> ErrorGuaranteed {
early_error_handler(output).struct_err(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
+pub fn early_error(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) -> ! {
early_error_handler(output).struct_fatal(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
+pub fn early_warn(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) {
early_error_handler(output).struct_warn(msg).emit()
}