Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 71 additions & 33 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -103,6 +104,7 @@
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <utility>
#if LLVM_ON_UNIX
#include <unistd.h> // getpid
Expand Down Expand Up @@ -2041,12 +2043,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)
Expand All @@ -2063,7 +2070,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.";
Expand All @@ -2086,46 +2093,77 @@ 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);

// 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;
}

// 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;
}
}

const ArgStringList &TempFiles = C.getTempFiles();
if (TempFiles.empty()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s).";
return;
// Copying filenames due to ownership.
const ArgStringList &Files = C.getTempFiles();
SmallVector<std::string> TempFiles(Files.begin(), Files.end());

// 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;

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;
}
llvm::sys::fs::copy_file(Input, FD);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to check the error code of copy_file?


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);
Expand All @@ -2142,7 +2180,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);
Expand Down
15 changes: 15 additions & 0 deletions clang/test/Driver/crash-ir-repro.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %clang -S -emit-llvm -o %t.ll %s
// RUN: not %clang -DCRASH %s %t.ll 2>&1 | FileCheck %s
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this regression test will break in some situations; it assumes that invoking "clang" can actually link a program, which isn't the case for less common build configs. Can we trigger this without trying to link a program?


// 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;
}