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.
This commit is contained in:
parent
d2219c2e2e
commit
d9497749a8
53
src/librustc_driver/args.rs
Normal file
53
src/librustc_driver/args.rs
Normal file
@ -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<Vec<String>, 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<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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error {
|
||||||
|
fn description(&self) -> &'static str {
|
||||||
|
"argument error"
|
||||||
|
}
|
||||||
|
}
|
@ -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<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArgsIter {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
ArgsIter { base: env::args_os(), file: vec![].into_iter() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for ArgsIter {
|
|
||||||
type Item = Result<String, Error>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
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::<Vec<_>>().into_iter();
|
|
||||||
}
|
|
||||||
Some(Ok(arg)) => return Some(Ok(arg)),
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
Utf8Error(Option<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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn description(&self) -> &'static str {
|
|
||||||
"argument error"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
fn want_args(v: impl IntoIterator<Item = &'static str>) -> Vec<String> {
|
|
||||||
v.into_iter().map(String::from).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn got_args(file: &[u8]) -> Result<Vec<String>, Error> {
|
|
||||||
let ret = str::from_utf8(file)
|
|
||||||
.map_err(|_| Error::Utf8Error(None))?
|
|
||||||
.lines()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
@ -140,14 +140,22 @@ fn config(&mut self, config: &mut interface::Config) {
|
|||||||
// See comments on CompilerCalls below for details about the callbacks argument.
|
// 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.
|
// The FileLoader provides a way to load files from sources other than the file system.
|
||||||
pub fn run_compiler(
|
pub fn run_compiler(
|
||||||
args: &[String],
|
at_args: &[String],
|
||||||
callbacks: &mut (dyn Callbacks + Send),
|
callbacks: &mut (dyn Callbacks + Send),
|
||||||
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||||
emitter: Option<Box<dyn Write + Send>>
|
emitter: Option<Box<dyn Write + Send>>
|
||||||
) -> interface::Result<()> {
|
) -> 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))
|
let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter))
|
||||||
.unwrap_or(DiagnosticOutput::Default);
|
.unwrap_or(DiagnosticOutput::Default);
|
||||||
let matches = match handle_options(args) {
|
let matches = match handle_options(&args) {
|
||||||
Some(matches) => matches,
|
Some(matches) => matches,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -1199,10 +1207,10 @@ pub fn main() {
|
|||||||
init_rustc_env_logger();
|
init_rustc_env_logger();
|
||||||
let mut callbacks = TimePassesCallbacks::default();
|
let mut callbacks = TimePassesCallbacks::default();
|
||||||
let result = report_ices_to_stderr_if_any(|| {
|
let result = report_ices_to_stderr_if_any(|| {
|
||||||
let args = args::ArgsIter::new().enumerate()
|
let args = env::args_os().enumerate()
|
||||||
.map(|(i, arg)| arg.unwrap_or_else(|err| {
|
.map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
|
||||||
early_error(ErrorOutputType::default(),
|
early_error(ErrorOutputType::default(),
|
||||||
&format!("Argument {} is not valid: {}", i, err))
|
&format!("Argument {} is not valid Unicode: {:?}", i, arg))
|
||||||
}))
|
}))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
run_compiler(&args, &mut callbacks, None, None)
|
run_compiler(&args, &mut callbacks, None, None)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Check to see if we can get parameters from an @argsfile file
|
// Check to see if we can get parameters from an @argsfile file
|
||||||
//
|
//
|
||||||
// build-fail
|
// build-fail
|
||||||
// normalize-stderr-test: "Argument \d+" -> "Argument $$N"
|
|
||||||
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args
|
// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args
|
||||||
|
|
||||||
#[cfg(not(cmdline_set))]
|
#[cfg(not(cmdline_set))]
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Check to see if we can get parameters from an @argsfile file
|
// Check to see if we can get parameters from an @argsfile file
|
||||||
//
|
//
|
||||||
|
// ignore-tidy-linelength
|
||||||
// build-fail
|
// build-fail
|
||||||
// normalize-stderr-test: "Argument \d+" -> "Argument $$N"
|
|
||||||
// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
|
// normalize-stderr-test: "os error \d+" -> "os error $$ERR"
|
||||||
// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING "
|
// 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}}/commandline-argfile-missing.args
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user