mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Serialization] Import incompatible targets when allowing errors
If allowing modules to be output with compile errors (-experimental-allow-module-with-errors), import targets regardless of whether they are compatible or not, and still output the module. The error diagnostic will still be output (preventing SILGen), but the AST will be available for various editor functionality.
This commit is contained in:
@@ -118,12 +118,14 @@ ModuleFile::ModuleFile(std::shared_ptr<const ModuleFileSharedCore> core)
|
||||
allocateBuffer(Identifiers, core->Identifiers);
|
||||
}
|
||||
|
||||
Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc) {
|
||||
Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc,
|
||||
bool recoverFromIncompatibility) {
|
||||
PrettyStackTraceModuleFile stackEntry(*this);
|
||||
|
||||
assert(!hasError() && "error already detected; should not call this");
|
||||
assert(!FileContext && "already associated with an AST module");
|
||||
FileContext = file;
|
||||
Status status = Status::Valid;
|
||||
|
||||
ModuleDecl *M = file->getParentModule();
|
||||
if (M->getName().str() != Core->Name)
|
||||
@@ -134,12 +136,14 @@ Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc) {
|
||||
llvm::Triple moduleTarget(llvm::Triple::normalize(Core->TargetTriple));
|
||||
if (!areCompatibleArchitectures(moduleTarget, ctx.LangOpts.Target) ||
|
||||
!areCompatibleOSs(moduleTarget, ctx.LangOpts.Target)) {
|
||||
return error(Status::TargetIncompatible);
|
||||
}
|
||||
if (ctx.LangOpts.EnableTargetOSChecking &&
|
||||
!M->isResilient() &&
|
||||
status = Status::TargetIncompatible;
|
||||
if (!recoverFromIncompatibility)
|
||||
return error(status);
|
||||
} else if (ctx.LangOpts.EnableTargetOSChecking && !M->isResilient() &&
|
||||
isTargetTooNew(moduleTarget, ctx.LangOpts.Target)) {
|
||||
return error(Status::TargetTooNew);
|
||||
status = Status::TargetTooNew;
|
||||
if (!recoverFromIncompatibility)
|
||||
return error(status);
|
||||
}
|
||||
|
||||
for (const auto &searchPath : Core->SearchPaths)
|
||||
@@ -240,7 +244,7 @@ Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc) {
|
||||
None);
|
||||
}
|
||||
|
||||
return Status::Valid;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool ModuleFile::mayHaveDiagnosticsPointingAtBuffer() const {
|
||||
|
||||
@@ -486,10 +486,14 @@ public:
|
||||
/// This does not include diagnostics about \e this file failing to load,
|
||||
/// but rather other things that might be imported as part of bringing the
|
||||
/// file into the AST.
|
||||
/// \param recoverFromIncompatibility Whether to associate the file
|
||||
/// regardless of the compatibility with the AST module. Still returns the
|
||||
/// underlying error for diagnostic purposes but does not set the error bit.
|
||||
///
|
||||
/// \returns any error that occurred during association, such as being
|
||||
/// compiled for a different OS.
|
||||
Status associateWithFileContext(FileUnit *file, SourceLoc diagLoc);
|
||||
Status associateWithFileContext(FileUnit *file, SourceLoc diagLoc,
|
||||
bool recoverFromIncompatibility);
|
||||
|
||||
/// Returns `true` if there is a buffer that might contain source code where
|
||||
/// other parts of the compiler could have emitted diagnostics, to indicate
|
||||
|
||||
@@ -706,13 +706,15 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
|
||||
std::move(moduleDocInputBuffer),
|
||||
std::move(moduleSourceInfoInputBuffer),
|
||||
isFramework, loadedModuleFileCore);
|
||||
SerializedASTFile *fileUnit = nullptr;
|
||||
|
||||
if (loadInfo.status == serialization::Status::Valid) {
|
||||
loadedModuleFile =
|
||||
std::make_unique<ModuleFile>(std::move(loadedModuleFileCore));
|
||||
M.setResilienceStrategy(loadedModuleFile->getResilienceStrategy());
|
||||
|
||||
// We've loaded the file. Now try to bring it into the AST.
|
||||
auto fileUnit = new (Ctx) SerializedASTFile(M, *loadedModuleFile);
|
||||
fileUnit = new (Ctx) SerializedASTFile(M, *loadedModuleFile);
|
||||
if (loadedModuleFile->isTestable())
|
||||
M.setTestingEnabled();
|
||||
if (loadedModuleFile->arePrivateImportsEnabled())
|
||||
@@ -723,8 +725,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
|
||||
M.setHasIncrementalInfo();
|
||||
|
||||
auto diagLocOrInvalid = diagLoc.getValueOr(SourceLoc());
|
||||
loadInfo.status =
|
||||
loadedModuleFile->associateWithFileContext(fileUnit, diagLocOrInvalid);
|
||||
loadInfo.status = loadedModuleFile->associateWithFileContext(
|
||||
fileUnit, diagLocOrInvalid, Ctx.LangOpts.AllowModuleWithCompilerErrors);
|
||||
|
||||
// FIXME: This seems wrong. Overlay for system Clang module doesn't
|
||||
// necessarily mean it's "system" module. User can make their own overlay
|
||||
@@ -734,31 +736,36 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
|
||||
if (shadowed->isSystemModule())
|
||||
M.setIsSystemModule(true);
|
||||
|
||||
if (loadInfo.status == serialization::Status::Valid) {
|
||||
if (loadInfo.status == serialization::Status::Valid ||
|
||||
(Ctx.LangOpts.AllowModuleWithCompilerErrors &&
|
||||
(loadInfo.status == serialization::Status::TargetTooNew ||
|
||||
loadInfo.status == serialization::Status::TargetIncompatible))) {
|
||||
Ctx.bumpGeneration();
|
||||
LoadedModuleFiles.emplace_back(std::move(loadedModuleFile),
|
||||
Ctx.getCurrentGeneration());
|
||||
findOverlayFiles(diagLoc.getValueOr(SourceLoc()), &M, fileUnit);
|
||||
return fileUnit;
|
||||
} else {
|
||||
fileUnit = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// From here on is the failure path.
|
||||
|
||||
if (loadInfo.status != serialization::Status::Valid) {
|
||||
if (diagLoc)
|
||||
serialization::diagnoseSerializedASTLoadFailure(
|
||||
Ctx, *diagLoc, loadInfo, moduleBufferID,
|
||||
moduleDocBufferID, loadedModuleFile.get(), M.getName());
|
||||
Ctx, *diagLoc, loadInfo, moduleBufferID, moduleDocBufferID,
|
||||
loadedModuleFile.get(), M.getName());
|
||||
|
||||
// Even though the module failed to load, it's possible its contents include
|
||||
// a source buffer that need to survive because it's already been used for
|
||||
// diagnostics.
|
||||
// Even though the module failed to load, it's possible its contents
|
||||
// include a source buffer that need to survive because it's already been
|
||||
// used for diagnostics.
|
||||
// Note this is only necessary in case a bridging header failed to load
|
||||
// during the `associateWithFileContext()` call.
|
||||
if (loadedModuleFile && loadedModuleFile->mayHaveDiagnosticsPointingAtBuffer())
|
||||
if (loadedModuleFile &&
|
||||
loadedModuleFile->mayHaveDiagnosticsPointingAtBuffer())
|
||||
OrphanedModuleFiles.push_back(std::move(loadedModuleFile));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return fileUnit;
|
||||
}
|
||||
|
||||
void swift::serialization::diagnoseSerializedASTLoadFailure(
|
||||
@@ -908,7 +915,8 @@ void swift::serialization::diagnoseSerializedASTLoadFailure(
|
||||
// FIXME: This doesn't handle a non-debugger REPL, which should also treat
|
||||
// this as a non-fatal error.
|
||||
auto diagKind = diag::serialization_target_incompatible;
|
||||
if (Ctx.LangOpts.DebuggerSupport)
|
||||
if (Ctx.LangOpts.DebuggerSupport ||
|
||||
Ctx.LangOpts.AllowModuleWithCompilerErrors)
|
||||
diagKind = diag::serialization_target_incompatible_repl;
|
||||
Ctx.Diags.diagnose(diagLoc, diagKind, ModuleName, loadInfo.targetTriple,
|
||||
moduleBufferID);
|
||||
@@ -926,7 +934,8 @@ void swift::serialization::diagnoseSerializedASTLoadFailure(
|
||||
// FIXME: This doesn't handle a non-debugger REPL, which should also treat
|
||||
// this as a non-fatal error.
|
||||
auto diagKind = diag::serialization_target_too_new;
|
||||
if (Ctx.LangOpts.DebuggerSupport)
|
||||
if (Ctx.LangOpts.DebuggerSupport ||
|
||||
Ctx.LangOpts.AllowModuleWithCompilerErrors)
|
||||
diagKind = diag::serialization_target_too_new_repl;
|
||||
Ctx.Diags.diagnose(diagLoc, diagKind, compilationOSInfo.first,
|
||||
compilationOSInfo.second, ModuleName,
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
// RUN: %{python} -u %S/Inputs/binary_sub.py x86_64-unknown-darwin14 x86_64-unknown-solaris8 < %t/solaris-template.swiftmodule > %t/solaris.swiftmodule
|
||||
// RUN: not %target-swift-frontend -I %t -typecheck -parse-stdlib %s -DSOLARIS 2>&1 | %FileCheck -check-prefix=CHECK-SOLARIS %s
|
||||
|
||||
// Check that we still get the diagnostic but the module is output anyway when
|
||||
// allowing errors
|
||||
// RUN: %target-swift-frontend -I %t -parse-stdlib -experimental-allow-module-with-compiler-errors -emit-module -module-name incompatmips -o %t %s -DMIPS 2>&1 | %FileCheck -check-prefix=CHECK-MIPS %s
|
||||
// RUN: ls %t/incompatmips.swiftmodule
|
||||
// RUN: %target-swift-frontend -I %t -parse-stdlib -experimental-allow-module-with-compiler-errors -emit-module -module-name incompatsol -o %t %s -DSOLARIS 2>&1 | %FileCheck -check-prefix=CHECK-SOLARIS %s
|
||||
// RUN: ls %t/incompatsol.swiftmodule
|
||||
|
||||
// These checks should still hold with -enable-library-evolution.
|
||||
|
||||
// RUN: %swift -target x86_64-unknown-darwin14 -o %t/mips-template.swiftmodule -parse-stdlib -emit-module -module-name mips %S/../Inputs/empty.swift -enable-library-evolution
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
// RUN: %target-swift-frontend -parse-stdlib -target x86_64-apple-ios50.50.1 -I %t -typecheck %s
|
||||
// RUN: %target-swift-frontend -parse-stdlib -target x86_64-apple-ios50.51 -I %t -typecheck %s
|
||||
|
||||
// Check that we still get the diagnostic but the module is output anyway when
|
||||
// allowing errors
|
||||
// RUN: %target-swift-frontend -I %t -target x86_64-apple-ios12 -parse-stdlib -experimental-allow-module-with-compiler-errors -emit-module -module-name toonewios -o %t %s 2>&1 | %FileCheck %s
|
||||
// RUN: ls %t/toonewios.swiftmodule
|
||||
|
||||
// REQUIRES: OS=ios
|
||||
|
||||
// CHECK: :[[@LINE+1]]:8: error: compiling for iOS 12.0, but module 'empty' has a minimum deployment target of iOS 50.50.1: {{.*}}empty.swiftmodule{{$}}
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.50 -I %t -typecheck %s
|
||||
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.50.1 -I %t -typecheck %s
|
||||
|
||||
// Check that we still get the diagnostic but the module is output anyway when
|
||||
// allowing errors
|
||||
// RUN: %target-swift-frontend -I %t -target %target-cpu-apple-macosx10.9 -parse-stdlib -experimental-allow-module-with-compiler-errors -emit-module -module-name toonew -o %t %s 2>&1 | %FileCheck %s
|
||||
// RUN: ls %t/toonew.swiftmodule
|
||||
// RUN: %target-swift-frontend -I %t -target %target-cpu-apple-darwin13 -parse-stdlib -experimental-allow-module-with-compiler-errors -emit-module -module-name toonewother -o %t %s 2>&1 | %FileCheck %s
|
||||
// RUN: ls %t/toonewother.swiftmodule
|
||||
|
||||
// Allow any version when built with resilience. (Really we should encode a
|
||||
// "minimum supported OS", but we don't have that information today.)
|
||||
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.50 -emit-module -parse-stdlib %S/../Inputs/empty.swift -enable-library-evolution -o %t
|
||||
|
||||
Reference in New Issue
Block a user