mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -51,9 +51,10 @@ public:
|
|||||||
GenerateDSYMJob,
|
GenerateDSYMJob,
|
||||||
VerifyDebugInfoJob,
|
VerifyDebugInfoJob,
|
||||||
GeneratePCHJob,
|
GeneratePCHJob,
|
||||||
|
VerifyModuleInterfaceJob,
|
||||||
|
|
||||||
JobFirst = CompileJob,
|
JobFirst = CompileJob,
|
||||||
JobLast = GeneratePCHJob
|
JobLast = VerifyModuleInterfaceJob
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *getClassName(Kind AC);
|
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 driver
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ protected:
|
|||||||
virtual InvocationInfo
|
virtual InvocationInfo
|
||||||
constructInvocation(const VerifyDebugInfoJobAction &job,
|
constructInvocation(const VerifyDebugInfoJobAction &job,
|
||||||
const JobContext &context) const;
|
const JobContext &context) const;
|
||||||
|
virtual InvocationInfo
|
||||||
|
constructInvocation(const VerifyModuleInterfaceJobAction &job,
|
||||||
|
const JobContext &context) const;
|
||||||
virtual InvocationInfo constructInvocation(const GeneratePCHJobAction &job,
|
virtual InvocationInfo constructInvocation(const GeneratePCHJobAction &job,
|
||||||
const JobContext &context) const;
|
const JobContext &context) const;
|
||||||
virtual InvocationInfo
|
virtual InvocationInfo
|
||||||
|
|||||||
@@ -460,6 +460,15 @@ def emit_private_module_interface_path :
|
|||||||
DoesNotAffectIncrementalBuild, ArgumentIsPath, SupplementaryOutput]>,
|
DoesNotAffectIncrementalBuild, ArgumentIsPath, SupplementaryOutput]>,
|
||||||
MetaVarName<"<path>">, HelpText<"Output private module interface file to <path>">;
|
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 :
|
def avoid_emit_module_source_info :
|
||||||
Flag<["-"], "avoid-emit-module-source-info">,
|
Flag<["-"], "avoid-emit-module-source-info">,
|
||||||
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
|
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const char *Action::getClassName(Kind AC) {
|
|||||||
case Kind::GenerateDSYMJob: return "generate-dSYM";
|
case Kind::GenerateDSYMJob: return "generate-dSYM";
|
||||||
case Kind::VerifyDebugInfoJob: return "verify-debug-info";
|
case Kind::VerifyDebugInfoJob: return "verify-debug-info";
|
||||||
case Kind::GeneratePCHJob: return "generate-pch";
|
case Kind::GeneratePCHJob: return "generate-pch";
|
||||||
|
case Kind::VerifyModuleInterfaceJob: return "verify-module-interface";
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm_unreachable("invalid class");
|
llvm_unreachable("invalid class");
|
||||||
@@ -65,3 +66,5 @@ void GenerateDSYMJobAction::anchor() {}
|
|||||||
void VerifyDebugInfoJobAction::anchor() {}
|
void VerifyDebugInfoJobAction::anchor() {}
|
||||||
|
|
||||||
void GeneratePCHJobAction::anchor() {}
|
void GeneratePCHJobAction::anchor() {}
|
||||||
|
|
||||||
|
void VerifyModuleInterfaceJobAction::anchor() {}
|
||||||
|
|||||||
@@ -2208,6 +2208,26 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
|
|||||||
TopLevelActions.push_back(MergeModuleAction);
|
TopLevelActions.push_back(MergeModuleAction);
|
||||||
TopLevelActions.append(AllLinkerInputs.begin(), AllLinkerInputs.end());
|
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) {
|
bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) {
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ std::unique_ptr<Job> ToolChain::constructJob(
|
|||||||
CASE(GeneratePCHJob)
|
CASE(GeneratePCHJob)
|
||||||
CASE(AutolinkExtractJob)
|
CASE(AutolinkExtractJob)
|
||||||
CASE(REPLJob)
|
CASE(REPLJob)
|
||||||
|
CASE(VerifyModuleInterfaceJob)
|
||||||
#undef CASE
|
#undef CASE
|
||||||
case Action::Kind::Input:
|
case Action::Kind::Input:
|
||||||
llvm_unreachable("not a JobAction");
|
llvm_unreachable("not a JobAction");
|
||||||
|
|||||||
@@ -1047,6 +1047,41 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
|
|||||||
return II;
|
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::InvocationInfo
|
||||||
ToolChain::constructInvocation(const ModuleWrapJobAction &job,
|
ToolChain::constructInvocation(const ModuleWrapJobAction &job,
|
||||||
const JobContext &context) const {
|
const JobContext &context) const {
|
||||||
|
|||||||
15
test/ModuleInterface/verify-module-interfaces.swift
Normal file
15
test/ModuleInterface/verify-module-interfaces.swift
Normal 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
|
||||||
Reference in New Issue
Block a user