Skip to content

Commit 285cea4

Browse files
authored
Merge pull request #37512 from ahoppen/pr/allow-driver-errors
[SourceKit] Recover if compiler arguments have errors
2 parents f03ef8f + 44f8e19 commit 285cea4

File tree

11 files changed

+66
-21
lines changed

11 files changed

+66
-21
lines changed

include/swift/Driver/Driver.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,17 @@ class Driver {
262262
/// Construct a compilation object for a given ToolChain and command line
263263
/// argument vector.
264264
///
265+
/// If \p AllowErrors is set to \c true, this method tries to build a
266+
/// compilation even if there were errors.
267+
///
265268
/// \return A Compilation, or nullptr if none was built for the given argument
266269
/// vector. A null return value does not necessarily indicate an error
267270
/// condition; the diagnostics should be queried to determine if an error
268271
/// occurred.
269272
std::unique_ptr<Compilation>
270273
buildCompilation(const ToolChain &TC,
271-
std::unique_ptr<llvm::opt::InputArgList> ArgList);
274+
std::unique_ptr<llvm::opt::InputArgList> ArgList,
275+
bool AllowErrors = false);
272276

273277
/// Parse the given list of strings into an InputArgList.
274278
std::unique_ptr<llvm::opt::InputArgList>

lib/Driver/Driver.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,8 @@ getDriverBatchSizeLimit(llvm::opt::InputArgList &ArgList,
860860

861861
std::unique_ptr<Compilation>
862862
Driver::buildCompilation(const ToolChain &TC,
863-
std::unique_ptr<llvm::opt::InputArgList> ArgList) {
863+
std::unique_ptr<llvm::opt::InputArgList> ArgList,
864+
bool AllowErrors) {
864865
llvm::PrettyStackTraceString CrashInfo("Compilation construction");
865866

866867
llvm::sys::TimePoint<> StartTime = std::chrono::system_clock::now();
@@ -880,7 +881,7 @@ Driver::buildCompilation(const ToolChain &TC,
880881
// Perform toolchain specific args validation.
881882
TC.validateArguments(Diags, *TranslatedArgList, DefaultTargetTriple);
882883

883-
if (Diags.hadAnyError())
884+
if (Diags.hadAnyError() && !AllowErrors)
884885
return nullptr;
885886

886887
if (!handleImmediateArgs(*TranslatedArgList, TC)) {
@@ -891,7 +892,7 @@ Driver::buildCompilation(const ToolChain &TC,
891892
InputFileList Inputs;
892893
buildInputs(TC, *TranslatedArgList, Inputs);
893894

894-
if (Diags.hadAnyError())
895+
if (Diags.hadAnyError() && !AllowErrors)
895896
return nullptr;
896897

897898
// Determine the OutputInfo for the driver.
@@ -900,14 +901,14 @@ Driver::buildCompilation(const ToolChain &TC,
900901
OI.CompilerMode = computeCompilerMode(*TranslatedArgList, Inputs, BatchMode);
901902
buildOutputInfo(TC, *TranslatedArgList, BatchMode, Inputs, OI);
902903

903-
if (Diags.hadAnyError())
904+
if (Diags.hadAnyError() && !AllowErrors)
904905
return nullptr;
905906

906907
assert(OI.CompilerOutputType != file_types::ID::TY_INVALID &&
907908
"buildOutputInfo() must set a valid output type!");
908909

909910
TC.validateOutputInfo(Diags, OI);
910-
if (Diags.hadAnyError())
911+
if (Diags.hadAnyError() && !AllowErrors)
911912
return nullptr;
912913

913914
validateEmbedBitcode(*TranslatedArgList, OI, Diags);
@@ -919,15 +920,17 @@ Driver::buildCompilation(const ToolChain &TC,
919920
Optional<OutputFileMap> OFM = buildOutputFileMap(
920921
*TranslatedArgList, workingDirectory);
921922

922-
if (Diags.hadAnyError())
923+
if (Diags.hadAnyError() && !AllowErrors)
923924
return nullptr;
924925

925926
if (ArgList->hasArg(options::OPT_driver_print_output_file_map)) {
926927
if (OFM)
927928
OFM->dump(llvm::errs(), true);
928929
else
929930
Diags.diagnose(SourceLoc(), diag::error_no_output_file_map_specified);
930-
return nullptr;
931+
if (!AllowErrors) {
932+
return nullptr;
933+
}
931934
}
932935

933936
const bool ShowIncrementalBuildDecisions =
@@ -1044,7 +1047,7 @@ Driver::buildCompilation(const ToolChain &TC,
10441047
buildActions(TopLevelActions, TC, OI,
10451048
whyIgnoreIncrementallity.empty() ? &outOfDateMap : nullptr, *C);
10461049

1047-
if (Diags.hadAnyError())
1050+
if (Diags.hadAnyError() && !AllowErrors)
10481051
return nullptr;
10491052

10501053
if (DriverPrintActions) {
@@ -1076,7 +1079,7 @@ Driver::buildCompilation(const ToolChain &TC,
10761079
if (!whyIgnoreIncrementallity.empty())
10771080
C->disableIncrementalBuild(whyIgnoreIncrementallity);
10781081

1079-
if (Diags.hadAnyError())
1082+
if (Diags.hadAnyError() && !AllowErrors)
10801083
return nullptr;
10811084

10821085
if (DriverPrintBindings)

lib/Driver/FrontendUtil.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ bool swift::driver::getSingleFrontendInvocationFromDriverArguments(
101101
return true;
102102

103103
std::unique_ptr<Compilation> C =
104-
TheDriver.buildCompilation(*TC, std::move(ArgList));
104+
TheDriver.buildCompilation(*TC, std::move(ArgList), /*AllowErrors=*/true);
105105
if (!C || C->getJobs().empty())
106106
return true; // Don't emit an error; one should already have been emitted
107107

@@ -113,7 +113,6 @@ bool swift::driver::getSingleFrontendInvocationFromDriverArguments(
113113
if (CompileCommands.size() != 1) {
114114
// TODO: include Jobs in the diagnostic.
115115
Diags.diagnose(SourceLoc(), diag::error_expected_one_frontend_job);
116-
return true;
117116
}
118117

119118
const Job *Cmd = *CompileCommands.begin();

lib/IDE/Utils.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,30 +294,38 @@ bool ide::initCompilerInvocation(
294294
StreamDiagConsumer DiagConsumer(ErrOS);
295295
Diags.addConsumer(DiagConsumer);
296296

297-
bool HadError = driver::getSingleFrontendInvocationFromDriverArguments(
298-
Args, Diags, [&](ArrayRef<const char *> FrontendArgs) {
299-
return Invocation.parseArgs(FrontendArgs, Diags);
300-
}, /*ForceNoOutputs=*/true);
297+
bool InvocationCreationFailed =
298+
driver::getSingleFrontendInvocationFromDriverArguments(
299+
Args, Diags,
300+
[&](ArrayRef<const char *> FrontendArgs) {
301+
return Invocation.parseArgs(FrontendArgs, Diags);
302+
},
303+
/*ForceNoOutputs=*/true);
301304

302305
// Remove the StreamDiagConsumer as it's no longer needed.
303306
Diags.removeConsumer(DiagConsumer);
304307

305-
if (HadError) {
306-
Error = std::string(ErrOS.str());
308+
Error = std::string(ErrOS.str());
309+
if (InvocationCreationFailed) {
307310
return true;
308311
}
309312

313+
std::string SymlinkResolveError;
310314
Invocation.getFrontendOptions().InputsAndOutputs =
311315
resolveSymbolicLinksInInputs(
312316
Invocation.getFrontendOptions().InputsAndOutputs,
313-
UnresolvedPrimaryFile, FileSystem, Error);
317+
UnresolvedPrimaryFile, FileSystem, SymlinkResolveError);
314318

315319
// SourceKit functionalities want to proceed even if there are missing inputs.
316320
Invocation.getFrontendOptions().InputsAndOutputs
317321
.setShouldRecoverMissingInputs();
318322

319-
if (!Error.empty())
323+
if (!SymlinkResolveError.empty()) {
324+
// resolveSymbolicLinksInInputs fails if the unresolved primary file is not
325+
// in the input files. We can't recover from that.
326+
Error += SymlinkResolveError;
320327
return true;
328+
}
321329

322330
ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions();
323331
ImporterOpts.DetailedPreprocessingRecord = true;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Foo {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Bar {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// A module should fail to be generated if the same filename is used twice and '-experimental-allow-module-with-compiler-errors' is not passed
4+
5+
// RUN: not %target-swift-frontend -emit-module -o %t/no_allow_compiler_errors.swiftmodule %S/Inputs/same_filename/A/File.swift %S/Inputs/same_filename/B/File.swift
6+
// RUN: not ls %t/no_allow_compiler_errors.swiftmodule
7+
8+
// If '-experimental-allow-module-with-compiler-errors' is passed, we should throw an error but still generate a module
9+
10+
// RUN: %target-swift-frontend -emit-module -experimental-allow-module-with-compiler-errors -o %t/allow_compiler_errors.swiftmodule %S/Inputs/same_filename/A/File.swift %S/Inputs/same_filename/B/File.swift 2>&1 | %FileCheck %s
11+
// RUN: ls %t/allow_compiler_errors.swiftmodule
12+
13+
// CHECK: filename "File.swift" used twice:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Foo {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Bar {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// We should not fail if two distinct file have the same name - this is only an issue in CodeGen
2+
// RUN: %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift -- %S/Inputs/invalid_compiler_args/A/File.swift %S/Inputs/invalid_compiler_args/B/File.swift | %FileCheck %s
3+
4+
// We can't do anything if the requested file is not in the compiler arguments
5+
// RUN: not %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift --
6+
// RUN: not %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift -- %S/Inputs/invalid_compiler_args/B/File.swift
7+
8+
// Specifying a file twice should just ignore one of them
9+
// RUN: %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift -- %S/Inputs/invalid_compiler_args/A/File.swift %S/Inputs/invalid_compiler_args/A/File.swift
10+
11+
12+
// CHECK: source.lang.swift.decl.class

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,8 +1788,10 @@ void SwiftLangSupport::getCursorInfo(
17881788
std::string Error;
17891789
SwiftInvocationRef Invok =
17901790
ASTMgr->getInvocation(Args, InputFile, fileSystem, Error);
1791+
if (!Error.empty()) {
1792+
LOG_WARN_FUNC("error creating ASTInvocation: " << Error);
1793+
}
17911794
if (!Invok) {
1792-
LOG_WARN_FUNC("failed to create an ASTInvocation: " << Error);
17931795
Receiver(RequestResult<CursorInfoData>::fromError(Error));
17941796
return;
17951797
}

0 commit comments

Comments
 (0)