Skip to content

Commit 5f523fe

Browse files
committed
Add flag to verify just-emitted module interfaces
The driver can now schedule jobs which typecheck just-emitted module interfaces to ensure that they can be consumed later. This can be enabled manually by passing `-verify-emitted-module-interface` to the driver.
1 parent 3c69837 commit 5f523fe

File tree

8 files changed

+108
-1
lines changed

8 files changed

+108
-1
lines changed

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/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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,26 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
22082208
TopLevelActions.push_back(MergeModuleAction);
22092209
TopLevelActions.append(AllLinkerInputs.begin(), AllLinkerInputs.end());
22102210
}
2211+
2212+
bool verifyInterfacesByDefault = false;
2213+
2214+
if (MergeModuleAction
2215+
&& Args.hasFlag(options::OPT_verify_emitted_module_interface,
2216+
options::OPT_no_verify_emitted_module_interface,
2217+
verifyInterfacesByDefault)) {
2218+
if (Args.hasArgNoClaim(options::OPT_emit_module_interface,
2219+
options::OPT_emit_module_interface_path)) {
2220+
TopLevelActions.push_back(
2221+
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
2222+
file_types::TY_SwiftModuleInterfaceFile));
2223+
}
2224+
2225+
if (Args.hasArgNoClaim(options::OPT_emit_private_module_interface_path)) {
2226+
TopLevelActions.push_back(
2227+
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
2228+
file_types::TY_PrivateSwiftModuleInterfaceFile));
2229+
}
2230+
}
22112231
}
22122232

22132233
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
@@ -1047,6 +1047,41 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
10471047
return II;
10481048
}
10491049

1050+
ToolChain::InvocationInfo
1051+
ToolChain::constructInvocation(const VerifyModuleInterfaceJobAction &job,
1052+
const JobContext &context) const {
1053+
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
1054+
ArgStringList &Arguments = II.Arguments;
1055+
II.allowsResponseFiles = true;
1056+
1057+
for (auto &s : getDriver().getSwiftProgramArgs())
1058+
Arguments.push_back(s.c_str());
1059+
Arguments.push_back("-frontend");
1060+
1061+
Arguments.push_back("-typecheck-module-from-interface");
1062+
1063+
size_t sizeBefore = Arguments.size();
1064+
addInputsOfType(Arguments, context.Inputs, context.Args, job.getInputType());
1065+
1066+
(void)sizeBefore;
1067+
assert(Arguments.size() - sizeBefore == 1 &&
1068+
"should verify exactly one module interface per job");
1069+
1070+
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
1071+
addRuntimeLibraryFlags(context.OI, Arguments);
1072+
1073+
addOutputsOfType(Arguments, context.Output, context.Args,
1074+
file_types::TY_SerializedDiagnostics,
1075+
"-serialize-diagnostics-path");
1076+
1077+
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
1078+
1079+
Arguments.push_back("-module-name");
1080+
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
1081+
1082+
return II;
1083+
}
1084+
10501085
ToolChain::InvocationInfo
10511086
ToolChain::constructInvocation(const ModuleWrapJobAction &job,
10521087
const JobContext &context) const {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// Check that verification won't reject a valid interface:
4+
// RUN: %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -verify-emitted-module-interface -module-name MyModule %s
5+
6+
// Check that verification will reject an invalid interface:
7+
// RUN: not %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -verify-emitted-module-interface -module-name MyModule -Xfrontend -debug-emit-invalid-swiftinterface-syntax %s 2>&1 | %FileCheck %s
8+
9+
// ...but not if verification is off.
10+
// RUN: %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -no-verify-emitted-module-interface -module-name MyModule -Xfrontend -debug-emit-invalid-swiftinterface-syntax %s
11+
12+
public struct MyStruct {}
13+
14+
// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#__debug_emit_invalid_swiftinterface_syntax__'
15+
// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: failed to build module 'MyModule' from its module interface; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced

0 commit comments

Comments
 (0)