From 859657f2c5dbe2cf55cf7a7665383a81e676bdf3 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 1 Aug 2019 11:06:52 -0700 Subject: [PATCH 1/3] Use named arguments for formatting usage message. It was getting a bit awkward. --- src/librustc_driver/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fdd0773b73ae2..cd030f3c9184e 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -777,13 +777,13 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - println!("{}\nAdditional help: + println!("{options}\nAdditional help: -C help Print codegen options -W help \ - Print 'lint' options and default settings{}{}\n", - options.usage(message), - nightly_help, - verbose_help); + Print 'lint' options and default settings{nightly}{verbose}\n", + options = options.usage(message), + nightly = nightly_help, + verbose = verbose_help); } fn print_wall_help() { From d2219c2e2e287d50c0f9761203d26d5fe3b0e639 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 30 Jul 2019 15:57:10 -0700 Subject: [PATCH 2/3] rustc: implement argsfiles for command line This makes `rustc` support `@path` arguments on the command line. The `path` is opened and the file is interpreted as new command line options which are logically inserted at that point in the command-line. The options in the file are one per line. The file is UTF-8 encoded, and may have either Unix or Windows line endings. It does not support recursive use of `@path`. This is useful for very large command lines, or when command-lines are being generated into files by other tooling. --- src/doc/rustc/src/command-line-arguments.md | 7 + src/librustc_driver/args/mod.rs | 84 ++++++++++ src/librustc_driver/args/tests.rs | 145 ++++++++++++++++++ src/librustc_driver/lib.rs | 21 ++- src/test/ui/commandline-argfile-badutf8.args | 2 + src/test/ui/commandline-argfile-badutf8.rs | 14 ++ .../ui/commandline-argfile-badutf8.stderr | 2 + src/test/ui/commandline-argfile-missing.rs | 16 ++ .../ui/commandline-argfile-missing.stderr | 2 + src/test/ui/commandline-argfile.args | 2 + src/test/ui/commandline-argfile.rs | 13 ++ 11 files changed, 304 insertions(+), 4 deletions(-) create mode 100644 src/librustc_driver/args/mod.rs create mode 100644 src/librustc_driver/args/tests.rs create mode 100644 src/test/ui/commandline-argfile-badutf8.args create mode 100644 src/test/ui/commandline-argfile-badutf8.rs create mode 100644 src/test/ui/commandline-argfile-badutf8.stderr create mode 100644 src/test/ui/commandline-argfile-missing.rs create mode 100644 src/test/ui/commandline-argfile-missing.stderr create mode 100644 src/test/ui/commandline-argfile.args create mode 100644 src/test/ui/commandline-argfile.rs diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d774e465118b3..5eea9c8687900 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -304,3 +304,10 @@ to customize the output: Note that it is invalid to combine the `--json` argument with the `--color` argument, and it is required to combine `--json` with `--error-format=json`. + +## `@path`: load command-line flags from a path + +If you specify `@path` on the command-line, then it will open `path` and read +command line options from it. These options are one per line; a blank line indicates +an empty option. The file can use Unix or Windows style line endings, and must be +encoded as UTF-8. diff --git a/src/librustc_driver/args/mod.rs b/src/librustc_driver/args/mod.rs new file mode 100644 index 0000000000000..a59f9afd8beb5 --- /dev/null +++ b/src/librustc_driver/args/mod.rs @@ -0,0 +1,84 @@ +use std::env; +use std::error; +use std::fmt; +use std::fs; +use std::io; +use std::str; +use std::sync::atomic::{AtomicBool, Ordering}; + +#[cfg(test)] +mod tests; + +static USED_ARGSFILE_FEATURE: AtomicBool = AtomicBool::new(false); + +pub fn used_unstable_argsfile() -> bool { + USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) +} + +pub struct ArgsIter { + base: env::ArgsOs, + file: std::vec::IntoIter, +} + +impl ArgsIter { + pub fn new() -> Self { + ArgsIter { base: env::args_os(), file: vec![].into_iter() } + } +} + +impl Iterator for ArgsIter { + type Item = Result; + + fn next(&mut self) -> Option { + loop { + if let Some(line) = self.file.next() { + return Some(Ok(line)); + } + + let arg = + self.base.next().map(|arg| arg.into_string().map_err(|_| Error::Utf8Error(None))); + match arg { + Some(Err(err)) => return Some(Err(err)), + Some(Ok(ref arg)) if arg.starts_with("@") => { + let path = &arg[1..]; + let file = match fs::read_to_string(path) { + Ok(file) => { + USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); + file + } + Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { + return Some(Err(Error::Utf8Error(Some(path.to_string())))); + } + Err(err) => return Some(Err(Error::IOError(path.to_string(), err))), + }; + self.file = + file.lines().map(ToString::to_string).collect::>().into_iter(); + } + Some(Ok(arg)) => return Some(Ok(arg)), + None => return None, + } + } + } +} + +#[derive(Debug)] +pub enum Error { + Utf8Error(Option), + 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), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &'static str { + "argument error" + } +} diff --git a/src/librustc_driver/args/tests.rs b/src/librustc_driver/args/tests.rs new file mode 100644 index 0000000000000..080dd5cb746c3 --- /dev/null +++ b/src/librustc_driver/args/tests.rs @@ -0,0 +1,145 @@ +use super::*; + +use std::str; + +fn want_args(v: impl IntoIterator) -> Vec { + v.into_iter().map(String::from).collect() +} + +fn got_args(file: &[u8]) -> Result, Error> { + let ret = str::from_utf8(file) + .map_err(|_| Error::Utf8Error(None))? + .lines() + .map(ToString::to_string) + .collect::>(); + Ok(ret) +} + +#[test] +fn nothing() { + let file = b""; + + assert_eq!(got_args(file).unwrap(), want_args(vec![])); +} + +#[test] +fn empty() { + let file = b"\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec![""])); +} + +#[test] +fn simple() { + let file = b"foo"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn simple_eol() { + let file = b"foo\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn multi() { + let file = b"foo\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_eol() { + let file = b"foo\nbar\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_empty() { + let file = b"foo\n\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_eol() { + let file = b"foo\n\nbar\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_start() { + let file = b"\nfoo\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); +} + +#[test] +fn multi_empty_end() { + let file = b"foo\nbar\n\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); +} + +#[test] +fn simple_eol_crlf() { + let file = b"foo\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn multi_crlf() { + let file = b"foo\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_eol_crlf() { + let file = b"foo\r\nbar\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_empty_crlf() { + let file = b"foo\r\n\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_eol_crlf() { + let file = b"foo\r\n\r\nbar\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_start_crlf() { + let file = b"\r\nfoo\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); +} + +#[test] +fn multi_empty_end_crlf() { + let file = b"foo\r\nbar\r\n\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); +} + +#[test] +fn bad_utf8() { + let file = b"foo\x80foo"; + + match got_args(file).unwrap_err() { + Error::Utf8Error(_) => (), + bad => panic!("bad err: {:?}", bad), + } +} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index cd030f3c9184e..4843c1a951b31 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -66,6 +66,7 @@ use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; pub mod pretty; +mod args; /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -777,11 +778,17 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - println!("{options}\nAdditional help: + let at_path = if verbose && nightly_options::is_nightly_build() { + " @path Read newline separated options from `path`\n" + } else { + "" + }; + println!("{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ Print 'lint' options and default settings{nightly}{verbose}\n", options = options.usage(message), + at_path = at_path, nightly = nightly_help, verbose = verbose_help); } @@ -1008,6 +1015,12 @@ pub fn handle_options(args: &[String]) -> Option { // (unstable option being used on stable) nightly_options::check_nightly_options(&matches, &config::rustc_optgroups()); + // Late check to see if @file was used without unstable options enabled + if crate::args::used_unstable_argsfile() && !nightly_options::is_unstable_enabled(&matches) { + early_error(ErrorOutputType::default(), + "@path is unstable - use -Z unstable-options to enable its use"); + } + if matches.opt_present("h") || matches.opt_present("help") { // Only show unstable options in --help if we accept unstable options. usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); @@ -1186,10 +1199,10 @@ pub fn main() { init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); let result = report_ices_to_stderr_if_any(|| { - let args = env::args_os().enumerate() - .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { + let args = args::ArgsIter::new().enumerate() + .map(|(i, arg)| arg.unwrap_or_else(|err| { early_error(ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg)) + &format!("Argument {} is not valid: {}", i, err)) })) .collect::>(); run_compiler(&args, &mut callbacks, None, None) diff --git a/src/test/ui/commandline-argfile-badutf8.args b/src/test/ui/commandline-argfile-badutf8.args new file mode 100644 index 0000000000000..c070b0c2400d8 --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.args @@ -0,0 +1,2 @@ +--cfg +unbroken€ \ No newline at end of file diff --git a/src/test/ui/commandline-argfile-badutf8.rs b/src/test/ui/commandline-argfile-badutf8.rs new file mode 100644 index 0000000000000..c017e7b5ea60b --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.rs @@ -0,0 +1,14 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// normalize-stderr-test: "Argument \d+" -> "Argument $$N" +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr new file mode 100644 index 0000000000000..cd8a03e34eac9 --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -0,0 +1,2 @@ +error: Argument $N is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args + diff --git a/src/test/ui/commandline-argfile-missing.rs b/src/test/ui/commandline-argfile-missing.rs new file mode 100644 index 0000000000000..34faf07633599 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.rs @@ -0,0 +1,16 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// normalize-stderr-test: "Argument \d+" -> "Argument $$N" +// 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 + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-missing.stderr b/src/test/ui/commandline-argfile-missing.stderr new file mode 100644 index 0000000000000..c0017782f2eb3 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.stderr @@ -0,0 +1,2 @@ +error: Argument $N is not valid: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR) + diff --git a/src/test/ui/commandline-argfile.args b/src/test/ui/commandline-argfile.args new file mode 100644 index 0000000000000..972938bf6c8dd --- /dev/null +++ b/src/test/ui/commandline-argfile.args @@ -0,0 +1,2 @@ +--cfg +unbroken \ No newline at end of file diff --git a/src/test/ui/commandline-argfile.rs b/src/test/ui/commandline-argfile.rs new file mode 100644 index 0000000000000..fc1ba0c8d677d --- /dev/null +++ b/src/test/ui/commandline-argfile.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-pass +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} From d9497749a87440d836495da6d40a5ce667a67ccb Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 19 Aug 2019 19:02:12 -0700 Subject: [PATCH 3/3] Move argfile expansion into run_compiler This will make @path work with miri and other non-standard entrypoints. Also since this simplifies librustc_driver::args, move it into a simple source file. Also remove the tests since they're doing nothing more than checking `str::lines` has the right behaviour. --- src/librustc_driver/args.rs | 53 +++++++ src/librustc_driver/args/mod.rs | 84 ---------- src/librustc_driver/args/tests.rs | 145 ------------------ src/librustc_driver/lib.rs | 20 ++- src/test/ui/commandline-argfile-badutf8.rs | 1 - .../ui/commandline-argfile-badutf8.stderr | 2 +- src/test/ui/commandline-argfile-missing.rs | 2 +- .../ui/commandline-argfile-missing.stderr | 2 +- 8 files changed, 70 insertions(+), 239 deletions(-) create mode 100644 src/librustc_driver/args.rs delete mode 100644 src/librustc_driver/args/mod.rs delete mode 100644 src/librustc_driver/args/tests.rs diff --git a/src/librustc_driver/args.rs b/src/librustc_driver/args.rs new file mode 100644 index 0000000000000..0906d358badd4 --- /dev/null +++ b/src/librustc_driver/args.rs @@ -0,0 +1,53 @@ +use std::error; +use std::fmt; +use std::fs; +use std::io; +use std::str; +use std::sync::atomic::{AtomicBool, Ordering}; + +static USED_ARGSFILE_FEATURE: AtomicBool = AtomicBool::new(false); + +pub fn used_unstable_argsfile() -> bool { + USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) +} + +pub fn arg_expand(arg: String) -> Result, Error> { + if arg.starts_with("@") { + let path = &arg[1..]; + let file = match fs::read_to_string(path) { + Ok(file) => { + USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); + file + } + Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { + return Err(Error::Utf8Error(Some(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]) + } +} + +#[derive(Debug)] +pub enum Error { + Utf8Error(Option), + 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), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &'static str { + "argument error" + } +} diff --git a/src/librustc_driver/args/mod.rs b/src/librustc_driver/args/mod.rs deleted file mode 100644 index a59f9afd8beb5..0000000000000 --- a/src/librustc_driver/args/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::env; -use std::error; -use std::fmt; -use std::fs; -use std::io; -use std::str; -use std::sync::atomic::{AtomicBool, Ordering}; - -#[cfg(test)] -mod tests; - -static USED_ARGSFILE_FEATURE: AtomicBool = AtomicBool::new(false); - -pub fn used_unstable_argsfile() -> bool { - USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) -} - -pub struct ArgsIter { - base: env::ArgsOs, - file: std::vec::IntoIter, -} - -impl ArgsIter { - pub fn new() -> Self { - ArgsIter { base: env::args_os(), file: vec![].into_iter() } - } -} - -impl Iterator for ArgsIter { - type Item = Result; - - fn next(&mut self) -> Option { - loop { - if let Some(line) = self.file.next() { - return Some(Ok(line)); - } - - let arg = - self.base.next().map(|arg| arg.into_string().map_err(|_| Error::Utf8Error(None))); - match arg { - Some(Err(err)) => return Some(Err(err)), - Some(Ok(ref arg)) if arg.starts_with("@") => { - let path = &arg[1..]; - let file = match fs::read_to_string(path) { - Ok(file) => { - USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); - file - } - Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { - return Some(Err(Error::Utf8Error(Some(path.to_string())))); - } - Err(err) => return Some(Err(Error::IOError(path.to_string(), err))), - }; - self.file = - file.lines().map(ToString::to_string).collect::>().into_iter(); - } - Some(Ok(arg)) => return Some(Ok(arg)), - None => return None, - } - } - } -} - -#[derive(Debug)] -pub enum Error { - Utf8Error(Option), - 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), - } - } -} - -impl error::Error for Error { - fn description(&self) -> &'static str { - "argument error" - } -} diff --git a/src/librustc_driver/args/tests.rs b/src/librustc_driver/args/tests.rs deleted file mode 100644 index 080dd5cb746c3..0000000000000 --- a/src/librustc_driver/args/tests.rs +++ /dev/null @@ -1,145 +0,0 @@ -use super::*; - -use std::str; - -fn want_args(v: impl IntoIterator) -> Vec { - v.into_iter().map(String::from).collect() -} - -fn got_args(file: &[u8]) -> Result, Error> { - let ret = str::from_utf8(file) - .map_err(|_| Error::Utf8Error(None))? - .lines() - .map(ToString::to_string) - .collect::>(); - Ok(ret) -} - -#[test] -fn nothing() { - let file = b""; - - assert_eq!(got_args(file).unwrap(), want_args(vec![])); -} - -#[test] -fn empty() { - let file = b"\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec![""])); -} - -#[test] -fn simple() { - let file = b"foo"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); -} - -#[test] -fn simple_eol() { - let file = b"foo\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); -} - -#[test] -fn multi() { - let file = b"foo\nbar"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); -} - -#[test] -fn multi_eol() { - let file = b"foo\nbar\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); -} - -#[test] -fn multi_empty() { - let file = b"foo\n\nbar"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); -} - -#[test] -fn multi_empty_eol() { - let file = b"foo\n\nbar\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); -} - -#[test] -fn multi_empty_start() { - let file = b"\nfoo\nbar"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); -} - -#[test] -fn multi_empty_end() { - let file = b"foo\nbar\n\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); -} - -#[test] -fn simple_eol_crlf() { - let file = b"foo\r\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); -} - -#[test] -fn multi_crlf() { - let file = b"foo\r\nbar"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); -} - -#[test] -fn multi_eol_crlf() { - let file = b"foo\r\nbar\r\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); -} - -#[test] -fn multi_empty_crlf() { - let file = b"foo\r\n\r\nbar"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); -} - -#[test] -fn multi_empty_eol_crlf() { - let file = b"foo\r\n\r\nbar\r\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); -} - -#[test] -fn multi_empty_start_crlf() { - let file = b"\r\nfoo\r\nbar"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); -} - -#[test] -fn multi_empty_end_crlf() { - let file = b"foo\r\nbar\r\n\r\n"; - - assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); -} - -#[test] -fn bad_utf8() { - let file = b"foo\x80foo"; - - match got_args(file).unwrap_err() { - Error::Utf8Error(_) => (), - bad => panic!("bad err: {:?}", bad), - } -} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4843c1a951b31..2cec404c3d7f6 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -140,14 +140,22 @@ impl Callbacks for TimePassesCallbacks { // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. pub fn run_compiler( - args: &[String], + at_args: &[String], callbacks: &mut (dyn Callbacks + Send), file_loader: Option>, emitter: Option> ) -> interface::Result<()> { + let mut args = Vec::new(); + for arg in at_args { + match args::arg_expand(arg.clone()) { + Ok(arg) => args.extend(arg), + Err(err) => early_error(ErrorOutputType::default(), + &format!("Failed to load argument file: {}", err)), + } + } let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter)) .unwrap_or(DiagnosticOutput::Default); - let matches = match handle_options(args) { + let matches = match handle_options(&args) { Some(matches) => matches, None => return Ok(()), }; @@ -1199,10 +1207,10 @@ pub fn main() { init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); let result = report_ices_to_stderr_if_any(|| { - let args = args::ArgsIter::new().enumerate() - .map(|(i, arg)| arg.unwrap_or_else(|err| { - early_error(ErrorOutputType::default(), - &format!("Argument {} is not valid: {}", i, err)) + let args = env::args_os().enumerate() + .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { + early_error(ErrorOutputType::default(), + &format!("Argument {} is not valid Unicode: {:?}", i, arg)) })) .collect::>(); run_compiler(&args, &mut callbacks, None, None) diff --git a/src/test/ui/commandline-argfile-badutf8.rs b/src/test/ui/commandline-argfile-badutf8.rs index c017e7b5ea60b..161715685b57f 100644 --- a/src/test/ui/commandline-argfile-badutf8.rs +++ b/src/test/ui/commandline-argfile-badutf8.rs @@ -1,7 +1,6 @@ // Check to see if we can get parameters from an @argsfile file // // build-fail -// normalize-stderr-test: "Argument \d+" -> "Argument $$N" // compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args #[cfg(not(cmdline_set))] diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr index cd8a03e34eac9..9af6fc0a518df 100644 --- a/src/test/ui/commandline-argfile-badutf8.stderr +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -1,2 +1,2 @@ -error: Argument $N is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args +error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args diff --git a/src/test/ui/commandline-argfile-missing.rs b/src/test/ui/commandline-argfile-missing.rs index 34faf07633599..a29b4ab062de3 100644 --- a/src/test/ui/commandline-argfile-missing.rs +++ b/src/test/ui/commandline-argfile-missing.rs @@ -1,7 +1,7 @@ // Check to see if we can get parameters from an @argsfile file // +// ignore-tidy-linelength // build-fail -// normalize-stderr-test: "Argument \d+" -> "Argument $$N" // 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 diff --git a/src/test/ui/commandline-argfile-missing.stderr b/src/test/ui/commandline-argfile-missing.stderr index c0017782f2eb3..179ad83100419 100644 --- a/src/test/ui/commandline-argfile-missing.stderr +++ b/src/test/ui/commandline-argfile-missing.stderr @@ -1,2 +1,2 @@ -error: Argument $N is not valid: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR) +error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR)