Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor pre-getopts command line argument handling #111658

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 52 additions & 18 deletions compiler/rustc_driver_impl/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,85 @@
use std::error;
use std::fmt;
use std::fs;
use std::io;
use rustc_span::ErrorGuaranteed;
use std::{env, error, fmt, fs, io};

use rustc_session::EarlyErrorHandler;

fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
fn arg_expand(arg: &str) -> Result<Vec<String>, Error> {
if let Some(path) = arg.strip_prefix('@') {
let file = match fs::read_to_string(path) {
Ok(file) => file,
Err(ref err) if err.kind() == io::ErrorKind::InvalidData => {
return Err(Error::Utf8Error(Some(path.to_string())));
return Err(Error::Utf8Error(path.to_string()));
}
Err(err) => return Err(Error::IOError(path.to_string(), err)),
};
Ok(file.lines().map(ToString::to_string).collect())
} else {
Ok(vec![arg])
Ok(vec![arg.to_string()])
}
}

/// Replaces any `@file` arguments with the contents of `file`, with each line of `file` as a
/// separate argument.
///
/// **Note:** This function doesn't interpret argument 0 in any special way.
/// If this function is intended to be used with command line arguments,
/// `argv[0]` must be removed prior to calling it manually.
pub fn arg_expand_all(handler: &EarlyErrorHandler, at_args: &[String]) -> Vec<String> {
let mut args = Vec::new();
pub fn arg_expand_all(
handler: &EarlyErrorHandler,
at_args: &[String],
) -> Result<Vec<String>, ErrorGuaranteed> {
let mut res = Ok(Vec::new());
for arg in at_args {
match arg_expand(arg.clone()) {
Ok(arg) => args.extend(arg),
Err(err) => handler.early_error(format!("Failed to load argument file: {err}")),
match arg_expand(arg) {
Ok(arg) => {
if let Ok(args) = &mut res {
args.extend(arg)
}
}
Err(err) => {
res =
Err(handler
.early_error_no_abort(format!("failed to load argument file: {err}")))
}
}
}
res
}

/// Gets the raw unprocessed command-line arguments as Unicode strings, without doing any further
/// processing (e.g., without `@file` expansion).
///
/// This function is identical to [`env::args()`] except that it emits an error when it encounters
/// non-Unicode arguments instead of panicking.
pub fn raw_args(handler: &EarlyErrorHandler) -> Result<Vec<String>, ErrorGuaranteed> {
let mut res = Ok(Vec::new());
for (i, arg) in env::args_os().enumerate() {
match arg.into_string() {
Ok(arg) => {
if let Ok(args) = &mut res {
args.push(arg);
}
}
Err(arg) => {
res = Err(handler
.early_error_no_abort(format!("argument {i} is not valid Unicode: {arg:?}")))
}
}
}
args
res
}

#[derive(Debug)]
pub enum Error {
Utf8Error(Option<String>),
enum Error {
Utf8Error(String),
IOError(String, io::Error),
}

impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Utf8Error(None) => write!(fmt, "Utf8 error"),
Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"),
Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"),
Error::Utf8Error(path) => write!(fmt, "UTF-8 error in {path}"),
Error::IOError(path, err) => write!(fmt, "IO error: {path}: {err}"),
}
}
}
Expand Down
15 changes: 3 additions & 12 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ fn run_compiler(
// the compiler with @empty_file as argv[0] and no more arguments.
let at_args = at_args.get(1..).unwrap_or_default();

let args = args::arg_expand_all(&early_error_handler, at_args);
let args = args::arg_expand_all(&early_error_handler, at_args)?;

let Some(matches) = handle_options(&early_error_handler, &args) else { return Ok(()) };

Expand Down Expand Up @@ -1565,17 +1565,8 @@ pub fn main() -> ! {
signal_handler::install();
let mut callbacks = TimePassesCallbacks::default();
install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
let exit_code = catch_with_exit_code(|| {
let args = env::args_os()
.enumerate()
.map(|(i, arg)| {
arg.into_string().unwrap_or_else(|arg| {
handler.early_error(format!("argument {i} is not valid Unicode: {arg:?}"))
})
})
.collect::<Vec<_>>();
RunCompiler::new(&args, &mut callbacks).run()
});
let exit_code =
catch_with_exit_code(|| RunCompiler::new(&args::raw_args(&handler)?, &mut callbacks).run());

if let Some(format) = callbacks.time_passes {
let end_rss = get_resident_set_size();
Expand Down
27 changes: 5 additions & 22 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,15 @@ pub fn main() {
init_logging(&handler);
rustc_driver::init_env_logger(&handler, "RUSTDOC_LOG");

let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&handler) {
Some(args) => main_args(&mut handler, &args),
_ =>
{
#[allow(deprecated)]
Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
}
let exit_code = rustc_driver::catch_with_exit_code(|| {
let at_args = rustc_driver::args::raw_args(&handler)?;
main_args(&mut handler, &at_args)
});
process::exit(exit_code);
}

fn init_logging(handler: &EarlyErrorHandler) {
let color_logs = match std::env::var("RUSTDOC_LOG_COLOR").as_deref() {
let color_logs = match env::var("RUSTDOC_LOG_COLOR").as_deref() {
Ok("always") => true,
Ok("never") => false,
Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
Expand Down Expand Up @@ -217,19 +213,6 @@ fn init_logging(handler: &EarlyErrorHandler) {
tracing::subscriber::set_global_default(subscriber).unwrap();
}

fn get_args(handler: &EarlyErrorHandler) -> Option<Vec<String>> {
env::args_os()
.enumerate()
.map(|(i, arg)| {
arg.into_string()
.map_err(|arg| {
handler.early_warn(format!("Argument {i} is not valid Unicode: {arg:?}"));
})
.ok()
})
.collect()
}

fn opts() -> Vec<RustcOptGroup> {
let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable;
let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable;
Expand Down Expand Up @@ -715,7 +698,7 @@ fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult
// the compiler with @empty_file as argv[0] and no more arguments.
let at_args = at_args.get(1..).unwrap_or_default();

let args = rustc_driver::args::arg_expand_all(handler, at_args);
let args = rustc_driver::args::arg_expand_all(handler, at_args)?;

let mut options = getopts::Options::new();
for option in opts() {
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ pub fn main() {
});

exit(rustc_driver::catch_with_exit_code(move || {
let mut orig_args: Vec<String> = env::args().collect();
let mut orig_args: Vec<String> = rustc_driver::args::raw_args(&handler)?;
let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some();

let sys_root_env = std::env::var("SYSROOT").ok();
Expand Down
6 changes: 4 additions & 2 deletions src/tools/miri/src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ fn main() {
// (`install_ice_hook` might change `RUST_BACKTRACE`.)
let env_snapshot = env::vars_os().collect::<Vec<_>>();

let args = rustc_driver::args::raw_args(&handler).unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE));

// If the environment asks us to actually be rustc, then do that.
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
// Earliest rustc setup.
Expand All @@ -307,7 +309,7 @@ fn main() {

// We cannot use `rustc_driver::main` as we need to adjust the CLI arguments.
run_compiler(
env::args().collect(),
args,
target_crate,
&mut MiriBeRustCompilerCalls { target_crate },
)
Expand All @@ -328,7 +330,7 @@ fn main() {

// If user has explicitly enabled/disabled isolation
let mut isolation_enabled: Option<bool> = None;
for arg in env::args() {
for arg in args {
if rustc_args.is_empty() {
// Very first arg: binary name.
rustc_args.push(arg);
Expand Down
6 changes: 3 additions & 3 deletions src/tools/tidy/src/ui_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
const ENTRY_LIMIT: usize = 900;
// FIXME: The following limits should be reduced eventually.
const ISSUES_ENTRY_LIMIT: usize = 1891;
const ROOT_ENTRY_LIMIT: usize = 866;
const ROOT_ENTRY_LIMIT: usize = 860;

const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
"rs", // test source files
Expand All @@ -25,8 +25,8 @@ const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
"tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint
"tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs
"tests/ui/commandline-argfile-badutf8.args", // passing args via a file
"tests/ui/commandline-argfile.args", // passing args via a file
"tests/ui/argfile/commandline-argfile-badutf8.args", // passing args via a file
"tests/ui/argfile/commandline-argfile.args", // passing args via a file
"tests/ui/crate-loading/auxiliary/libfoo.rlib", // testing loading a manually created rlib
"tests/ui/include-macros/data.bin", // testing including data with the include macros
"tests/ui/include-macros/file.txt", // testing including data with the include macros
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Check to see if we can get parameters from an @argsfile file
//
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile-badutf8.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");
Expand Down
2 changes: 2 additions & 0 deletions tests/rustdoc-ui/argfile/commandline-argfile-badutf8.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: failed to load argument file: UTF-8 error in $DIR/commandline-argfile-badutf8.args

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile-missing.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");
Expand Down
2 changes: 2 additions & 0 deletions tests/rustdoc-ui/argfile/commandline-argfile-missing.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: failed to load argument file: IO error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)

14 changes: 14 additions & 0 deletions tests/rustdoc-ui/argfile/commandline-argfile-multiple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Check to see if we can get parameters from an @argsfile file
//
// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile-missing.args @{{src-base}}/argfile/commandline-argfile-badutf8.args @{{src-base}}/argfile/commandline-argfile-missing2.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");

#[cfg(not(unbroken))]
compile_error!("unbroken not set");

fn main() {
}
6 changes: 6 additions & 0 deletions tests/rustdoc-ui/argfile/commandline-argfile-multiple.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
error: failed to load argument file: IO error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)

error: failed to load argument file: UTF-8 error in $DIR/commandline-argfile-badutf8.args

error: failed to load argument file: IO error: $DIR/commandline-argfile-missing2.args: No such file or directory (os error $ERR)

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Check to see if we can get parameters from an @argsfile file
//
// check-pass
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");
Expand Down
2 changes: 0 additions & 2 deletions tests/rustdoc-ui/commandline-argfile-badutf8.stderr

This file was deleted.

2 changes: 0 additions & 2 deletions tests/rustdoc-ui/commandline-argfile-missing.stderr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Check to see if we can get parameters from an @argsfile file
//
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile-badutf8.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/argfile/commandline-argfile-badutf8.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: failed to load argument file: UTF-8 error in $DIR/commandline-argfile-badutf8.args

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile-missing.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/argfile/commandline-argfile-missing.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: failed to load argument file: IO error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)

14 changes: 14 additions & 0 deletions tests/ui/argfile/commandline-argfile-multiple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Check to see if we can get parameters from an @argsfile file
//
// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile-missing.args @{{src-base}}/argfile/commandline-argfile-badutf8.args @{{src-base}}/argfile/commandline-argfile-missing2.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");

#[cfg(not(unbroken))]
compile_error!("unbroken not set");

fn main() {
}
6 changes: 6 additions & 0 deletions tests/ui/argfile/commandline-argfile-multiple.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
error: failed to load argument file: IO error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)

error: failed to load argument file: UTF-8 error in $DIR/commandline-argfile-badutf8.args

error: failed to load argument file: IO error: $DIR/commandline-argfile-missing2.args: No such file or directory (os error $ERR)

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Check to see if we can get parameters from an @argsfile file
//
// build-pass
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args
// compile-flags: --cfg cmdline_set @{{src-base}}/argfile/commandline-argfile.args

#[cfg(not(cmdline_set))]
compile_error!("cmdline_set not set");
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/commandline-argfile-badutf8.stderr

This file was deleted.

2 changes: 0 additions & 2 deletions tests/ui/commandline-argfile-missing.stderr

This file was deleted.

Loading