Frontend: add a flag to downgrade all module interface verification errors to warnings

Ideally, module interface verification should fail the build when fatal error occurs when
type checking emitted module interfaces. However, we found it's hard to stage this phase in
because the ideal case requires all Swift adopters to have valid interfaces. This new front-end flag allows
driver to downgrade all interface verification errors to warnings as an intermediate step.
This commit is contained in:
Xi Ge
2021-11-09 15:08:17 -08:00
parent d682049d25
commit f77ca2e2ae
7 changed files with 60 additions and 5 deletions

View File

@@ -333,6 +333,11 @@ public:
/// skip nodes entirely, depending on the errors involved.
bool AllowModuleWithCompilerErrors = false;
/// Downgrade all errors emitted in the module interface verification phase
/// to warnings.
/// TODO: remove this after we fix all project-side warnings in the interface.
bool DowngradeInterfaceVerificationError = false;
/// True if the "-static" option is set.
bool Static = false;

View File

@@ -299,12 +299,14 @@ struct ModuleInterfaceLoaderOptions {
bool disableInterfaceLock = false;
bool disableImplicitSwiftModule = false;
bool disableBuildingInterface = false;
bool downgradeInterfaceVerificationError = false;
std::string mainExecutablePath;
ModuleInterfaceLoaderOptions(const FrontendOptions &Opts):
remarkOnRebuildFromInterface(Opts.RemarkOnRebuildFromModuleInterface),
disableInterfaceLock(Opts.DisableInterfaceFileLock),
disableImplicitSwiftModule(Opts.DisableImplicitModules),
disableBuildingInterface(Opts.DisableBuildingInterface),
downgradeInterfaceVerificationError(Opts.DowngradeInterfaceVerificationError),
mainExecutablePath(Opts.MainExecutablePath)
{
switch (Opts.RequestedAction) {

View File

@@ -562,6 +562,9 @@ def warn_long_expression_type_checking_EQ : Joined<["-"], "warn-long-expression-
def Rmodule_interface_rebuild : Flag<["-"], "Rmodule-interface-rebuild">,
HelpText<"Emits a remark if an imported module needs to be re-compiled from its module interface">;
def downgrade_typecheck_interface_error : Flag<["-"], "downgrade-typecheck-interface-error">,
HelpText<"Downgrade error to warning when typechecking emitted module interfaces">;
def enable_volatile_modules : Flag<["-"], "enable-volatile-modules">,
HelpText<"Load Swift modules in memory">;

View File

@@ -141,6 +141,8 @@ bool ArgsToFrontendOptionsConverter::convert(
Opts.RemarkOnRebuildFromModuleInterface |=
Args.hasArg(OPT_Rmodule_interface_rebuild);
Opts.DowngradeInterfaceVerificationError |=
Args.hasArg(OPT_downgrade_typecheck_interface_error);
computePrintStatsOptions();
computeDebugTimeOptions();
computeTBDOptions();

View File

@@ -36,6 +36,7 @@
#include "llvm/Support/Regex.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/ADT/STLExtras.h"
using namespace swift;
using FileDependency = SerializationOptions::FileDependency;
@@ -152,6 +153,32 @@ bool ModuleInterfaceBuilder::collectDepsForSerialization(
return false;
}
struct ErrorDowngradeConsumerRAII: DiagnosticConsumer {
DiagnosticEngine &Diag;
std::vector<DiagnosticConsumer *> allConsumers;
bool SeenError;
ErrorDowngradeConsumerRAII(DiagnosticEngine &Diag): Diag(Diag),
allConsumers(Diag.takeConsumers()), SeenError(false) {
Diag.addConsumer(*this);
}
~ErrorDowngradeConsumerRAII() {
for (auto *consumer: allConsumers) {
Diag.addConsumer(*consumer);
}
Diag.removeConsumer(*this);
}
void handleDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override {
DiagnosticInfo localInfo(Info);
if (localInfo.Kind == DiagnosticKind::Error) {
localInfo.Kind = DiagnosticKind::Warning;
SeenError = true;
for (auto *consumer: allConsumers) {
consumer->handleDiagnostic(SM, localInfo);
}
}
}
};
bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
StringRef OutPath, bool ShouldSerializeDeps,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
@@ -204,6 +231,12 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
LLVM_DEBUG(llvm::dbgs() << "Setting up instance to compile "
<< InPath << " to " << OutPath << "\n");
LLVM_DEBUG(llvm::dbgs() << "Performing sema\n");
if (isTypeChecking && FEOpts.DowngradeInterfaceVerificationError) {
ErrorDowngradeConsumerRAII R(SubInstance.getDiags());
SubInstance.performSema();
return std::error_code();
}
SWIFT_DEFER {
// Make sure to emit a generic top-level error if a module fails to
// load. This is not only good for users; it also makes sure that we've
@@ -225,12 +258,14 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
}
};
LLVM_DEBUG(llvm::dbgs() << "Performing sema\n");
SubInstance.performSema();
if (SubInstance.getASTContext().hadError()) {
LLVM_DEBUG(llvm::dbgs() << "encountered errors\n");
return std::make_error_code(std::errc::not_supported);
}
// If we are just type-checking the interface, we are done.
if (isTypeChecking)
return std::error_code();
SILOptions &SILOpts = subInvocation.getSILOptions();
auto Mod = SubInstance.getMainModule();
@@ -268,9 +303,6 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
SerializationOpts.IsOSSA = SILOpts.EnableOSSAModules;
SILMod->setSerializeSILAction([&]() {
if (isTypeChecking)
return;
// We don't want to serialize module docs in the cache -- they
// will be serialized beside the interface file.
serializeToBuffers(Mod, SerializationOpts, ModuleBuffer,

View File

@@ -1497,7 +1497,9 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl(
if (LoaderOpts.remarkOnRebuildFromInterface) {
GenericArgs.push_back("-Rmodule-interface-rebuild");
}
// This flag only matters when we are verifying an textual interface.
frontendOpts.DowngradeInterfaceVerificationError =
LoaderOpts.downgradeInterfaceVerificationError;
// Note that we don't assume cachePath is the same as the Clang
// module cache path at this point.
if (buildModuleCacheDirIfAbsent && !moduleCachePath.empty())

View File

@@ -0,0 +1,9 @@
// RUN: %empty-directory(%t)
// RUN: echo "// swift-interface-format-version: 1.0" > %t/Main.swiftinterface
// RUN: echo "// swift-module-flags: -module-name Foo" >> %t/Main.swiftinterface
// RUN: echo "malfunctioned" >> %t/Main.swiftinterface
// RUN: %target-swift-frontend -typecheck-module-from-interface %t/Main.swiftinterface -module-name Foo -downgrade-typecheck-interface-error &> %t/results.txt
// RUN: %FileCheck --input-file %t/results.txt %s
// CHECK: warning:
// CHECK-NOT: error: