Skip to content

Commit ab6c15f

Browse files
committed
[Frontend] Bail early if the stdlib is missing
Rather than trying to continue the compilation with an empty main module, let's bail out early if we expect an implicit stdlib import and fail to load in the stdlib.
1 parent ae624f3 commit ab6c15f

File tree

4 files changed

+32
-26
lines changed

4 files changed

+32
-26
lines changed

include/swift/Frontend/Frontend.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -646,10 +646,11 @@ class CompilerInstance {
646646
public:
647647
void freeASTContext();
648648

649-
private:
650-
/// Load stdlib & return true if should continue, i.e. no error
651-
bool loadStdlib();
649+
/// If an implicit standard library import is expected, loads the standard
650+
/// library, returning \c false if we should continue, i.e. no error.
651+
bool loadStdlibIfNeeded();
652652

653+
private:
653654
/// Retrieve a description of which modules should be implicitly imported.
654655
ImplicitImportInfo getImplicitImportInfo() const;
655656

lib/Frontend/Frontend.cpp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -740,17 +740,6 @@ void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage,
740740
ModuleDecl *mainModule = getMainModule();
741741
Context->LoadedModules[mainModule->getName()] = mainModule;
742742

743-
// If we aren't in a parse-only context, load the standard library.
744-
if (LimitStage > SourceFile::Unprocessed &&
745-
Invocation.getImplicitStdlibKind() == ImplicitStdlibKind::Stdlib
746-
&& !loadStdlib()) {
747-
// If we failed to load the stdlib, mark the main module as having
748-
// "failed to load", as it will contain no files.
749-
// FIXME: We need to better handle a missing stdlib.
750-
mainModule->setFailedToLoad();
751-
return;
752-
}
753-
754743
// Make sure the main file is the first file in the module, so do this now.
755744
if (MainBufferID != NO_SUCH_BUFFER) {
756745
auto *mainFile = createSourceFileForMainModule(
@@ -813,23 +802,27 @@ void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage,
813802
finishTypeChecking();
814803
}
815804

816-
bool CompilerInstance::loadStdlib() {
805+
bool CompilerInstance::loadStdlibIfNeeded() {
806+
// If we aren't expecting an implicit stdlib import, there's nothing to do.
807+
if (getImplicitImportInfo().StdlibKind != ImplicitStdlibKind::Stdlib)
808+
return false;
809+
817810
FrontendStatsTracer tracer(getStatsReporter(), "load-stdlib");
818-
ModuleDecl *M = Context->getStdlibModule(true);
811+
ModuleDecl *M = Context->getStdlibModule(/*loadIfAbsent*/ true);
819812

820813
if (!M) {
821814
Diagnostics.diagnose(SourceLoc(), diag::error_stdlib_not_found,
822815
Invocation.getTargetTriple());
823-
return false;
816+
return true;
824817
}
825818

826-
// If we failed to load, we should have already diagnosed
819+
// If we failed to load, we should have already diagnosed.
827820
if (M->failedToLoad()) {
828821
assert(Diagnostics.hadAnyError() &&
829822
"Module failed to load but nothing was diagnosed?");
830-
return false;
823+
return true;
831824
}
832-
return true;
825+
return false;
833826
}
834827

835828
bool CompilerInstance::loadPartialModulesAndImplicitImports() {

lib/FrontendTool/FrontendTool.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,17 @@ static bool performCompile(CompilerInstance &Instance,
12501250
if (Invocation.getInputKind() == InputFileKind::LLVM)
12511251
return compileLLVMIR(Instance);
12521252

1253+
// If we aren't in a parse-only context and expect an implicit stdlib import,
1254+
// load in the standard library. If we either fail to find it or encounter an
1255+
// error while loading it, bail early. Continuing the compilation will at best
1256+
// trigger a bunch of other errors due to the stdlib being missing, or at
1257+
// worst crash downstream as many call sites don't currently handle a missing
1258+
// stdlib.
1259+
if (!FrontendOptions::shouldActionOnlyParse(Action)) {
1260+
if (Instance.loadStdlibIfNeeded())
1261+
return true;
1262+
}
1263+
12531264
if (FrontendOptions::shouldActionOnlyParse(Action)) {
12541265
// Disable delayed parsing of type and function bodies when we've been
12551266
// asked to dump the resulting AST.

lib/IDE/CompletionInstance.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,15 +527,16 @@ bool CompletionInstance::performNewOperation(
527527
}
528528
registerIDERequestFunctions(CI.getASTContext().evaluator);
529529

530-
CI.performParseAndResolveImportsOnly();
531-
532-
// If we didn't create a source file for completion, bail. This can happen
533-
// if for example we fail to load the stdlib.
534-
auto completionFile = CI.getCodeCompletionFile();
535-
if (!completionFile)
530+
// If we're expecting a standard library, but there either isn't one, or it
531+
// failed to load, let's bail early and hand back an empty completion
532+
// result to avoid any downstream crashes.
533+
if (CI.loadStdlibIfNeeded())
536534
return true;
537535

536+
CI.performParseAndResolveImportsOnly();
537+
538538
// If we didn't find a code completion token, bail.
539+
auto completionFile = CI.getCodeCompletionFile();
539540
auto *state = completionFile.get()->getDelayedParserState();
540541
if (!state->hasCodeCompletionDelayedDeclState())
541542
return true;

0 commit comments

Comments
 (0)