Small improvements to createOutputFile.
* Use a single stat to find out if the file exists and if it is a regular file.
* Use early returns when possible.
* Add comments explaining why we have each check.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@185091 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 3ad05a6..5673c59 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -591,10 +591,10 @@
/// \return - Null on error.
llvm::raw_fd_ostream *
createOutputFile(StringRef OutputPath,
- bool Binary = true, bool RemoveFileOnSignal = true,
- StringRef BaseInput = "",
- StringRef Extension = "",
- bool UseTemporary = false,
+ bool Binary, bool RemoveFileOnSignal,
+ StringRef BaseInput,
+ StringRef Extension,
+ bool UseTemporary,
bool CreateMissingDirectories = false);
/// Create a new output file, optionally deriving the output path name.
@@ -624,13 +624,13 @@
/// will be stored here on success.
static llvm::raw_fd_ostream *
createOutputFile(StringRef OutputPath, std::string &Error,
- bool Binary = true, bool RemoveFileOnSignal = true,
- StringRef BaseInput = "",
- StringRef Extension = "",
- bool UseTemporary = false,
- bool CreateMissingDirectories = false,
- std::string *ResultPathName = 0,
- std::string *TempPathName = 0);
+ bool Binary, bool RemoveFileOnSignal,
+ StringRef BaseInput,
+ StringRef Extension,
+ bool UseTemporary,
+ bool CreateMissingDirectories,
+ std::string *ResultPathName,
+ std::string *TempPathName);
/// }
/// @name Initialization Utility Methods
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 4bd398e..ec1f959 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -519,36 +519,52 @@
OwningPtr<llvm::raw_fd_ostream> OS;
std::string OSFile;
- if (UseTemporary && OutFile != "-") {
- // Only create the temporary if the parent directory exists (or create
- // missing directories is true) and we can actually write to OutPath,
- // otherwise we want to fail early.
- SmallString<256> AbsPath(OutputPath);
- llvm::sys::fs::make_absolute(AbsPath);
- StringRef OutPath = AbsPath;
- bool ParentExists = false;
- if (llvm::sys::fs::exists(llvm::sys::path::parent_path(AbsPath.str()),
- ParentExists))
- ParentExists = false;
- bool Exists;
- if ((CreateMissingDirectories || ParentExists) &&
- ((llvm::sys::fs::exists(AbsPath.str(), Exists) || !Exists) ||
- (llvm::sys::fs::is_regular_file(OutPath) &&
- llvm::sys::fs::can_write(AbsPath.c_str())))) {
- // Create a temporary file.
- SmallString<128> TempPath;
- TempPath = OutFile;
- TempPath += "-%%%%%%%%";
- int fd;
- if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
- /*makeAbsolute=*/false, 0664)
- == llvm::errc::success) {
- OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
- OSFile = TempFile = TempPath.str();
+ if (UseTemporary) {
+ if (OutFile == "-")
+ UseTemporary = false;
+ else {
+ llvm::sys::fs::file_status Status;
+ llvm::sys::fs::status(OutputPath, Status);
+ if (llvm::sys::fs::exists(Status)) {
+ // Fail early if we can't write to the final destination.
+ if (!llvm::sys::fs::can_write(OutputPath))
+ return 0;
+
+ // Don't use a temporary if the output is a special file. This handles
+ // things like '-o /dev/null'
+ if (!llvm::sys::fs::is_regular_file(Status))
+ UseTemporary = false;
}
}
}
+ if (UseTemporary) {
+ SmallString<256> AbsPath(OutputPath);
+ llvm::sys::fs::make_absolute(AbsPath);
+
+ // If the parent directory doesn't exist and we can't create it, fail.
+ bool ParentExists =
+ llvm::sys::fs::exists(llvm::sys::path::parent_path(AbsPath.str()));
+ if (!CreateMissingDirectories && !ParentExists) {
+ Error = "Parent directory doesn't exist";
+ return 0;
+ }
+
+ // Create a temporary file.
+ SmallString<128> TempPath;
+ TempPath = OutFile;
+ TempPath += "-%%%%%%%%";
+ int fd;
+ if (!llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
+ /*makeAbsolute=*/false, 0664)) {
+ OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
+ OSFile = TempFile = TempPath.str();
+ }
+ // If we failed to create the temporary, fallback to writing to the file
+ // directly. This handles the corner case where we cannot write to the
+ // directory, but can write to the file.
+ }
+
if (!OS) {
OSFile = OutFile;
OS.reset(
diff --git a/test/Frontend/output-failures.c b/test/Frontend/output-failures.c
index e2af7c7..2b5aba6 100644
--- a/test/Frontend/output-failures.c
+++ b/test/Frontend/output-failures.c
@@ -1,4 +1,4 @@
// RUN: not %clang_cc1 -emit-llvm -o %S/doesnotexist/somename %s 2> %t
// RUN: FileCheck -check-prefix=OUTPUTFAIL -input-file=%t %s
-// OUTPUTFAIL: Error opening output file '{{.*}}doesnotexist{{.*}}'
+// OUTPUTFAIL: unable to open output file '{{.*}}doesnotexist{{.*}}': 'Parent directory doesn't exist'