[Clang][Driver] Create crash reproducers for IR inputs (#165572)
This patch makes Clang produce the crash reproducer shell script for IR inputs as well.
This commit is contained in:
parent
47d9d735a7
commit
83d27f6c84
2 changed files with 91 additions and 33 deletions
|
|
@ -70,6 +70,7 @@
|
|||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
|
|
@ -103,6 +104,7 @@
|
|||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#if LLVM_ON_UNIX
|
||||
#include <unistd.h> // getpid
|
||||
|
|
@ -2050,12 +2052,17 @@ void Driver::generateCompilationDiagnostics(
|
|||
InputList Inputs;
|
||||
BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs);
|
||||
|
||||
ArgStringList IRInputs;
|
||||
for (InputList::iterator it = Inputs.begin(), ie = Inputs.end(); it != ie;) {
|
||||
bool IgnoreInput = false;
|
||||
|
||||
// Ignore input from stdin or any inputs that cannot be preprocessed.
|
||||
// Check type first as not all linker inputs have a value.
|
||||
if (types::getPreprocessedType(it->first) == types::TY_INVALID) {
|
||||
// Save IR inputs separately, ignore input from stdin or any other inputs
|
||||
// that cannot be preprocessed. Check type first as not all linker inputs
|
||||
// have a value.
|
||||
if (types::isLLVMIR(it->first)) {
|
||||
IRInputs.push_back(it->second->getValue());
|
||||
IgnoreInput = true;
|
||||
} else if (types::getPreprocessedType(it->first) == types::TY_INVALID) {
|
||||
IgnoreInput = true;
|
||||
} else if (!strcmp(it->second->getValue(), "-")) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
|
|
@ -2072,7 +2079,7 @@ void Driver::generateCompilationDiagnostics(
|
|||
}
|
||||
}
|
||||
|
||||
if (Inputs.empty()) {
|
||||
if (Inputs.empty() && IRInputs.empty()) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating preprocessed source(s) - "
|
||||
"no preprocessable inputs.";
|
||||
|
|
@ -2095,46 +2102,82 @@ void Driver::generateCompilationDiagnostics(
|
|||
return;
|
||||
}
|
||||
|
||||
// Construct the list of abstract actions to perform for this compilation. On
|
||||
// Darwin OSes this uses the driver-driver and builds universal actions.
|
||||
const ToolChain &TC = C.getDefaultToolChain();
|
||||
if (TC.getTriple().isOSBinFormatMachO())
|
||||
BuildUniversalActions(C, TC, Inputs);
|
||||
else
|
||||
BuildActions(C, C.getArgs(), Inputs, C.getActions());
|
||||
// If we only have IR inputs there's no need for preprocessing.
|
||||
if (!Inputs.empty()) {
|
||||
// Construct the list of abstract actions to perform for this compilation.
|
||||
// On Darwin OSes this uses the driver-driver and builds universal actions.
|
||||
const ToolChain &TC = C.getDefaultToolChain();
|
||||
if (TC.getTriple().isOSBinFormatMachO())
|
||||
BuildUniversalActions(C, TC, Inputs);
|
||||
else
|
||||
BuildActions(C, C.getArgs(), Inputs, C.getActions());
|
||||
|
||||
BuildJobs(C);
|
||||
BuildJobs(C);
|
||||
|
||||
// If there were errors building the compilation, quit now.
|
||||
if (Trap.hasErrorOccurred()) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating preprocessed source(s).";
|
||||
return;
|
||||
// If there were errors building the compilation, quit now.
|
||||
if (Trap.hasErrorOccurred()) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating preprocessed source(s).";
|
||||
return;
|
||||
}
|
||||
// Generate preprocessed output.
|
||||
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
|
||||
C.ExecuteJobs(C.getJobs(), FailingCommands);
|
||||
|
||||
// If any of the preprocessing commands failed, clean up and exit.
|
||||
if (!FailingCommands.empty()) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating preprocessed source(s).";
|
||||
return;
|
||||
}
|
||||
|
||||
const ArgStringList &TempFiles = C.getTempFiles();
|
||||
if (TempFiles.empty()) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating preprocessed source(s).";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate preprocessed output.
|
||||
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
|
||||
C.ExecuteJobs(C.getJobs(), FailingCommands);
|
||||
// Copying filenames due to ownership.
|
||||
const ArgStringList &Files = C.getTempFiles();
|
||||
SmallVector<std::string> TempFiles(Files.begin(), Files.end());
|
||||
|
||||
// If any of the preprocessing commands failed, clean up and exit.
|
||||
if (!FailingCommands.empty()) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating preprocessed source(s).";
|
||||
return;
|
||||
}
|
||||
// We'd like to copy the IR input file into our own temp file
|
||||
// because the build system might try to clean-up after itself.
|
||||
for (auto const *Input : IRInputs) {
|
||||
int FD;
|
||||
llvm::SmallVector<char, 64> Path;
|
||||
|
||||
const ArgStringList &TempFiles = C.getTempFiles();
|
||||
if (TempFiles.empty()) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating preprocessed source(s).";
|
||||
return;
|
||||
StringRef extension = llvm::sys::path::extension(Input);
|
||||
if (!extension.empty())
|
||||
extension = extension.drop_front();
|
||||
|
||||
std::error_code EC = llvm::sys::fs::createTemporaryFile(
|
||||
llvm::sys::path::stem(Input), extension, FD, Path);
|
||||
if (EC) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating run script: " << "Failed copying IR input files"
|
||||
<< " " << EC.message();
|
||||
return;
|
||||
}
|
||||
|
||||
EC = llvm::sys::fs::copy_file(Input, FD);
|
||||
if (EC) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg)
|
||||
<< "Error generating run script: " << "Failed copying IR input files"
|
||||
<< " " << EC.message();
|
||||
return;
|
||||
}
|
||||
|
||||
TempFiles.push_back(std::string(Path.begin(), Path.end()));
|
||||
}
|
||||
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg;
|
||||
|
||||
SmallString<128> VFS;
|
||||
SmallString<128> ReproCrashFilename;
|
||||
for (const char *TempFile : TempFiles) {
|
||||
for (std::string &TempFile : TempFiles) {
|
||||
Diag(clang::diag::note_drv_command_failed_diag_msg) << TempFile;
|
||||
if (Report)
|
||||
Report->TemporaryFiles.push_back(TempFile);
|
||||
|
|
@ -2151,7 +2194,7 @@ void Driver::generateCompilationDiagnostics(
|
|||
}
|
||||
|
||||
for (const char *TempFile : SavedTemps)
|
||||
C.addTempFile(TempFile);
|
||||
TempFiles.push_back(TempFile);
|
||||
|
||||
// Assume associated files are based off of the first temporary file.
|
||||
CrashReportInfo CrashInfo(TempFiles[0], VFS);
|
||||
|
|
|
|||
15
clang/test/Driver/crash-ir-repro.cpp
Normal file
15
clang/test/Driver/crash-ir-repro.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// RUN: %clang -S -emit-llvm -o %t.ll %s
|
||||
// RUN: not %clang -S -DCRASH %s %t.ll 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: Preprocessed source(s) and associated run script(s) are located at:
|
||||
// CHECK-NEXT: clang: note: diagnostic msg: {{.*}}.cpp
|
||||
// CHECK-NEXT: clang: note: diagnostic msg: {{.*}}.ll
|
||||
// CHECK-NEXT: clang: note: diagnostic msg: {{.*}}.sh
|
||||
|
||||
#ifdef CRASH
|
||||
#pragma clang __debug parser_crash
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue