1
Fork 0

Provide more context for rustc +nightly -Zunstable-options on stable

This commit is contained in:
许杰友 Jieyou Xu (Joe) 2023-06-23 05:56:09 +08:00
parent f42f19b6d3
commit cef812bd95
No known key found for this signature in database
GPG key ID: C5FD5D32014FDB47
19 changed files with 509 additions and 471 deletions

View file

@ -5,8 +5,8 @@ pub use crate::options::*;
use crate::search_paths::SearchPath;
use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use crate::{early_error, early_warn, Session};
use crate::{lint, HashStableContext};
use crate::{EarlyErrorHandler, Session};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -1389,6 +1389,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
}
pub(super) fn build_target_config(
handler: &EarlyErrorHandler,
opts: &Options,
target_override: Option<Target>,
sysroot: &Path,
@ -1398,27 +1399,21 @@ pub(super) fn build_target_config(
|t| Ok((t, TargetWarnings::empty())),
);
let (target, target_warnings) = target_result.unwrap_or_else(|e| {
early_error(
opts.error_format,
format!(
"Error loading target specification: {}. \
handler.early_error(format!(
"Error loading target specification: {}. \
Run `rustc --print target-list` for a list of built-in targets",
e
),
)
e
))
});
for warning in target_warnings.warning_messages() {
early_warn(opts.error_format, warning)
handler.early_warn(warning)
}
if !matches!(target.pointer_width, 16 | 32 | 64) {
early_error(
opts.error_format,
format!(
"target specification was invalid: unrecognized target-pointer-width {}",
target.pointer_width
),
)
handler.early_error(format!(
"target specification was invalid: unrecognized target-pointer-width {}",
target.pointer_width
))
}
target
@ -1654,8 +1649,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
}
pub fn get_cmd_lint_options(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
let mut lint_opts_with_position = vec![];
let mut describe_lints = false;
@ -1679,14 +1674,14 @@ 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(|| handler.early_error(format!("unknown lint level: `{cap}`")))
});
(lint_opts, describe_lints, lint_cap)
}
/// Parses the `--color` flag.
pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> ColorConfig {
match matches.opt_str("color").as_deref() {
Some("auto") => ColorConfig::Auto,
Some("always") => ColorConfig::Always,
@ -1694,13 +1689,10 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
None => ColorConfig::Auto,
Some(arg) => early_error(
ErrorOutputType::default(),
format!(
"argument for `--color` must be auto, \
Some(arg) => handler.early_error(format!(
"argument for `--color` must be auto, \
always or never (instead was `{arg}`)"
),
),
)),
}
}
@ -1743,7 +1735,7 @@ impl JsonUnusedExterns {
///
/// The first value returned is how to render JSON diagnostics, and the second
/// is whether or not artifact notifications are enabled.
pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> JsonConfig {
let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
HumanReadableErrorType::Default;
let mut json_color = ColorConfig::Never;
@ -1755,10 +1747,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
// won't actually be emitting any colors and anything colorized is
// embedded in a diagnostic message anyway.
if matches.opt_str("color").is_some() {
early_error(
ErrorOutputType::default(),
"cannot specify the `--color` option with `--json`",
);
handler.early_error("cannot specify the `--color` option with `--json`");
}
for sub_option in option.split(',') {
@ -1769,10 +1758,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
"unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
"unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
"future-incompat" => json_future_incompat = true,
s => early_error(
ErrorOutputType::default(),
format!("unknown `--json` option `{s}`"),
),
s => handler.early_error(format!("unknown `--json` option `{s}`")),
}
}
}
@ -1787,6 +1773,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
/// Parses the `--error-format` flag.
pub fn parse_error_format(
handler: &mut EarlyErrorHandler,
matches: &getopts::Matches,
color: ColorConfig,
json_rendered: HumanReadableErrorType,
@ -1807,13 +1794,15 @@ pub fn parse_error_format(
Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
Some(arg) => early_error(
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
format!(
Some(arg) => {
handler.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
HumanReadableErrorType::Default(color),
));
handler.early_error(format!(
"argument for `--error-format` must be `human`, `json` or \
`short` (instead was `{arg}`)"
),
),
))
}
}
} else {
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
@ -1826,10 +1815,7 @@ pub fn parse_error_format(
// `--error-format=json`. This means that `--json` is specified we
// should actually be emitting JSON blobs.
_ if !matches.opt_strs("json").is_empty() => {
early_error(
ErrorOutputType::default(),
"using `--json` requires also using `--error-format=json`",
);
handler.early_error("using `--json` requires also using `--error-format=json`");
}
_ => {}
@ -1838,16 +1824,13 @@ pub fn parse_error_format(
error_format
}
pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Edition {
let edition = match matches.opt_str("edition") {
Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
early_error(
ErrorOutputType::default(),
format!(
"argument for `--edition` must be one of: \
handler.early_error(format!(
"argument for `--edition` must be one of: \
{EDITION_NAME_LIST}. (instead was `{arg}`)"
),
)
))
}),
None => DEFAULT_EDITION,
};
@ -1862,39 +1845,42 @@ 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)
handler.early_error(msg)
}
edition
}
fn check_error_format_stability(
handler: &mut EarlyErrorHandler,
unstable_opts: &UnstableOptions,
error_format: ErrorOutputType,
json_rendered: HumanReadableErrorType,
) {
if !unstable_opts.unstable_options {
if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
early_error(
ErrorOutputType::Json { pretty: false, json_rendered },
"`--error-format=pretty-json` is unstable",
);
handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
pretty: false,
json_rendered,
});
handler.early_error("`--error-format=pretty-json` is unstable");
}
if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
error_format
{
early_error(
ErrorOutputType::Json { pretty: false, json_rendered },
"`--error-format=human-annotate-rs` is unstable",
);
handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
pretty: false,
json_rendered,
});
handler.early_error("`--error-format=human-annotate-rs` is unstable");
}
}
}
fn parse_output_types(
handler: &EarlyErrorHandler,
unstable_opts: &UnstableOptions,
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> OutputTypes {
let mut output_types = BTreeMap::new();
if !unstable_opts.parse_only {
@ -1908,13 +1894,10 @@ fn parse_output_types(
}
};
let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
early_error(
error_format,
format!(
"unknown emission type: `{shorthand}` - expected one of: {display}",
display = OutputType::shorthands_display(),
),
)
handler.early_error(format!(
"unknown emission type: `{shorthand}` - expected one of: {display}",
display = OutputType::shorthands_display(),
))
});
output_types.insert(output_type, path);
}
@ -1927,9 +1910,9 @@ fn parse_output_types(
}
fn should_override_cgus_and_disable_thinlto(
handler: &EarlyErrorHandler,
output_types: &OutputTypes,
matches: &getopts::Matches,
error_format: ErrorOutputType,
mut codegen_units: Option<usize>,
) -> (bool, Option<usize>) {
let mut disable_local_thinlto = false;
@ -1947,15 +1930,12 @@ fn should_override_cgus_and_disable_thinlto(
Some(n) if n > 1 => {
if matches.opt_present("o") {
for ot in &incompatible {
early_warn(
error_format,
format!(
"`--emit={ot}` with `-o` incompatible with \
handler.early_warn(format!(
"`--emit={ot}` with `-o` incompatible with \
`-C codegen-units=N` for N > 1",
),
);
));
}
early_warn(error_format, "resetting to default -C codegen-units=1");
handler.early_warn("resetting to default -C codegen-units=1");
codegen_units = Some(1);
disable_local_thinlto = true;
}
@ -1968,27 +1948,27 @@ fn should_override_cgus_and_disable_thinlto(
}
if codegen_units == Some(0) {
early_error(error_format, "value for codegen units must be a positive non-zero integer");
handler.early_error("value for codegen units must be a positive non-zero integer");
}
(disable_local_thinlto, codegen_units)
}
fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
fn check_thread_count(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) {
if unstable_opts.threads == 0 {
early_error(error_format, "value for threads must be a positive non-zero integer");
handler.early_error("value for threads must be a positive non-zero integer");
}
if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
early_error(error_format, "optimization fuel is incompatible with multiple threads");
handler.early_error("optimization fuel is incompatible with multiple threads");
}
}
fn collect_print_requests(
handler: &EarlyErrorHandler,
cg: &mut CodegenOptions,
unstable_opts: &mut UnstableOptions,
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> Vec<PrintRequest> {
let mut prints = Vec::<PrintRequest>::new();
if cg.target_cpu.as_ref().is_some_and(|s| s == "help") {
@ -2028,8 +2008,7 @@ fn collect_print_requests(
if unstable_opts.unstable_options {
PrintRequest::TargetSpec
} else {
early_error(
error_format,
handler.early_error(
"the `-Z unstable-options` flag must also be passed to \
enable the target-spec-json print option",
);
@ -2039,8 +2018,7 @@ fn collect_print_requests(
if unstable_opts.unstable_options {
PrintRequest::AllTargetSpecs
} else {
early_error(
error_format,
handler.early_error(
"the `-Z unstable-options` flag must also be passed to \
enable the all-target-specs-json print option",
);
@ -2051,10 +2029,9 @@ fn collect_print_requests(
let prints =
PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
let prints = prints.join(", ");
early_error(
error_format,
format!("unknown print request `{req}`. Valid print requests are: {prints}"),
);
handler.early_error(format!(
"unknown print request `{req}`. Valid print requests are: {prints}"
));
}
}
}));
@ -2063,14 +2040,14 @@ fn collect_print_requests(
}
pub fn parse_target_triple(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> TargetTriple {
match matches.opt_str("target") {
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"))
handler.early_error(format!("target file {path:?} does not exist"))
})
}
Some(target) => TargetTriple::TargetTriple(target),
@ -2079,9 +2056,9 @@ pub fn parse_target_triple(
}
fn parse_opt_level(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
cg: &CodegenOptions,
error_format: ErrorOutputType,
) -> OptLevel {
// The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
// to use them interchangeably. However, because they're technically different flags,
@ -2109,13 +2086,10 @@ fn parse_opt_level(
"s" => OptLevel::Size,
"z" => OptLevel::SizeMin,
arg => {
early_error(
error_format,
format!(
"optimization level needs to be \
handler.early_error(format!(
"optimization level needs to be \
between 0-3, s or z (instead was `{arg}`)"
),
);
));
}
}
}
@ -2135,23 +2109,23 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
}
pub(crate) fn parse_assert_incr_state(
handler: &EarlyErrorHandler,
opt_assertion: &Option<String>,
error_format: ErrorOutputType,
) -> Option<IncrementalStateAssertion> {
match opt_assertion {
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}"))
handler.early_error(format!("unexpected incremental state assertion value: {s}"))
}
None => None,
}
}
fn parse_native_lib_kind(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
kind: &str,
error_format: ErrorOutputType,
) -> (NativeLibKind, Option<bool>) {
let (kind, modifiers) = match kind.split_once(':') {
None => (kind, None),
@ -2169,35 +2143,31 @@ 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}"))
handler.early_error(format!("library kind `link-arg` is unstable{why}"))
}
NativeLibKind::LinkArg
}
_ => early_error(
error_format,
format!(
"unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
),
),
_ => handler.early_error(format!(
"unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
)),
};
match modifiers {
None => (kind, None),
Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
Some(modifiers) => parse_native_lib_modifiers(handler, kind, modifiers, matches),
}
}
fn parse_native_lib_modifiers(
handler: &EarlyErrorHandler,
mut kind: NativeLibKind,
modifiers: &str,
error_format: ErrorOutputType,
matches: &getopts::Matches,
) -> (NativeLibKind, Option<bool>) {
let mut verbatim = None;
for modifier in modifiers.split(',') {
let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
None => early_error(
error_format,
None => handler.early_error(
"invalid linking modifier syntax, expected '+' or '-' prefix \
before one of: bundle, verbatim, whole-archive, as-needed",
),
@ -2210,21 +2180,20 @@ 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}"))
handler.early_error(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)
handler.early_error(msg)
} else {
*dst = Some(value);
}
};
match (modifier, &mut kind) {
("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
("bundle", _) => early_error(
error_format,
("bundle", _) => handler.early_error(
"linking modifier `bundle` is only compatible with `static` linking kind",
),
@ -2233,8 +2202,7 @@ fn parse_native_lib_modifiers(
("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
assign_modifier(whole_archive)
}
("whole-archive", _) => early_error(
error_format,
("whole-archive", _) => handler.early_error(
"linking modifier `whole-archive` is only compatible with `static` linking kind",
),
@ -2243,28 +2211,24 @@ fn parse_native_lib_modifiers(
report_unstable_modifier();
assign_modifier(as_needed)
}
("as-needed", _) => early_error(
error_format,
("as-needed", _) => handler.early_error(
"linking modifier `as-needed` is only compatible with \
`dylib` and `framework` linking kinds",
),
// Note: this error also excludes the case with empty modifier
// string, like `modifiers = ""`.
_ => early_error(
error_format,
format!(
"unknown linking modifier `{modifier}`, expected one \
_ => handler.early_error(format!(
"unknown linking modifier `{modifier}`, expected one \
of: bundle, verbatim, whole-archive, as-needed"
),
),
)),
}
}
(kind, verbatim)
}
fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<NativeLib> {
matches
.opt_strs("l")
.into_iter()
@ -2278,7 +2242,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
let (name, kind, verbatim) = match s.split_once('=') {
None => (s, NativeLibKind::Unspecified, None),
Some((kind, name)) => {
let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
let (kind, verbatim) = parse_native_lib_kind(handler, matches, kind);
(name.to_string(), kind, verbatim)
}
};
@ -2288,7 +2252,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
};
if name.is_empty() {
early_error(error_format, "library name must not be empty");
handler.early_error("library name must not be empty");
}
NativeLib { name, new_name, kind, verbatim }
})
@ -2296,9 +2260,9 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
}
pub fn parse_externs(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
unstable_opts: &UnstableOptions,
error_format: ErrorOutputType,
) -> Externs {
let is_unstable_enabled = unstable_opts.unstable_options;
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
@ -2362,8 +2326,7 @@ pub fn parse_externs(
let mut force = false;
if let Some(opts) = options {
if !is_unstable_enabled {
early_error(
error_format,
handler.early_error(
"the `-Z unstable-options` flag must also be passed to \
enable `--extern` options",
);
@ -2375,15 +2338,14 @@ pub fn parse_externs(
if let ExternLocation::ExactPaths(_) = &entry.location {
add_prelude = false;
} else {
early_error(
error_format,
handler.early_error(
"the `noprelude` --extern option requires a file path",
);
}
}
"nounused" => nounused_dep = true,
"force" => force = true,
_ => early_error(error_format, format!("unknown --extern option `{opt}`")),
_ => handler.early_error(format!("unknown --extern option `{opt}`")),
}
}
}
@ -2402,18 +2364,15 @@ pub fn parse_externs(
}
fn parse_remap_path_prefix(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
unstable_opts: &UnstableOptions,
error_format: ErrorOutputType,
) -> Vec<(PathBuf, PathBuf)> {
let mut mapping: Vec<(PathBuf, PathBuf)> = matches
.opt_strs("remap-path-prefix")
.into_iter()
.map(|remap| match remap.rsplit_once('=') {
None => early_error(
error_format,
"--remap-path-prefix must contain '=' between FROM and TO",
),
None => handler.early_error("--remap-path-prefix must contain '=' between FROM and TO"),
Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
})
.collect();
@ -2429,86 +2388,75 @@ fn parse_remap_path_prefix(
// JUSTIFICATION: before wrapper fn is available
#[allow(rustc::bad_opt_access)]
pub fn build_session_options(matches: &getopts::Matches) -> Options {
let color = parse_color(matches);
pub fn build_session_options(
handler: &mut EarlyErrorHandler,
matches: &getopts::Matches,
) -> Options {
let color = parse_color(handler, matches);
let edition = parse_crate_edition(matches);
let edition = parse_crate_edition(handler, matches);
let JsonConfig {
json_rendered,
json_artifact_notifications,
json_unused_externs,
json_future_incompat,
} = parse_json(matches);
} = parse_json(handler, matches);
let error_format = parse_error_format(matches, color, json_rendered);
let error_format = parse_error_format(handler, matches, color, json_rendered);
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
early_error(error_format, "`--diagnostic-width` must be an positive integer");
handler.early_error("`--diagnostic-width` must be an positive integer");
});
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| handler.early_error(e));
let mut unstable_opts = UnstableOptions::build(matches, error_format);
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
let mut unstable_opts = UnstableOptions::build(handler, matches);
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
check_error_format_stability(&unstable_opts, error_format, json_rendered);
check_error_format_stability(handler, &unstable_opts, error_format, json_rendered);
if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
early_error(
error_format,
handler.early_error(
"the `-Z unstable-options` flag must also be passed to enable \
the flag `--json=unused-externs`",
);
}
let output_types = parse_output_types(&unstable_opts, matches, error_format);
let output_types = parse_output_types(handler, &unstable_opts, matches);
let mut cg = CodegenOptions::build(matches, error_format);
let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
&output_types,
matches,
error_format,
cg.codegen_units,
);
let mut cg = CodegenOptions::build(handler, matches);
let (disable_local_thinlto, mut codegen_units) =
should_override_cgus_and_disable_thinlto(handler, &output_types, matches, cg.codegen_units);
check_thread_count(&unstable_opts, error_format);
check_thread_count(handler, &unstable_opts);
let incremental = cg.incremental.as_ref().map(PathBuf::from);
let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
let assert_incr_state = parse_assert_incr_state(handler, &unstable_opts.assert_incr_state);
if unstable_opts.profile && incremental.is_some() {
early_error(
error_format,
"can't instrument with gcov profiling when compiling incrementally",
);
handler.early_error("can't instrument with gcov profiling when compiling incrementally");
}
if unstable_opts.profile {
match codegen_units {
Some(1) => {}
None => codegen_units = Some(1),
Some(_) => early_error(
error_format,
"can't instrument with gcov profiling with multiple codegen units",
),
Some(_) => handler
.early_error("can't instrument with gcov profiling with multiple codegen units"),
}
}
if cg.profile_generate.enabled() && cg.profile_use.is_some() {
early_error(
error_format,
"options `-C profile-generate` and `-C profile-use` are exclusive",
);
handler.early_error("options `-C profile-generate` and `-C profile-use` are exclusive");
}
if unstable_opts.profile_sample_use.is_some()
&& (cg.profile_generate.enabled() || cg.profile_use.is_some())
{
early_error(
error_format,
handler.early_error(
"option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
);
}
@ -2517,23 +2465,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
// precedence.
match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
(Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
early_error(
error_format,
handler.early_error(
"incompatible values passed for `-C symbol-mangling-version` \
and `-Z symbol-mangling-version`",
);
}
(Some(SymbolManglingVersion::V0), _) => {}
(Some(_), _) if !unstable_opts.unstable_options => {
early_error(
error_format,
"`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
);
handler
.early_error("`-C symbol-mangling-version=legacy` requires `-Z unstable-options`");
}
(None, None) => {}
(None, smv) => {
early_warn(
error_format,
handler.early_warn(
"`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
);
cg.symbol_mangling_version = smv;
@ -2545,25 +2489,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
// precedence.
match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
(Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
early_error(
error_format,
handler.early_error(
"incompatible values passed for `-C instrument-coverage` \
and `-Z instrument-coverage`",
);
}
(Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
(Some(_), _) if !unstable_opts.unstable_options => {
early_error(
error_format,
"`-C instrument-coverage=except-*` requires `-Z unstable-options`",
);
handler.early_error("`-C instrument-coverage=except-*` requires `-Z unstable-options`");
}
(None, None) => {}
(None, ic) => {
early_warn(
error_format,
"`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
);
handler
.early_warn("`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`");
cg.instrument_coverage = ic;
}
_ => {}
@ -2571,8 +2509,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
early_error(
error_format,
handler.early_error(
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \
or `-C profile-generate`",
);
@ -2585,8 +2522,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
match cg.symbol_mangling_version {
None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
Some(SymbolManglingVersion::Legacy) => {
early_warn(
error_format,
handler.early_warn(
"-C instrument-coverage requires symbol mangling version `v0`, \
but `-C symbol-mangling-version=legacy` was specified",
);
@ -2602,10 +2538,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
if !cg.embed_bitcode {
match cg.lto {
LtoCli::No | LtoCli::Unspecified => {}
LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
error_format,
"options `-C embed-bitcode=no` and `-C lto` are incompatible",
),
LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
handler.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible")
}
}
}
@ -2618,17 +2553,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
flag must also be passed to explicitly use it",
flavor.desc()
);
early_error(error_format, msg);
handler.early_error(msg);
}
}
let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches);
let cg = cg;
let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
let target_triple = parse_target_triple(matches, error_format);
let opt_level = parse_opt_level(matches, &cg, error_format);
let target_triple = parse_target_triple(handler, matches);
let opt_level = parse_opt_level(handler, matches, &cg);
// The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
// to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
// for more details.
@ -2637,28 +2572,28 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let mut search_paths = vec![];
for s in &matches.opt_strs("L") {
search_paths.push(SearchPath::from_cli_opt(s, error_format));
search_paths.push(SearchPath::from_cli_opt(handler, s));
}
let libs = parse_libs(matches, error_format);
let libs = parse_libs(handler, matches);
let test = matches.opt_present("test");
if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
handler.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
}
let externs = parse_externs(matches, &unstable_opts, error_format);
let externs = parse_externs(handler, matches, &unstable_opts);
let crate_name = matches.opt_str("crate-name");
let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
let remap_path_prefix = parse_remap_path_prefix(handler, matches, &unstable_opts);
let pretty = parse_pretty(&unstable_opts, error_format);
let pretty = parse_pretty(handler, &unstable_opts);
// query-dep-graph is required if dump-dep-graph is given #106736
if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`");
handler.early_error("can't dump dependency graph without `-Z query-dep-graph`");
}
// Try to find a directory containing the Rust `src`, for more details see
@ -2690,7 +2625,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}"));
handler.early_error(format!("Current directory is invalid: {e}"));
});
let remap = FilePathMapping::new(remap_path_prefix.clone());
@ -2741,7 +2676,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
}
}
fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> Option<PpMode> {
use PpMode::*;
let first = match unstable_opts.unpretty.as_deref()? {
@ -2760,16 +2695,13 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
"thir-flat" => ThirFlat,
"mir" => Mir,
"mir-cfg" => MirCFG,
name => early_error(
efmt,
format!(
"argument to `unpretty` must be one of `normal`, `identified`, \
name => handler.early_error(format!(
"argument to `unpretty` must be one of `normal`, `identified`, \
`expanded`, `expanded,identified`, `expanded,hygiene`, \
`ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
`hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \
`mir-cfg`; got {name}"
),
),
)),
};
debug!("got unpretty option: {first:?}");
Some(first)
@ -2809,8 +2741,8 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
}
pub mod nightly_options {
use super::{ErrorOutputType, OptionStability, RustcOptGroup};
use crate::early_error;
use super::{OptionStability, RustcOptGroup};
use crate::EarlyErrorHandler;
use rustc_feature::UnstableFeatures;
pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
@ -2826,7 +2758,11 @@ pub mod nightly_options {
UnstableFeatures::from_environment(krate).is_nightly_build()
}
pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
pub fn check_nightly_options(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
flags: &[RustcOptGroup],
) {
let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
let really_allows_unstable_options = match_is_nightly_build(matches);
@ -2838,14 +2774,11 @@ pub mod nightly_options {
continue;
}
if opt.name != "Z" && !has_z_unstable_option {
early_error(
ErrorOutputType::default(),
format!(
"the `-Z unstable-options` flag must also be passed to enable \
handler.early_error(format!(
"the `-Z unstable-options` flag must also be passed to enable \
the flag `{}`",
opt.name
),
);
opt.name
));
}
if really_allows_unstable_options {
continue;
@ -2856,7 +2789,12 @@ pub mod nightly_options {
"the option `{}` is only accepted on the nightly compiler",
opt.name
);
early_error(ErrorOutputType::default(), msg);
let _ = handler.early_error_no_abort(msg);
handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
handler.early_help(
"consider switching to a nightly toolchain: `rustup default nightly`",
);
handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
}
OptionStability::Stable => {}
}

View file

@ -1,9 +1,8 @@
use crate::config::*;
use crate::early_error;
use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
use crate::{lint, EarlyErrorHandler};
use rustc_data_structures::profiling::TimePassesFormat;
use rustc_errors::{LanguageIdentifier, TerminalUrl};
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
@ -245,10 +244,10 @@ macro_rules! options {
impl $struct_name {
pub fn build(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> $struct_name {
build_options(matches, $stat, $prefix, $outputname, error_format)
build_options(handler, matches, $stat, $prefix, $outputname)
}
fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
@ -309,11 +308,11 @@ type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)];
fn build_options<O: Default>(
handler: &EarlyErrorHandler,
matches: &getopts::Matches,
descrs: OptionDescrs<O>,
prefix: &str,
outputname: &str,
error_format: ErrorOutputType,
) -> O {
let mut op = O::default();
for option in matches.opt_strs(prefix) {
@ -327,15 +326,13 @@ fn build_options<O: Default>(
Some((_, setter, type_desc, _)) => {
if !setter(&mut op, value) {
match value {
None => early_error(
error_format,
None => handler.early_error(
format!(
"{0} option `{1}` requires {2} ({3} {1}=<value>)",
outputname, key, type_desc, prefix
),
),
Some(value) => early_error(
error_format,
Some(value) => handler.early_error(
format!(
"incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected"
),
@ -343,7 +340,7 @@ fn build_options<O: Default>(
}
}
}
None => early_error(error_format, format!("unknown {outputname} option: `{key}`")),
None => handler.early_error(format!("unknown {outputname} option: `{key}`")),
}
}
return op;

View file

@ -1,5 +1,5 @@
use crate::filesearch::make_target_lib_path;
use crate::{config, early_error};
use crate::EarlyErrorHandler;
use std::path::{Path, PathBuf};
#[derive(Clone, Debug)]
@ -46,7 +46,7 @@ impl PathKind {
}
impl SearchPath {
pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self {
pub fn from_cli_opt(handler: &EarlyErrorHandler, path: &str) -> Self {
let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
(PathKind::Native, stripped)
} else if let Some(stripped) = path.strip_prefix("crate=") {
@ -61,7 +61,7 @@ impl SearchPath {
(PathKind::All, path)
};
if path.is_empty() {
early_error(output, "empty search path given via `-L`");
handler.early_error("empty search path given via `-L`");
}
let dir = PathBuf::from(path);

View file

@ -1,10 +1,10 @@
use crate::cgu_reuse_tracker::CguReuseTracker;
use crate::code_stats::CodeStats;
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
use crate::config::Input;
use crate::config::{
self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
};
use crate::config::{ErrorOutputType, Input};
use crate::errors;
use crate::parse::{add_feature_diagnostics, ParseSess};
use crate::search_paths::{PathKind, SearchPath};
@ -25,7 +25,7 @@ use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry;
use rustc_errors::{
error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
TerminalUrl,
};
use rustc_macros::HashStable_Generic;
@ -1382,6 +1382,7 @@ fn default_emitter(
// JUSTIFICATION: literally session construction
#[allow(rustc::bad_opt_access)]
pub fn build_session(
handler: &EarlyErrorHandler,
sopts: config::Options,
io: CompilerIO,
bundle: Option<Lrc<rustc_errors::FluentBundle>>,
@ -1408,13 +1409,12 @@ pub fn build_session(
None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
};
let target_cfg = config::build_target_config(&sopts, target_override, &sysroot);
let target_cfg = config::build_target_config(handler, &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}"))
});
let (host, target_warnings) = Target::search(&host_triple, &sysroot)
.unwrap_or_else(|e| handler.early_error(format!("Error loading host specification: {e}")));
for warning in target_warnings.warning_messages() {
early_warn(sopts.error_format, warning)
handler.early_warn(warning)
}
let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
@ -1456,7 +1456,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}"));
handler.early_warn(format!("failed to create profiler: {e}"));
None
}
}
@ -1723,7 +1723,64 @@ pub enum IncrCompSession {
InvalidBecauseOfErrors { session_directory: PathBuf },
}
fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler {
/// A wrapper around an [`Handler`] that is used for early error emissions.
pub struct EarlyErrorHandler {
handler: Handler,
}
impl EarlyErrorHandler {
pub fn new(output: ErrorOutputType) -> Self {
let emitter = mk_emitter(output);
Self { handler: rustc_errors::Handler::with_emitter(true, None, emitter) }
}
pub fn abort_if_errors(&self) {
self.handler.abort_if_errors()
}
/// Swap out the underlying handler once we acquire the user's preference on error emission
/// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
/// previous handler will be emitted.
pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) {
self.handler.abort_if_errors();
let emitter = mk_emitter(output);
self.handler = Handler::with_emitter(true, None, emitter);
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn early_note(&self, msg: impl Into<DiagnosticMessage>) {
self.handler.struct_note_without_error(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn early_help(&self, msg: impl Into<DiagnosticMessage>) {
self.handler.struct_help(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
#[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(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.handler.struct_err(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn early_error(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.handler.struct_fatal(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) {
self.handler.struct_warn(msg).emit()
}
}
fn mk_emitter(output: ErrorOutputType) -> Box<dyn Emitter + sync::Send + 'static> {
// FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will
// need to reference every crate that might emit an early error for translation to work.
let fallback_bundle =
@ -1755,27 +1812,5 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
TerminalUrl::No,
)),
};
rustc_errors::Handler::with_emitter(true, None, emitter)
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
#[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: 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: impl Into<DiagnosticMessage>) {
early_error_handler(output).struct_warn(msg).emit()
emitter
}