Skip to content

Commit ad7aaa4

Browse files
committed
Frontend: Fix layering between create{,Default}OutputFile, NFC
Fix layering between `CompilerInstance::createDefaultOutputFile` and the two versions of `createOutputFile`. - Add missing configuration flags to `createDefaultOutputFile` so that GeneratePCHAction and GenerateModuleFromModuleMapAction can use it. They previously promised that temporary files were turned on; now `createDefaultOutputFile` handles that logic. - Lift the logic handling `InFile` and `Extension` to `createDefaultOutputFile`, since it's only the callers of that function that are using it. - Rename the deeper of the two `createOutputFile`s to `createOutputFileImpl` and make it private to `CompilerInstance` (to prove that no one else is using it). - Sink the logic for adding to `CompilerInstance::OutputFiles` down to `createOutputFileImpl`, allowing two "optional" (but always used) `std::string*` out parameters to be removed. - Instead of passing a `std::error_code` out parameter into `createOutputFileImpl`, have it return `Expected<>`. - As a drive-by, inline `CompilerInstance::addOutputFile` into its only caller, `createOutputFileImpl`. Clean layering makes it easier for a future commit to extract `createOutputFileImpl` out of `CompilerInstance`. Differential Revision: https://reviews.llvm.org/D93248
1 parent 4d28f0a commit ad7aaa4

File tree

4 files changed

+79
-111
lines changed

4 files changed

+79
-111
lines changed

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -578,11 +578,6 @@ class CompilerInstance : public ModuleLoader {
578578
/// @name Output Files
579579
/// {
580580

581-
/// addOutputFile - Add an output file onto the list of tracked output files.
582-
///
583-
/// \param OutFile - The output file info.
584-
void addOutputFile(OutputFile &&OutFile);
585-
586581
/// clearOutputFiles - Clear the output file list. The underlying output
587582
/// streams must have been closed beforehand.
588583
///
@@ -695,25 +690,29 @@ class CompilerInstance : public ModuleLoader {
695690
/// Create the default output file (from the invocation's options) and add it
696691
/// to the list of tracked output files.
697692
///
698-
/// The files created by this function always use temporary files to write to
699-
/// their result (that is, the data is written to a temporary file which will
700-
/// atomically replace the target output on success).
693+
/// The files created by this are usually removed on signal, and, depending
694+
/// on FrontendOptions, may also use a temporary file (that is, the data is
695+
/// written to a temporary file which will atomically replace the target
696+
/// output on success). If a client (like libclang) needs to disable
697+
/// RemoveFileOnSignal, temporary files will be forced on.
701698
///
702699
/// \return - Null on error.
703700
std::unique_ptr<raw_pwrite_stream>
704701
createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "",
705-
StringRef Extension = "");
702+
StringRef Extension = "",
703+
bool RemoveFileOnSignal = true,
704+
bool CreateMissingDirectories = false);
706705

707-
/// Create a new output file and add it to the list of tracked output files,
708-
/// optionally deriving the output path name.
706+
/// Create a new output file, optionally deriving the output path name, and
707+
/// add it to the list of tracked output files.
709708
///
710709
/// \return - Null on error.
711710
std::unique_ptr<raw_pwrite_stream>
712711
createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal,
713-
StringRef BaseInput, StringRef Extension, bool UseTemporary,
714-
bool CreateMissingDirectories = false);
712+
bool UseTemporary, bool CreateMissingDirectories = false);
715713

716-
/// Create a new output file, optionally deriving the output path name.
714+
private:
715+
/// Create a new output file and add it to the list of tracked output files.
717716
///
718717
/// If \p OutputPath is empty, then createOutputFile will derive an output
719718
/// path location as \p BaseInput, with any suffix removed, and \p Extension
@@ -722,10 +721,6 @@ class CompilerInstance : public ModuleLoader {
722721
/// renamed to \p OutputPath in the end.
723722
///
724723
/// \param OutputPath - If given, the path to the output file.
725-
/// \param Error [out] - On failure, the error.
726-
/// \param BaseInput - If \p OutputPath is empty, the input path name to use
727-
/// for deriving the output path.
728-
/// \param Extension - The extension to use for derived output names.
729724
/// \param Binary - The mode to open the file in.
730725
/// \param RemoveFileOnSignal - Whether the file should be registered with
731726
/// llvm::sys::RemoveFileOnSignal. Note that this is not safe for
@@ -734,17 +729,12 @@ class CompilerInstance : public ModuleLoader {
734729
/// OutputPath in the end.
735730
/// \param CreateMissingDirectories - When \p UseTemporary is true, create
736731
/// missing directories in the output path.
737-
/// \param ResultPathName [out] - If given, the result path name will be
738-
/// stored here on success.
739-
/// \param TempPathName [out] - If given, the temporary file path name
740-
/// will be stored here on success.
741-
std::unique_ptr<raw_pwrite_stream>
742-
createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary,
743-
bool RemoveFileOnSignal, StringRef BaseInput,
744-
StringRef Extension, bool UseTemporary,
745-
bool CreateMissingDirectories, std::string *ResultPathName,
746-
std::string *TempPathName);
732+
Expected<std::unique_ptr<raw_pwrite_stream>>
733+
createOutputFileImpl(StringRef OutputPath, bool Binary,
734+
bool RemoveFileOnSignal, bool UseTemporary,
735+
bool CreateMissingDirectories);
747736

737+
public:
748738
std::unique_ptr<raw_pwrite_stream> createNullOutputFile();
749739

750740
/// }

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 51 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -646,10 +646,6 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind,
646646

647647
// Output Files
648648

649-
void CompilerInstance::addOutputFile(OutputFile &&OutFile) {
650-
OutputFiles.push_back(std::move(OutFile));
651-
}
652-
653649
void CompilerInstance::clearOutputFiles(bool EraseFiles) {
654650
for (OutputFile &OF : OutputFiles) {
655651
if (!OF.TempFilename.empty()) {
@@ -682,10 +678,25 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
682678

683679
std::unique_ptr<raw_pwrite_stream>
684680
CompilerInstance::createDefaultOutputFile(bool Binary, StringRef InFile,
685-
StringRef Extension) {
686-
return createOutputFile(getFrontendOpts().OutputFile, Binary,
687-
/*RemoveFileOnSignal=*/true, InFile, Extension,
688-
getFrontendOpts().UseTemporary);
681+
StringRef Extension,
682+
bool RemoveFileOnSignal,
683+
bool CreateMissingDirectories) {
684+
StringRef OutputPath = getFrontendOpts().OutputFile;
685+
Optional<SmallString<128>> PathStorage;
686+
if (OutputPath.empty()) {
687+
if (InFile == "-" || Extension.empty()) {
688+
OutputPath = "-";
689+
} else {
690+
PathStorage.emplace(InFile);
691+
llvm::sys::path::replace_extension(*PathStorage, Extension);
692+
OutputPath = *PathStorage;
693+
}
694+
}
695+
696+
// Force a temporary file if RemoveFileOnSignal was disabled.
697+
return createOutputFile(OutputPath, Binary, RemoveFileOnSignal,
698+
getFrontendOpts().UseTemporary || !RemoveFileOnSignal,
699+
CreateMissingDirectories);
689700
}
690701

691702
std::unique_ptr<raw_pwrite_stream> CompilerInstance::createNullOutputFile() {
@@ -694,64 +705,40 @@ std::unique_ptr<raw_pwrite_stream> CompilerInstance::createNullOutputFile() {
694705

695706
std::unique_ptr<raw_pwrite_stream>
696707
CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary,
697-
bool RemoveFileOnSignal, StringRef InFile,
698-
StringRef Extension, bool UseTemporary,
708+
bool RemoveFileOnSignal, bool UseTemporary,
699709
bool CreateMissingDirectories) {
700-
std::string OutputPathName, TempPathName;
701-
std::error_code EC;
702-
std::unique_ptr<raw_pwrite_stream> OS = createOutputFile(
703-
OutputPath, EC, Binary, RemoveFileOnSignal, InFile, Extension,
704-
UseTemporary, CreateMissingDirectories, &OutputPathName, &TempPathName);
705-
if (!OS) {
706-
getDiagnostics().Report(diag::err_fe_unable_to_open_output) << OutputPath
707-
<< EC.message();
708-
return nullptr;
709-
}
710-
711-
// Add the output file -- but don't try to remove "-", since this means we are
712-
// using stdin.
713-
addOutputFile(
714-
OutputFile((OutputPathName != "-") ? OutputPathName : "", TempPathName));
715-
716-
return OS;
710+
Expected<std::unique_ptr<raw_pwrite_stream>> OS =
711+
createOutputFileImpl(OutputPath, Binary, RemoveFileOnSignal, UseTemporary,
712+
CreateMissingDirectories);
713+
if (OS)
714+
return std::move(*OS);
715+
getDiagnostics().Report(diag::err_fe_unable_to_open_output)
716+
<< OutputPath << errorToErrorCode(OS.takeError()).message();
717+
return nullptr;
717718
}
718719

719-
std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
720-
StringRef OutputPath, std::error_code &Error, bool Binary,
721-
bool RemoveFileOnSignal, StringRef InFile, StringRef Extension,
722-
bool UseTemporary, bool CreateMissingDirectories,
723-
std::string *ResultPathName, std::string *TempPathName) {
720+
Expected<std::unique_ptr<llvm::raw_pwrite_stream>>
721+
CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary,
722+
bool RemoveFileOnSignal,
723+
bool UseTemporary,
724+
bool CreateMissingDirectories) {
724725
assert((!CreateMissingDirectories || UseTemporary) &&
725726
"CreateMissingDirectories is only allowed when using temporary files");
726727

727-
std::string OutFile, TempFile;
728-
if (!OutputPath.empty()) {
729-
OutFile = std::string(OutputPath);
730-
} else if (InFile == "-") {
731-
OutFile = "-";
732-
} else if (!Extension.empty()) {
733-
SmallString<128> Path(InFile);
734-
llvm::sys::path::replace_extension(Path, Extension);
735-
OutFile = std::string(Path.str());
736-
} else {
737-
OutFile = "-";
738-
}
739-
740728
std::unique_ptr<llvm::raw_fd_ostream> OS;
741-
std::string OSFile;
729+
Optional<StringRef> OSFile;
742730

743731
if (UseTemporary) {
744-
if (OutFile == "-")
732+
if (OutputPath == "-")
745733
UseTemporary = false;
746734
else {
747735
llvm::sys::fs::file_status Status;
748736
llvm::sys::fs::status(OutputPath, Status);
749737
if (llvm::sys::fs::exists(Status)) {
750738
// Fail early if we can't write to the final destination.
751-
if (!llvm::sys::fs::can_write(OutputPath)) {
752-
Error = make_error_code(llvm::errc::operation_not_permitted);
753-
return nullptr;
754-
}
739+
if (!llvm::sys::fs::can_write(OutputPath))
740+
return llvm::errorCodeToError(
741+
make_error_code(llvm::errc::operation_not_permitted));
755742

756743
// Don't use a temporary if the output is a special file. This handles
757744
// things like '-o /dev/null'
@@ -761,14 +748,15 @@ std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
761748
}
762749
}
763750

751+
std::string TempFile;
764752
if (UseTemporary) {
765753
// Create a temporary file.
766754
// Insert -%%%%%%%% before the extension (if any), and because some tools
767755
// (noticeable, clang's own GlobalModuleIndex.cpp) glob for build
768756
// artifacts, also append .tmp.
769-
StringRef OutputExtension = llvm::sys::path::extension(OutFile);
757+
StringRef OutputExtension = llvm::sys::path::extension(OutputPath);
770758
SmallString<128> TempPath =
771-
StringRef(OutFile).drop_back(OutputExtension.size());
759+
StringRef(OutputPath).drop_back(OutputExtension.size());
772760
TempPath += "-%%%%%%%%";
773761
TempPath += OutputExtension;
774762
TempPath += ".tmp";
@@ -795,22 +783,23 @@ std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
795783
}
796784

797785
if (!OS) {
798-
OSFile = OutFile;
786+
OSFile = OutputPath;
787+
std::error_code EC;
799788
OS.reset(new llvm::raw_fd_ostream(
800-
OSFile, Error,
789+
*OSFile, EC,
801790
(Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text)));
802-
if (Error)
803-
return nullptr;
791+
if (EC)
792+
return llvm::errorCodeToError(EC);
804793
}
805794

806795
// Make sure the out stream file gets removed if we crash.
807796
if (RemoveFileOnSignal)
808-
llvm::sys::RemoveFileOnSignal(OSFile);
797+
llvm::sys::RemoveFileOnSignal(*OSFile);
809798

810-
if (ResultPathName)
811-
*ResultPathName = OutFile;
812-
if (TempPathName)
813-
*TempPathName = TempFile;
799+
// Add the output file -- but don't try to remove "-", since this means we are
800+
// using stdin.
801+
OutputFiles.emplace_back(((OutputPath != "-") ? OutputPath : "").str(),
802+
std::move(TempFile));
814803

815804
if (!Binary || OS->supportsSeeking())
816805
return std::move(OS);

clang/lib/Frontend/FrontendActions.cpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,9 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
136136
std::unique_ptr<llvm::raw_pwrite_stream>
137137
GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile,
138138
std::string &OutputFile) {
139-
// We use createOutputFile here because this is exposed via libclang, and we
140-
// must disable the RemoveFileOnSignal behavior.
141-
// We use a temporary to avoid race conditions.
142-
std::unique_ptr<raw_pwrite_stream> OS =
143-
CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
144-
/*RemoveFileOnSignal=*/false, InFile,
145-
/*Extension=*/"", CI.getFrontendOpts().UseTemporary);
139+
// Because this is exposed via libclang we must disable RemoveFileOnSignal.
140+
std::unique_ptr<raw_pwrite_stream> OS = CI.createDefaultOutputFile(
141+
/*Binary=*/true, InFile, /*Extension=*/"", /*RemoveFileOnSignal=*/false);
146142
if (!OS)
147143
return nullptr;
148144

@@ -219,13 +215,10 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
219215
ModuleMapFile);
220216
}
221217

222-
// We use createOutputFile here because this is exposed via libclang, and we
223-
// must disable the RemoveFileOnSignal behavior.
224-
// We use a temporary to avoid race conditions.
225-
return CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
226-
/*RemoveFileOnSignal=*/false, InFile,
227-
/*Extension=*/"", /*UseTemporary=*/true,
228-
/*CreateMissingDirectories=*/true);
218+
// Because this is exposed via libclang we must disable RemoveFileOnSignal.
219+
return CI.createDefaultOutputFile(/*Binary=*/true, InFile, /*Extension=*/"",
220+
/*RemoveFileOnSignal=*/false,
221+
/*CreateMissingDirectories=*/true);
229222
}
230223

231224
bool GenerateModuleInterfaceAction::BeginSourceFileAction(

clang/tools/driver/cc1_main.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
248248
if (llvm::timeTraceProfilerEnabled()) {
249249
SmallString<128> Path(Clang->getFrontendOpts().OutputFile);
250250
llvm::sys::path::replace_extension(Path, "json");
251-
if (auto profilerOutput =
252-
Clang->createOutputFile(Path.str(),
253-
/*Binary=*/false,
254-
/*RemoveFileOnSignal=*/false, "",
255-
/*Extension=*/"json",
256-
/*useTemporary=*/false)) {
257-
251+
if (auto profilerOutput = Clang->createOutputFile(
252+
Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false,
253+
/*useTemporary=*/false)) {
258254
llvm::timeTraceProfilerWrite(*profilerOutput);
259255
// FIXME(ibiryukov): make profilerOutput flush in destructor instead.
260256
profilerOutput->flush();

0 commit comments

Comments
 (0)