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.
This commit is contained in:
Brent Royal-Gordon
2020-08-07 17:43:28 -07:00
parent 3c69837102
commit 5f523fee66
8 changed files with 108 additions and 1 deletions

View File

@@ -51,9 +51,10 @@ public:
GenerateDSYMJob,
VerifyDebugInfoJob,
GeneratePCHJob,
VerifyModuleInterfaceJob,
JobFirst = CompileJob,
JobLast = GeneratePCHJob
JobLast = VerifyModuleInterfaceJob
};
static const char *getClassName(Kind AC);
@@ -357,6 +358,26 @@ public:
}
};
class VerifyModuleInterfaceJobAction : public JobAction {
virtual void anchor();
file_types::ID inputType;
public:
VerifyModuleInterfaceJobAction(const Action * ModuleEmitter,
file_types::ID inputType)
: JobAction(Action::Kind::VerifyModuleInterfaceJob, { ModuleEmitter },
file_types::TY_Nothing), inputType(inputType) {
assert(inputType == file_types::TY_SwiftModuleInterfaceFile ||
inputType == file_types::TY_PrivateSwiftModuleInterfaceFile);
}
file_types::ID getInputType() const { return inputType; }
static bool classof(const Action *A) {
return A->getKind() == Action::Kind::VerifyModuleInterfaceJob;
}
};
} // end namespace driver
} // end namespace swift

View File

@@ -162,6 +162,9 @@ protected:
virtual InvocationInfo
constructInvocation(const VerifyDebugInfoJobAction &job,
const JobContext &context) const;
virtual InvocationInfo
constructInvocation(const VerifyModuleInterfaceJobAction &job,
const JobContext &context) const;
virtual InvocationInfo constructInvocation(const GeneratePCHJobAction &job,
const JobContext &context) const;
virtual InvocationInfo

View File

@@ -460,6 +460,15 @@ def emit_private_module_interface_path :
DoesNotAffectIncrementalBuild, ArgumentIsPath, SupplementaryOutput]>,
MetaVarName<"<path>">, HelpText<"Output private module interface file to <path>">;
def verify_emitted_module_interface :
Flag<["-"], "verify-emitted-module-interface">,
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
HelpText<"Check that module interfaces emitted during compilation typecheck">;
def no_verify_emitted_module_interface :
Flag<["-"], "no-verify-emitted-module-interface">,
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
HelpText<"Don't check that module interfaces emitted during compilation typecheck">;
def avoid_emit_module_source_info :
Flag<["-"], "avoid-emit-module-source-info">,
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,

View File

@@ -33,6 +33,7 @@ const char *Action::getClassName(Kind AC) {
case Kind::GenerateDSYMJob: return "generate-dSYM";
case Kind::VerifyDebugInfoJob: return "verify-debug-info";
case Kind::GeneratePCHJob: return "generate-pch";
case Kind::VerifyModuleInterfaceJob: return "verify-module-interface";
}
llvm_unreachable("invalid class");
@@ -65,3 +66,5 @@ void GenerateDSYMJobAction::anchor() {}
void VerifyDebugInfoJobAction::anchor() {}
void GeneratePCHJobAction::anchor() {}
void VerifyModuleInterfaceJobAction::anchor() {}

View File

@@ -2208,6 +2208,26 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
TopLevelActions.push_back(MergeModuleAction);
TopLevelActions.append(AllLinkerInputs.begin(), AllLinkerInputs.end());
}
bool verifyInterfacesByDefault = false;
if (MergeModuleAction
&& Args.hasFlag(options::OPT_verify_emitted_module_interface,
options::OPT_no_verify_emitted_module_interface,
verifyInterfacesByDefault)) {
if (Args.hasArgNoClaim(options::OPT_emit_module_interface,
options::OPT_emit_module_interface_path)) {
TopLevelActions.push_back(
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
file_types::TY_SwiftModuleInterfaceFile));
}
if (Args.hasArgNoClaim(options::OPT_emit_private_module_interface_path)) {
TopLevelActions.push_back(
C.createAction<VerifyModuleInterfaceJobAction>(MergeModuleAction,
file_types::TY_PrivateSwiftModuleInterfaceFile));
}
}
}
bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) {

View File

@@ -111,6 +111,7 @@ std::unique_ptr<Job> ToolChain::constructJob(
CASE(GeneratePCHJob)
CASE(AutolinkExtractJob)
CASE(REPLJob)
CASE(VerifyModuleInterfaceJob)
#undef CASE
case Action::Kind::Input:
llvm_unreachable("not a JobAction");

View File

@@ -1047,6 +1047,41 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
return II;
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const VerifyModuleInterfaceJobAction &job,
const JobContext &context) const {
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
ArgStringList &Arguments = II.Arguments;
II.allowsResponseFiles = true;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-frontend");
Arguments.push_back("-typecheck-module-from-interface");
size_t sizeBefore = Arguments.size();
addInputsOfType(Arguments, context.Inputs, context.Args, job.getInputType());
(void)sizeBefore;
assert(Arguments.size() - sizeBefore == 1 &&
"should verify exactly one module interface per job");
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
addRuntimeLibraryFlags(context.OI, Arguments);
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
return II;
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const ModuleWrapJobAction &job,
const JobContext &context) const {

View File

@@ -0,0 +1,15 @@
// RUN: %empty-directory(%t)
// Check that verification won't reject a valid interface:
// 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
// Check that verification will reject an invalid interface:
// 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
// ...but not if verification is off.
// 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
public struct MyStruct {}
// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#__debug_emit_invalid_swiftinterface_syntax__'
// 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