Skip to content

Commit 8fbd449

Browse files
authored
Merge pull request #33114 from brentdax/check-your-interfaces-at-the-door
Verify that just-emitted module interfaces parse and typecheck
2 parents e1d0ea2 + f824204 commit 8fbd449

23 files changed

+203
-26
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -708,12 +708,12 @@ ERROR(sema_opening_import,Fatal,
708708
ERROR(serialization_load_failed,Fatal,
709709
"failed to load module '%0'", (StringRef))
710710
ERROR(module_interface_build_failed,Fatal,
711-
"failed to build module '%0' from its module interface; "
712-
"%select{the compiler that produced it, '%2', may have used features "
713-
"that aren't supported by this compiler, '%3'"
714-
"|it may have been damaged or it may have triggered a bug in the Swift "
715-
"compiler when it was produced}1",
716-
(StringRef, bool, StringRef, StringRef))
711+
"failed to %select{build module '%1' from its module interface|verify "
712+
"module interface of '%1'}0; %select{the compiler that produced it, "
713+
"'%3', may have used features that aren't supported by this compiler, "
714+
"'%4'|it may have been damaged or it may have triggered a bug in the "
715+
"Swift compiler when it was produced}2",
716+
(bool, StringRef, bool, StringRef, StringRef))
717717
ERROR(serialization_malformed_module,Fatal,
718718
"malformed compiled module: %0", (StringRef))
719719
ERROR(serialization_module_too_new,Fatal,

include/swift/Driver/Action.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ class Action {
5151
GenerateDSYMJob,
5252
VerifyDebugInfoJob,
5353
GeneratePCHJob,
54+
VerifyModuleInterfaceJob,
5455

5556
JobFirst = CompileJob,
56-
JobLast = GeneratePCHJob
57+
JobLast = VerifyModuleInterfaceJob
5758
};
5859

5960
static const char *getClassName(Kind AC);
@@ -357,6 +358,26 @@ class StaticLinkJobAction : public JobAction {
357358
}
358359
};
359360

361+
class VerifyModuleInterfaceJobAction : public JobAction {
362+
virtual void anchor();
363+
file_types::ID inputType;
364+
365+
public:
366+
VerifyModuleInterfaceJobAction(const Action * ModuleEmitter,
367+
file_types::ID inputType)
368+
: JobAction(Action::Kind::VerifyModuleInterfaceJob, { ModuleEmitter },
369+
file_types::TY_Nothing), inputType(inputType) {
370+
assert(inputType == file_types::TY_SwiftModuleInterfaceFile ||
371+
inputType == file_types::TY_PrivateSwiftModuleInterfaceFile);
372+
}
373+
374+
file_types::ID getInputType() const { return inputType; }
375+
376+
static bool classof(const Action *A) {
377+
return A->getKind() == Action::Kind::VerifyModuleInterfaceJob;
378+
}
379+
};
380+
360381
} // end namespace driver
361382
} // end namespace swift
362383

include/swift/Driver/ToolChain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ class ToolChain {
162162
virtual InvocationInfo
163163
constructInvocation(const VerifyDebugInfoJobAction &job,
164164
const JobContext &context) const;
165+
virtual InvocationInfo
166+
constructInvocation(const VerifyModuleInterfaceJobAction &job,
167+
const JobContext &context) const;
165168
virtual InvocationInfo constructInvocation(const GeneratePCHJobAction &job,
166169
const JobContext &context) const;
167170
virtual InvocationInfo

include/swift/Frontend/FrontendOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class FrontendOptions {
116116

117117
/// Build from a swiftinterface, as close to `import` as possible
118118
CompileModuleFromInterface,
119+
/// Same as CompileModuleFromInterface, but stopping after typechecking
120+
TypecheckModuleFromInterface,
119121

120122
EmitSIBGen, ///< Emit serialized AST + raw SIL
121123
EmitSIB, ///< Emit serialized AST + canonical SIL

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ class ExplicitModuleMapParser {
285285
};
286286

287287
struct ModuleInterfaceLoaderOptions {
288+
FrontendOptions::ActionType requestedAction =
289+
FrontendOptions::ActionType::EmitModuleOnly;
288290
bool remarkOnRebuildFromInterface = false;
289291
bool disableInterfaceLock = false;
290292
bool disableImplicitSwiftModule = false;
@@ -293,7 +295,17 @@ struct ModuleInterfaceLoaderOptions {
293295
remarkOnRebuildFromInterface(Opts.RemarkOnRebuildFromModuleInterface),
294296
disableInterfaceLock(Opts.DisableInterfaceFileLock),
295297
disableImplicitSwiftModule(Opts.DisableImplicitModules),
296-
mainExecutablePath(Opts.MainExecutablePath) {}
298+
mainExecutablePath(Opts.MainExecutablePath)
299+
{
300+
switch (Opts.RequestedAction) {
301+
case FrontendOptions::ActionType::TypecheckModuleFromInterface:
302+
requestedAction = FrontendOptions::ActionType::Typecheck;
303+
break;
304+
default:
305+
requestedAction = FrontendOptions::ActionType::EmitModuleOnly;
306+
break;
307+
}
308+
}
297309
ModuleInterfaceLoaderOptions() = default;
298310
};
299311

include/swift/Frontend/ModuleInterfaceSupport.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,15 @@ struct ModuleInterfaceOptions {
4141
/// back .swiftinterface and reconstructing .swiftmodule.
4242
std::string Flags;
4343

44-
// Print SPI decls and attributes.
44+
/// Print SPI decls and attributes.
4545
bool PrintSPIs = false;
4646

4747
/// Print imports with both @_implementationOnly and @_spi, only applies
4848
/// when PrintSPIs is true.
4949
bool ExperimentalSPIImports = false;
50+
51+
/// Intentionally print invalid syntax into the file.
52+
bool DebugPrintInvalidSyntax = false;
5053
};
5154

5255
extern version::Version InterfaceFormatVersion;

include/swift/Option/FrontendOptions.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ def debug_forbid_typecheck_prefix : Separate<["-"], "debug-forbid-typecheck-pref
260260
HelpText<"Triggers llvm fatal_error if typechecker tries to typecheck a decl "
261261
"with the provided prefix name">;
262262

263+
def debug_emit_invalid_swiftinterface_syntax : Flag<["-"], "debug-emit-invalid-swiftinterface-syntax">,
264+
HelpText<"Write an invalid declaration into swiftinterface files">;
265+
263266
def debug_cycles : Flag<["-"], "debug-cycles">,
264267
HelpText<"Print out debug dumps when cycles are detected in evaluation">;
265268
def build_request_dependency_graph : Flag<["-"], "build-request-dependency-graph">,
@@ -645,6 +648,11 @@ def build_module_from_parseable_interface :
645648
Alias<compile_module_from_interface>,
646649
ModeOpt;
647650

651+
def typecheck_module_from_interface :
652+
Flag<["-"], "typecheck-module-from-interface">,
653+
HelpText<"Treat the (single) input as a swiftinterface and typecheck it">,
654+
ModeOpt;
655+
648656
def module_interface_preserve_types_as_written :
649657
Flag<["-"], "module-interface-preserve-types-as-written">,
650658
HelpText<"When emitting a module interface, preserve types as they were "

include/swift/Option/Options.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,15 @@ def emit_private_module_interface_path :
460460
DoesNotAffectIncrementalBuild, ArgumentIsPath, SupplementaryOutput]>,
461461
MetaVarName<"<path>">, HelpText<"Output private module interface file to <path>">;
462462

463+
def verify_emitted_module_interface :
464+
Flag<["-"], "verify-emitted-module-interface">,
465+
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
466+
HelpText<"Check that module interfaces emitted during compilation typecheck">;
467+
def no_verify_emitted_module_interface :
468+
Flag<["-"], "no-verify-emitted-module-interface">,
469+
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
470+
HelpText<"Don't check that module interfaces emitted during compilation typecheck">;
471+
463472
def avoid_emit_module_source_info :
464473
Flag<["-"], "avoid-emit-module-source-info">,
465474
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,

lib/Driver/Action.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const char *Action::getClassName(Kind AC) {
3333
case Kind::GenerateDSYMJob: return "generate-dSYM";
3434
case Kind::VerifyDebugInfoJob: return "verify-debug-info";
3535
case Kind::GeneratePCHJob: return "generate-pch";
36+
case Kind::VerifyModuleInterfaceJob: return "verify-module-interface";
3637
}
3738

3839
llvm_unreachable("invalid class");
@@ -65,3 +66,5 @@ void GenerateDSYMJobAction::anchor() {}
6566
void VerifyDebugInfoJobAction::anchor() {}
6667

6768
void GeneratePCHJobAction::anchor() {}
69+
70+
void VerifyModuleInterfaceJobAction::anchor() {}

lib/Driver/Driver.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,30 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
22082208
TopLevelActions.push_back(MergeModuleAction);
22092209
TopLevelActions.append(AllLinkerInputs.begin(), AllLinkerInputs.end());
22102210
}
2211+
2212+
#ifdef NDEBUG
2213+
bool verifyInterfacesByDefault = false;
2214+
#else
2215+
bool verifyInterfacesByDefault = true;
2216+
#endif
2217+
2218+
if (MergeModuleAction
2219+
&& Args.hasFlag(options::OPT_verify_emitted_module_interface,
2220+
options::OPT_no_verify_emitted_module_interface,
2221+
verifyInterfacesByDefault)) {
2222+
if (Args.hasArgNoClaim(options::OPT_emit_module_interface,
2223+
options::OPT_emit_module_interface_path)) {
2224+
TopLevelActions.push_back(
2225+
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
2226+
file_types::TY_SwiftModuleInterfaceFile));
2227+
}
2228+
2229+
if (Args.hasArgNoClaim(options::OPT_emit_private_module_interface_path)) {
2230+
TopLevelActions.push_back(
2231+
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
2232+
file_types::TY_PrivateSwiftModuleInterfaceFile));
2233+
}
2234+
}
22112235
}
22122236

22132237
bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) {

lib/Driver/ToolChain.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ std::unique_ptr<Job> ToolChain::constructJob(
111111
CASE(GeneratePCHJob)
112112
CASE(AutolinkExtractJob)
113113
CASE(REPLJob)
114+
CASE(VerifyModuleInterfaceJob)
114115
#undef CASE
115116
case Action::Kind::Input:
116117
llvm_unreachable("not a JobAction");

lib/Driver/ToolChains.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,41 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
10461046
return II;
10471047
}
10481048

1049+
ToolChain::InvocationInfo
1050+
ToolChain::constructInvocation(const VerifyModuleInterfaceJobAction &job,
1051+
const JobContext &context) const {
1052+
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
1053+
ArgStringList &Arguments = II.Arguments;
1054+
II.allowsResponseFiles = true;
1055+
1056+
for (auto &s : getDriver().getSwiftProgramArgs())
1057+
Arguments.push_back(s.c_str());
1058+
Arguments.push_back("-frontend");
1059+
1060+
Arguments.push_back("-typecheck-module-from-interface");
1061+
1062+
size_t sizeBefore = Arguments.size();
1063+
addInputsOfType(Arguments, context.Inputs, context.Args, job.getInputType());
1064+
1065+
(void)sizeBefore;
1066+
assert(Arguments.size() - sizeBefore == 1 &&
1067+
"should verify exactly one module interface per job");
1068+
1069+
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
1070+
addRuntimeLibraryFlags(context.OI, Arguments);
1071+
1072+
addOutputsOfType(Arguments, context.Output, context.Args,
1073+
file_types::TY_SerializedDiagnostics,
1074+
"-serialize-diagnostics-path");
1075+
1076+
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
1077+
1078+
Arguments.push_back("-module-name");
1079+
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
1080+
1081+
return II;
1082+
}
1083+
10491084
ToolChain::InvocationInfo
10501085
ToolChain::constructInvocation(const ModuleWrapJobAction &job,
10511086
const JobContext &context) const {

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ bool ArgsToFrontendOptionsConverter::convert(
147147
Opts.RequestedAction = determineRequestedAction(Args);
148148
}
149149

150-
if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface) {
150+
if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface ||
151+
Opts.RequestedAction == FrontendOptions::ActionType::TypecheckModuleFromInterface) {
151152
// The situations where we use this action, e.g. explicit module building and
152153
// generating prebuilt module cache, don't need synchronization. We should avoid
153154
// using lock files for them.
@@ -391,6 +392,8 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) {
391392
return FrontendOptions::ActionType::Immediate;
392393
if (Opt.matches(OPT_compile_module_from_interface))
393394
return FrontendOptions::ActionType::CompileModuleFromInterface;
395+
if (Opt.matches(OPT_typecheck_module_from_interface))
396+
return FrontendOptions::ActionType::TypecheckModuleFromInterface;
394397

395398
llvm_unreachable("Unhandled mode option");
396399
}

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
325325
Args.hasArg(OPT_experimental_print_full_convention);
326326
Opts.ExperimentalSPIImports |=
327327
Args.hasArg(OPT_experimental_spi_imports);
328+
Opts.DebugPrintInvalidSyntax |=
329+
Args.hasArg(OPT_debug_emit_invalid_swiftinterface_syntax);
328330
}
329331

330332
/// Save a copy of any flags marked as ModuleInterfaceOption, if running

lib/Frontend/Frontend.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,9 @@ void CompilerInstance::recordPrimaryInputBuffer(unsigned BufID) {
192192

193193
bool CompilerInstance::setUpASTContextIfNeeded() {
194194
if (Invocation.getFrontendOptions().RequestedAction ==
195-
FrontendOptions::ActionType::CompileModuleFromInterface) {
195+
FrontendOptions::ActionType::CompileModuleFromInterface ||
196+
Invocation.getFrontendOptions().RequestedAction ==
197+
FrontendOptions::ActionType::TypecheckModuleFromInterface) {
196198
// Compiling a module interface from source uses its own CompilerInstance
197199
// with options read from the input file. Don't bother setting up an
198200
// ASTContext at this level.

lib/Frontend/FrontendOptions.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) {
5151
case ActionType::EmitModuleOnly:
5252
case ActionType::MergeModules:
5353
case ActionType::CompileModuleFromInterface:
54+
case ActionType::TypecheckModuleFromInterface:
5455
return true;
5556
case ActionType::Immediate:
5657
case ActionType::REPL:
@@ -120,6 +121,7 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) {
120121
case ActionType::Parse:
121122
case ActionType::ResolveImports:
122123
case ActionType::Typecheck:
124+
case ActionType::TypecheckModuleFromInterface:
123125
case ActionType::DumpParse:
124126
case ActionType::DumpInterfaceHash:
125127
case ActionType::DumpAST:
@@ -195,6 +197,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) {
195197
case ActionType::DumpTypeRefinementContexts:
196198
case ActionType::DumpTypeInfo:
197199
case ActionType::CompileModuleFromInterface:
200+
case ActionType::TypecheckModuleFromInterface:
198201
case ActionType::Immediate:
199202
case ActionType::REPL:
200203
case ActionType::DumpPCM:
@@ -236,6 +239,7 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) {
236239
case ActionType::DumpTypeRefinementContexts:
237240
case ActionType::DumpTypeInfo:
238241
case ActionType::CompileModuleFromInterface:
242+
case ActionType::TypecheckModuleFromInterface:
239243
case ActionType::Immediate:
240244
case ActionType::REPL:
241245
case ActionType::EmitPCM:
@@ -285,6 +289,7 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) {
285289
case ActionType::DumpTypeRefinementContexts:
286290
case ActionType::DumpTypeInfo:
287291
case ActionType::CompileModuleFromInterface:
292+
case ActionType::TypecheckModuleFromInterface:
288293
case ActionType::Immediate:
289294
case ActionType::REPL:
290295
case ActionType::EmitPCM:
@@ -323,6 +328,7 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) {
323328
case ActionType::DumpTypeRefinementContexts:
324329
case ActionType::DumpTypeInfo:
325330
case ActionType::CompileModuleFromInterface:
331+
case ActionType::TypecheckModuleFromInterface:
326332
case ActionType::Immediate:
327333
case ActionType::REPL:
328334
case ActionType::EmitPCM:
@@ -367,6 +373,7 @@ bool FrontendOptions::canActionEmitModule(ActionType action) {
367373
case ActionType::DumpTypeInfo:
368374
case ActionType::EmitSILGen:
369375
case ActionType::CompileModuleFromInterface:
376+
case ActionType::TypecheckModuleFromInterface:
370377
case ActionType::Immediate:
371378
case ActionType::REPL:
372379
case ActionType::EmitPCM:
@@ -412,6 +419,7 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) {
412419
case ActionType::EmitSILGen:
413420
case ActionType::EmitSIBGen:
414421
case ActionType::CompileModuleFromInterface:
422+
case ActionType::TypecheckModuleFromInterface:
415423
case ActionType::Immediate:
416424
case ActionType::REPL:
417425
case ActionType::EmitPCM:
@@ -459,6 +467,7 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) {
459467
case ActionType::EmitImportedModules:
460468
case ActionType::MergeModules:
461469
case ActionType::CompileModuleFromInterface:
470+
case ActionType::TypecheckModuleFromInterface:
462471
case ActionType::DumpTypeInfo:
463472
case ActionType::EmitPCM:
464473
case ActionType::DumpPCM:
@@ -494,6 +503,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) {
494503
case ActionType::Parse:
495504
case ActionType::ResolveImports:
496505
case ActionType::Typecheck:
506+
case ActionType::TypecheckModuleFromInterface:
497507
case ActionType::DumpParse:
498508
case ActionType::DumpInterfaceHash:
499509
case ActionType::DumpAST:
@@ -532,6 +542,7 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) {
532542
case ActionType::EmitImportedModules:
533543
case ActionType::EmitPCH:
534544
case ActionType::CompileModuleFromInterface:
545+
case ActionType::TypecheckModuleFromInterface:
535546
case ActionType::EmitPCM:
536547
case ActionType::DumpPCM:
537548
case ActionType::ScanDependencies:
@@ -569,6 +580,7 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) {
569580
case ActionType::DumpTypeRefinementContexts:
570581
case ActionType::DumpTypeInfo:
571582
case ActionType::CompileModuleFromInterface:
583+
case ActionType::TypecheckModuleFromInterface:
572584
case ActionType::Typecheck:
573585
case ActionType::ResolveImports:
574586
case ActionType::MergeModules:

0 commit comments

Comments
 (0)