Skip to content

Commit f77ca2e

Browse files
committed
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.
1 parent d682049 commit f77ca2e

File tree

7 files changed

+60
-5
lines changed

7 files changed

+60
-5
lines changed

include/swift/Frontend/FrontendOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ class FrontendOptions {
333333
/// skip nodes entirely, depending on the errors involved.
334334
bool AllowModuleWithCompilerErrors = false;
335335

336+
/// Downgrade all errors emitted in the module interface verification phase
337+
/// to warnings.
338+
/// TODO: remove this after we fix all project-side warnings in the interface.
339+
bool DowngradeInterfaceVerificationError = false;
340+
336341
/// True if the "-static" option is set.
337342
bool Static = false;
338343

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,14 @@ struct ModuleInterfaceLoaderOptions {
299299
bool disableInterfaceLock = false;
300300
bool disableImplicitSwiftModule = false;
301301
bool disableBuildingInterface = false;
302+
bool downgradeInterfaceVerificationError = false;
302303
std::string mainExecutablePath;
303304
ModuleInterfaceLoaderOptions(const FrontendOptions &Opts):
304305
remarkOnRebuildFromInterface(Opts.RemarkOnRebuildFromModuleInterface),
305306
disableInterfaceLock(Opts.DisableInterfaceFileLock),
306307
disableImplicitSwiftModule(Opts.DisableImplicitModules),
307308
disableBuildingInterface(Opts.DisableBuildingInterface),
309+
downgradeInterfaceVerificationError(Opts.DowngradeInterfaceVerificationError),
308310
mainExecutablePath(Opts.MainExecutablePath)
309311
{
310312
switch (Opts.RequestedAction) {

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,9 @@ def warn_long_expression_type_checking_EQ : Joined<["-"], "warn-long-expression-
562562
def Rmodule_interface_rebuild : Flag<["-"], "Rmodule-interface-rebuild">,
563563
HelpText<"Emits a remark if an imported module needs to be re-compiled from its module interface">;
564564

565+
def downgrade_typecheck_interface_error : Flag<["-"], "downgrade-typecheck-interface-error">,
566+
HelpText<"Downgrade error to warning when typechecking emitted module interfaces">;
567+
565568
def enable_volatile_modules : Flag<["-"], "enable-volatile-modules">,
566569
HelpText<"Load Swift modules in memory">;
567570

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ bool ArgsToFrontendOptionsConverter::convert(
141141
Opts.RemarkOnRebuildFromModuleInterface |=
142142
Args.hasArg(OPT_Rmodule_interface_rebuild);
143143

144+
Opts.DowngradeInterfaceVerificationError |=
145+
Args.hasArg(OPT_downgrade_typecheck_interface_error);
144146
computePrintStatsOptions();
145147
computeDebugTimeOptions();
146148
computeTBDOptions();

lib/Frontend/ModuleInterfaceBuilder.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/Support/Regex.h"
3737
#include "llvm/Support/StringSaver.h"
3838
#include "llvm/Support/LockFileManager.h"
39+
#include "llvm/ADT/STLExtras.h"
3940

4041
using namespace swift;
4142
using FileDependency = SerializationOptions::FileDependency;
@@ -152,6 +153,32 @@ bool ModuleInterfaceBuilder::collectDepsForSerialization(
152153
return false;
153154
}
154155

156+
struct ErrorDowngradeConsumerRAII: DiagnosticConsumer {
157+
DiagnosticEngine &Diag;
158+
std::vector<DiagnosticConsumer *> allConsumers;
159+
bool SeenError;
160+
ErrorDowngradeConsumerRAII(DiagnosticEngine &Diag): Diag(Diag),
161+
allConsumers(Diag.takeConsumers()), SeenError(false) {
162+
Diag.addConsumer(*this);
163+
}
164+
~ErrorDowngradeConsumerRAII() {
165+
for (auto *consumer: allConsumers) {
166+
Diag.addConsumer(*consumer);
167+
}
168+
Diag.removeConsumer(*this);
169+
}
170+
void handleDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override {
171+
DiagnosticInfo localInfo(Info);
172+
if (localInfo.Kind == DiagnosticKind::Error) {
173+
localInfo.Kind = DiagnosticKind::Warning;
174+
SeenError = true;
175+
for (auto *consumer: allConsumers) {
176+
consumer->handleDiagnostic(SM, localInfo);
177+
}
178+
}
179+
}
180+
};
181+
155182
bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
156183
StringRef OutPath, bool ShouldSerializeDeps,
157184
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
@@ -204,6 +231,12 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
204231
LLVM_DEBUG(llvm::dbgs() << "Setting up instance to compile "
205232
<< InPath << " to " << OutPath << "\n");
206233

234+
LLVM_DEBUG(llvm::dbgs() << "Performing sema\n");
235+
if (isTypeChecking && FEOpts.DowngradeInterfaceVerificationError) {
236+
ErrorDowngradeConsumerRAII R(SubInstance.getDiags());
237+
SubInstance.performSema();
238+
return std::error_code();
239+
}
207240
SWIFT_DEFER {
208241
// Make sure to emit a generic top-level error if a module fails to
209242
// load. This is not only good for users; it also makes sure that we've
@@ -225,12 +258,14 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
225258
}
226259
};
227260

228-
LLVM_DEBUG(llvm::dbgs() << "Performing sema\n");
229261
SubInstance.performSema();
230262
if (SubInstance.getASTContext().hadError()) {
231263
LLVM_DEBUG(llvm::dbgs() << "encountered errors\n");
232264
return std::make_error_code(std::errc::not_supported);
233265
}
266+
// If we are just type-checking the interface, we are done.
267+
if (isTypeChecking)
268+
return std::error_code();
234269

235270
SILOptions &SILOpts = subInvocation.getSILOptions();
236271
auto Mod = SubInstance.getMainModule();
@@ -268,9 +303,6 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
268303
SerializationOpts.IsOSSA = SILOpts.EnableOSSAModules;
269304

270305
SILMod->setSerializeSILAction([&]() {
271-
if (isTypeChecking)
272-
return;
273-
274306
// We don't want to serialize module docs in the cache -- they
275307
// will be serialized beside the interface file.
276308
serializeToBuffers(Mod, SerializationOpts, ModuleBuffer,

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1497,7 +1497,9 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl(
14971497
if (LoaderOpts.remarkOnRebuildFromInterface) {
14981498
GenericArgs.push_back("-Rmodule-interface-rebuild");
14991499
}
1500-
1500+
// This flag only matters when we are verifying an textual interface.
1501+
frontendOpts.DowngradeInterfaceVerificationError =
1502+
LoaderOpts.downgradeInterfaceVerificationError;
15011503
// Note that we don't assume cachePath is the same as the Clang
15021504
// module cache path at this point.
15031505
if (buildModuleCacheDirIfAbsent && !moduleCachePath.empty())
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: echo "// swift-interface-format-version: 1.0" > %t/Main.swiftinterface
3+
// RUN: echo "// swift-module-flags: -module-name Foo" >> %t/Main.swiftinterface
4+
// RUN: echo "malfunctioned" >> %t/Main.swiftinterface
5+
// RUN: %target-swift-frontend -typecheck-module-from-interface %t/Main.swiftinterface -module-name Foo -downgrade-typecheck-interface-error &> %t/results.txt
6+
// RUN: %FileCheck --input-file %t/results.txt %s
7+
8+
// CHECK: warning:
9+
// CHECK-NOT: error:

0 commit comments

Comments
 (0)