Skip to content

Commit e4ddee4

Browse files
committed
Don't crash if a -filelist file doesn't exist or doesn't contain the primary file.
I know this is the frontend and not the driver, but c'mon.
1 parent 2931c21 commit e4ddee4

File tree

3 files changed

+47
-21
lines changed

3 files changed

+47
-21
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ ERROR(error_implicit_output_file_is_directory,none,
128128
"the implicit output file '%0' is a directory; explicitly specify a filename "
129129
"using -o", (StringRef))
130130

131+
ERROR(error_primary_file_not_found,none,
132+
"primary file '%0' was not found in file list '%1'",
133+
(StringRef, StringRef))
134+
131135
ERROR(repl_must_be_initialized,none,
132136
"variables currently must have an initial value when entered at the "
133137
"top level of the REPL", ())

lib/Frontend/CompilerInvocation.cpp

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -112,32 +112,46 @@ static void debugFailWithCrash() {
112112
LLVM_BUILTIN_TRAP;
113113
}
114114

115-
static unsigned readFileList(std::vector<std::string> &inputFiles,
116-
const llvm::opt::Arg *filelistPath,
117-
const llvm::opt::Arg *primaryFileArg = nullptr) {
118-
bool foundPrimaryFile = false;
119-
unsigned primaryFileIndex = 0;
120-
StringRef primaryFile;
121-
if (primaryFileArg)
122-
primaryFile = primaryFileArg->getValue();
115+
/// Try to read a file list file.
116+
///
117+
/// Returns false on error.
118+
static bool readFileList(DiagnosticEngine &diags,
119+
std::vector<std::string> &inputFiles,
120+
const llvm::opt::Arg *filelistPath,
121+
const llvm::opt::Arg *primaryFileArg = nullptr,
122+
unsigned *primaryFileIndex = nullptr) {
123+
assert((primaryFileArg == nullptr) || (primaryFileIndex != nullptr) &&
124+
"did not provide argument for primary file index");
123125

124126
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
125127
llvm::MemoryBuffer::getFile(filelistPath->getValue());
126-
assert(buffer && "can't read filelist; unrecoverable");
128+
if (!buffer) {
129+
diags.diagnose(SourceLoc(), diag::cannot_open_file,
130+
filelistPath->getValue(), buffer.getError().message());
131+
return false;
132+
}
133+
134+
bool foundPrimaryFile = false;
135+
if (primaryFileIndex) *primaryFileIndex = 0;
127136

128137
for (StringRef line : make_range(llvm::line_iterator(*buffer.get()), {})) {
129138
inputFiles.push_back(line);
130-
if (foundPrimaryFile)
139+
140+
if (foundPrimaryFile || primaryFileArg == nullptr)
131141
continue;
132-
if (line == primaryFile)
142+
if (line == primaryFileArg->getValue())
133143
foundPrimaryFile = true;
134144
else
135-
++primaryFileIndex;
145+
++*primaryFileIndex;
136146
}
137147

138-
if (primaryFileArg)
139-
assert(foundPrimaryFile && "primary file not found in filelist");
140-
return primaryFileIndex;
148+
if (primaryFileArg && !foundPrimaryFile) {
149+
diags.diagnose(SourceLoc(), diag::error_primary_file_not_found,
150+
primaryFileArg->getValue(), filelistPath->getValue());
151+
return false;
152+
}
153+
154+
return true;
141155
}
142156

143157
static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
@@ -199,11 +213,13 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
199213

200214
if (const Arg *A = Args.getLastArg(OPT_filelist)) {
201215
const Arg *primaryFileArg = Args.getLastArg(OPT_primary_file);
202-
auto primaryFileIndex = readFileList(Opts.InputFilenames, A,
203-
primaryFileArg);
204-
if (primaryFileArg)
205-
Opts.PrimaryInput = SelectedInput(primaryFileIndex);
206-
assert(!Args.hasArg(OPT_INPUT) && "mixing -filelist with inputs");
216+
unsigned primaryFileIndex = 0;
217+
if (readFileList(Diags, Opts.InputFilenames, A,
218+
primaryFileArg, &primaryFileIndex)) {
219+
if (primaryFileArg)
220+
Opts.PrimaryInput = SelectedInput(primaryFileIndex);
221+
assert(!Args.hasArg(OPT_INPUT) && "mixing -filelist with inputs");
222+
}
207223
} else {
208224
for (const Arg *A : make_range(Args.filtered_begin(OPT_INPUT,
209225
OPT_primary_file),
@@ -355,7 +371,7 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
355371
Opts.InputKind = InputFileKind::IFK_Swift;
356372

357373
if (const Arg *A = Args.getLastArg(OPT_output_filelist)) {
358-
readFileList(Opts.OutputFilenames, A);
374+
readFileList(Diags, Opts.OutputFilenames, A);
359375
assert(!Args.hasArg(OPT_o) && "don't use -o with -output-filelist");
360376
} else {
361377
Opts.OutputFilenames = Args.getAllArgValues(OPT_o);

test/Frontend/filelist.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
// RUN: not %target-swift-frontend -parse -filelist %t/input.txt -primary-file %s 2>&1 | FileCheck %s
66
// RUN: not %target-swift-frontend -parse -filelist %t/input.txt 2>&1 | FileCheck %s
77

8+
// RUN: not %target-swift-frontend -emit-bc -filelist %t/nonexistent-input.txt 2>&1 | FileCheck -check-prefix=CHECK-BADFILE %s
9+
// CHECK-BADFILE: error: cannot open file
10+
11+
// RUN: not %target-swift-frontend -emit-bc -filelist %t/input.txt -primary-file nonexistent.swift 2>&1 | FileCheck -check-prefix=CHECK-BADPRIMARYFILE %s
12+
// CHECK-BADPRIMARYFILE: error: primary file 'nonexistent.swift' was not found in file list
13+
814
// RUN: echo '%t/filelist-other.bc' >> %t/output.txt
915
// RUN: echo '%t/filelist.bc' >> %t/output.txt
1016
// RUN: echo '%t/filelist-other.bc' >> %t/output.txt

0 commit comments

Comments
 (0)