Warn when rustc output conflicts with existing directories

When the compiled executable would conflict with a directory, display a
rustc error instead of a verbose and potentially-confusing linker
error. This is a usability improvement, and doesn’t actually change
behaviour with regards to compilation success. This addresses the
concern in #35887.
This commit is contained in:
varkor 2018-01-05 00:31:40 +00:00
parent 6b99adeb11
commit df1c61d303
4 changed files with 64 additions and 17 deletions

View file

@ -549,23 +549,43 @@ impl OutputFilenames {
format!("{}{}", self.out_filestem, self.extra) format!("{}{}", self.out_filestem, self.extra)
} }
fn check_output<F, T>(&self, f: F) -> Option<T> where F: Fn(PathBuf) -> Option<T> {
match self.single_output_file {
Some(ref output_path) => {
f(output_path.clone())
},
None => {
for k in self.outputs.keys() {
let output_path = self.path(k.to_owned());
if let Some(result) = f(output_path) {
return Some(result);
}
}
None
}
}
}
pub fn contains_path(&self, input_path: &PathBuf) -> bool { pub fn contains_path(&self, input_path: &PathBuf) -> bool {
let input_path = input_path.canonicalize().ok(); let input_path = input_path.canonicalize().ok();
if input_path.is_none() { if input_path.is_none() {
return false return false
} }
match self.single_output_file { let check = |output_path: PathBuf| {
Some(ref output_path) => output_path.canonicalize().ok() == input_path,
None => {
for k in self.outputs.keys() {
let output_path = self.path(k.to_owned());
if output_path.canonicalize().ok() == input_path { if output_path.canonicalize().ok() == input_path {
return true; Some(())
} } else { None }
} };
false self.check_output(check).is_some()
}
} }
pub fn conflicts_with_dir(&self) -> Option<PathBuf> {
let check = |output_path: PathBuf| {
if output_path.is_dir() {
Some(output_path)
} else { None }
};
self.check_output(check)
} }
} }

View file

@ -125,12 +125,21 @@ pub fn compile_input(trans: Box<TransCrate>,
// Ensure the source file isn't accidentally overwritten during compilation. // Ensure the source file isn't accidentally overwritten during compilation.
match *input_path { match *input_path {
Some(ref input_path) => { Some(ref input_path) => {
if outputs.contains_path(input_path) && sess.opts.will_create_output_file() { if sess.opts.will_create_output_file() {
if outputs.contains_path(input_path) {
sess.err(&format!( sess.err(&format!(
"the input file \"{}\" would be overwritten by the generated executable", "the input file \"{}\" would be overwritten by the generated executable",
input_path.display())); input_path.display()));
return Err(CompileIncomplete::Stopped); return Err(CompileIncomplete::Stopped);
} }
if let Some(dir_path) = outputs.conflicts_with_dir() {
sess.err(&format!(
"the generated executable for the input file \"{}\" conflicts with the \
existing directory \"{}\'",
input_path.display(), dir_path.display()));
return Err(CompileIncomplete::Stopped);
}
}
}, },
None => {} None => {}
} }

View file

@ -0,0 +1,7 @@
-include ../tools.mk
all:
cp foo.rs $(TMPDIR)/foo.rs
mkdir $(TMPDIR)/foo
$(RUSTC) $(TMPDIR)/foo.rs 2>&1 \
| $(CGREP) -e "the generated executable for the input file \".*foo\.rs\" conflicts with the existing directory \".*foo\'"

View file

@ -0,0 +1,11 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() {}