diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 775cad840dd..689402c65e6 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -131,6 +131,8 @@ ERROR(error_mode_cannot_emit_symbol_graph,none, "this mode does not support emitting symbol graph files", ()) ERROR(error_mode_cannot_emit_abi_descriptor,none, "this mode does not support emitting ABI descriptor", ()) +ERROR(error_mode_cannot_emit_module_semantic_info,none, + "this mode does not support emitting module semantic info", ()) ERROR(cannot_emit_ir_skipping_function_bodies,none, "the -experimental-skip-*-function-bodies* flags do not support " "emitting IR", ()) diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h index d945408594a..6abdd3399cb 100644 --- a/include/swift/Basic/SupplementaryOutputPaths.h +++ b/include/swift/Basic/SupplementaryOutputPaths.h @@ -146,6 +146,9 @@ struct SupplementaryOutputPaths { /// The output path to generate ABI baseline. std::string ABIDescriptorOutputPath; + /// The output path of Swift semantic info for this module. + std::string ModuleSemanticInfoOutputPath; + /// The output path for YAML optimization record file. std::string YAMLOptRecordPath; @@ -189,6 +192,8 @@ struct SupplementaryOutputPaths { fn(YAMLOptRecordPath); if (!BitstreamOptRecordPath.empty()) fn(BitstreamOptRecordPath); + if (!ModuleSemanticInfoOutputPath.empty()) + fn(ModuleSemanticInfoOutputPath); } bool empty() const { @@ -198,6 +203,7 @@ struct SupplementaryOutputPaths { SerializedDiagnosticsPath.empty() && LoadedModuleTracePath.empty() && TBDPath.empty() && ModuleInterfaceOutputPath.empty() && ModuleSourceInfoOutputPath.empty() && ABIDescriptorOutputPath.empty() && + ModuleSemanticInfoOutputPath.empty() && YAMLOptRecordPath.empty() && BitstreamOptRecordPath.empty(); } }; diff --git a/include/swift/Frontend/FrontendInputsAndOutputs.h b/include/swift/Frontend/FrontendInputsAndOutputs.h index a613eb85914..9d2786e6f0e 100644 --- a/include/swift/Frontend/FrontendInputsAndOutputs.h +++ b/include/swift/Frontend/FrontendInputsAndOutputs.h @@ -257,6 +257,7 @@ public: bool hasModuleInterfaceOutputPath() const; bool hasPrivateModuleInterfaceOutputPath() const; bool hasABIDescriptorOutputPath() const; + bool hasModuleSemanticInfoOutputPath() const; bool hasModuleSummaryOutputPath() const; bool hasTBDPath() const; bool hasYAMLOptRecordPath() const; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index ce557ca71e2..f8d44dd513e 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -437,6 +437,7 @@ private: static bool canActionEmitModuleSummary(ActionType); static bool canActionEmitInterface(ActionType); static bool canActionEmitABIDescriptor(ActionType); + static bool canActionEmitModuleSemanticInfo(ActionType); public: static bool doesActionGenerateSIL(ActionType); diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 43c4baf8953..97c46b50ad6 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -68,6 +68,10 @@ def emit_abi_descriptor_path : Separate<["-"], "emit-abi-descriptor-path">, MetaVarName<"">, HelpText<"Output the ABI descriptor of current module to ">; +def emit_module_semantic_info_path + : Separate<["-"], "emit-module-semantic-info-path">, MetaVarName<"">, + HelpText<"Output semantic info of current module to ">; + def serialize_module_interface_dependency_hashes : Flag<["-"], "serialize-module-interface-dependency-hashes">, Flags<[HelpHidden]>; diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 8d861a3b8ae..5c7bb77525e 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -680,6 +680,11 @@ bool ArgsToFrontendOptionsConverter::checkUnusedSupplementaryOutputPaths() Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_abi_descriptor); return true; } + if (!FrontendOptions::canActionEmitModuleSemanticInfo(Opts.RequestedAction) && + Opts.InputsAndOutputs.hasModuleSemanticInfoOutputPath()) { + Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_semantic_info); + return true; + } // If we cannot emit module doc, we cannot emit source information file either. if (!FrontendOptions::canActionEmitModuleDoc(Opts.RequestedAction) && Opts.InputsAndOutputs.hasModuleSourceInfoOutputPath()) { diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp index 26c4c37d4db..7e9dfbfc3d8 100644 --- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp @@ -341,6 +341,8 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() options::OPT_emit_module_summary_path); auto abiDescriptorOutput = getSupplementaryFilenamesFromArguments( options::OPT_emit_abi_descriptor_path); + auto moduleSemanticInfoOutput = getSupplementaryFilenamesFromArguments( + options::OPT_emit_module_semantic_info_path); auto optRecordOutput = getSupplementaryFilenamesFromArguments( options::OPT_save_optimization_record_path); if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput || @@ -348,7 +350,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() !serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD || !moduleInterfaceOutput || !privateModuleInterfaceOutput || !moduleSourceInfoOutput || !moduleSummaryOutput || !abiDescriptorOutput || - !optRecordOutput) { + !moduleSemanticInfoOutput || !optRecordOutput) { return None; } std::vector result; @@ -371,6 +373,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() sop.ModuleSourceInfoOutputPath = (*moduleSourceInfoOutput)[i]; sop.ModuleSummaryOutputPath = (*moduleSummaryOutput)[i]; sop.ABIDescriptorOutputPath = (*abiDescriptorOutput)[i]; + sop.ModuleSemanticInfoOutputPath = (*moduleSemanticInfoOutput)[i]; sop.YAMLOptRecordPath = (*optRecordOutput)[i]; sop.BitstreamOptRecordPath = (*optRecordOutput)[i]; result.push_back(sop); @@ -473,6 +476,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( // There is no non-path form of -emit-abi-descriptor-path auto ABIDescriptorOutputPath = pathsFromArguments.ABIDescriptorOutputPath; + auto ModuleSemanticInfoOutputPath = pathsFromArguments.ModuleSemanticInfoOutputPath; ID emitModuleOption; std::string moduleExtension; std::string mainOutputIfUsableForModule; @@ -508,6 +512,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( sop.ModuleSourceInfoOutputPath = moduleSourceInfoOutputPath; sop.ModuleSummaryOutputPath = moduleSummaryOutputPath; sop.ABIDescriptorOutputPath = ABIDescriptorOutputPath; + sop.ModuleSemanticInfoOutputPath = ModuleSemanticInfoOutputPath; sop.YAMLOptRecordPath = YAMLOptRecordPath; sop.BitstreamOptRecordPath = bitstreamOptRecordPath; return sop; diff --git a/lib/Frontend/FrontendInputsAndOutputs.cpp b/lib/Frontend/FrontendInputsAndOutputs.cpp index 060f901c3ef..98257c564c1 100644 --- a/lib/Frontend/FrontendInputsAndOutputs.cpp +++ b/lib/Frontend/FrontendInputsAndOutputs.cpp @@ -509,6 +509,12 @@ bool FrontendInputsAndOutputs::hasABIDescriptorOutputPath() const { return outs.ABIDescriptorOutputPath; }); } +bool FrontendInputsAndOutputs::hasModuleSemanticInfoOutputPath() const { + return hasSupplementaryOutputPath( + [](const SupplementaryOutputPaths &outs) -> const std::string & { + return outs.ModuleSemanticInfoOutputPath; + }); +} bool FrontendInputsAndOutputs::hasModuleSummaryOutputPath() const { return hasSupplementaryOutputPath( [](const SupplementaryOutputPaths &outs) -> const std::string & { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index bc8bf8148b7..2861216b8fc 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -524,6 +524,48 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) { } llvm_unreachable("unhandled action"); } +bool FrontendOptions::canActionEmitModuleSemanticInfo(ActionType action) { + switch (action) { + case ActionType::MergeModules: + case ActionType::EmitModuleOnly: + case ActionType::CompileModuleFromInterface: + // For test + case ActionType::Typecheck: + return true; + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::ResolveImports: + case ActionType::DumpParse: + case ActionType::DumpInterfaceHash: + case ActionType::DumpAST: + case ActionType::EmitSyntax: + case ActionType::PrintAST: + case ActionType::EmitPCH: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::DumpTypeInfo: + case ActionType::EmitSILGen: + case ActionType::TypecheckModuleFromInterface: + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::ScanDependencies: + case ActionType::PrintVersion: + case ActionType::PrintFeature: + case ActionType::EmitSIL: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::EmitIRGen: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitAssembly: + case ActionType::EmitObject: + case ActionType::EmitImportedModules: + return false; + } + llvm_unreachable("unhandled action"); +} bool FrontendOptions::canActionEmitABIDescriptor(ActionType action) { switch (action) { case ActionType::MergeModules: diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 1414be9921b..c4b4fb29043 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -80,6 +80,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/FileSystem.h" #if __has_include() #include @@ -660,6 +661,22 @@ static void emitSwiftdepsForAllPrimaryInputsIfNeeded( } } +static bool writeModuleSemanticInfoIfNeeded(CompilerInstance &Instance) { + const auto &Invocation = Instance.getInvocation(); + const auto &frontendOpts = Invocation.getFrontendOptions(); + if (!frontendOpts.InputsAndOutputs.hasModuleSemanticInfoOutputPath()) + return false; + std::error_code EC; + assert(frontendOpts.InputsAndOutputs.isWholeModule() && + "TBDPath only makes sense when the whole module can be seen"); + auto ModuleSemanticPath = frontendOpts.InputsAndOutputs + .getPrimarySpecificPathsForAtMostOnePrimary().SupplementaryOutputs + .ModuleSemanticInfoOutputPath; + llvm::raw_fd_ostream OS(ModuleSemanticPath, EC, llvm::sys::fs::OF_None); + OS << "{}\n"; + return false; +} + static bool writeTBDIfNeeded(CompilerInstance &Instance) { const auto &Invocation = Instance.getInvocation(); const auto &frontendOpts = Invocation.getFrontendOptions(); @@ -842,6 +859,9 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs( hadAnyError |= writeTBDIfNeeded(Instance); } + { + hadAnyError |= writeModuleSemanticInfoIfNeeded(Instance); + } return hadAnyError; } diff --git a/test/IDE/emit-module-semantic.swift b/test/IDE/emit-module-semantic.swift new file mode 100644 index 00000000000..1295e9513a5 --- /dev/null +++ b/test/IDE/emit-module-semantic.swift @@ -0,0 +1,7 @@ +// REQUIRES: VENDOR=apple +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -emit-module %s -emit-module-path %t/Foo.swiftmodule -module-name Foo -emit-module-semantic-info-path %t/Foo.swiftsemanticinfo + +// RUN: ls %t/Foo.swiftmodule +// RUN: ls %t/Foo.swiftsemanticinfo