Merge remote-tracking branch 'origin/master' into master-next

This commit is contained in:
swift-ci
2018-02-28 11:51:52 -08:00
23 changed files with 490 additions and 379 deletions

View File

@@ -15,26 +15,39 @@
#include "swift/Basic/LLVM.h" #include "swift/Basic/LLVM.h"
#include "swift/Basic/SupplementaryOutputPaths.h" #include "swift/Basic/SupplementaryOutputPaths.h"
#include "llvm/ADT/StringRef.h"
#include <string> #include <string>
namespace swift { namespace swift {
/// Holds all of the output paths, and debugging-info path that are
/// specific to which primary file is being compiled at the moment.
class PrimarySpecificPaths { class PrimarySpecificPaths {
public: public:
/// The name of the main output file,
/// that is, the .o file for this input. If there is no such file, contains an
/// empty string. If the output is to be written to stdout, contains "-".
std::string OutputFilename; std::string OutputFilename;
SupplementaryOutputPaths SupplementaryOutputs; SupplementaryOutputPaths SupplementaryOutputs;
/// The name of the "main" input file, used by the debug info. /// The name of the "main" input file, used by the debug info.
std::string MainInputFilenameForDebugInfo; std::string MainInputFilenameForDebugInfo;
PrimarySpecificPaths( PrimarySpecificPaths(StringRef OutputFilename = StringRef(),
std::string OutputFilename = std::string(), StringRef MainInputFilenameForDebugInfo = StringRef(),
std::string MainInputFilenameForDebugInfo = std::string(), SupplementaryOutputPaths SupplementaryOutputs =
SupplementaryOutputPaths SupplementaryOutputs = SupplementaryOutputPaths())
SupplementaryOutputPaths())
: OutputFilename(OutputFilename), : OutputFilename(OutputFilename),
SupplementaryOutputs(SupplementaryOutputs), SupplementaryOutputs(SupplementaryOutputs),
MainInputFilenameForDebugInfo(MainInputFilenameForDebugInfo) {} MainInputFilenameForDebugInfo(MainInputFilenameForDebugInfo) {}
bool haveModuleOrModuleDocOutputPaths() const {
return !SupplementaryOutputs.ModuleOutputPath.empty() ||
!SupplementaryOutputs.ModuleDocOutputPath.empty();
}
}; };
} // namespace swift } // namespace swift

View File

@@ -21,18 +21,28 @@
namespace swift { namespace swift {
struct SupplementaryOutputPaths { struct SupplementaryOutputPaths {
/// The path to which we should emit an Objective-C header for the module. /// The path to which we should emit an Objective-C header for the module.
/// Currently only makes sense when the compiler has whole module knowledge.
/// The modes for which it makes sense incuide both WMO and the "merge
/// modules" job that happens after the normal compilation jobs. That's where
/// the header is emitted in single-file mode, since it needs whole-module
/// information.
std::string ObjCHeaderOutputPath; std::string ObjCHeaderOutputPath;
/// The path to which we should emit a serialized module. /// The path to which we should emit a serialized module.
/// It is valid whenever there are any inputs.
std::string ModuleOutputPath; std::string ModuleOutputPath;
/// The path to which we should emit a module documentation file. /// The path to which we should emit a module documentation file.
/// It is valid whenever there are any inputs.
std::string ModuleDocOutputPath; std::string ModuleDocOutputPath;
/// The path to which we should output a Make-style dependencies file. /// The path to which we should output a Make-style dependencies file.
/// It is valid whenever there are any inputs.
std::string DependenciesFilePath; std::string DependenciesFilePath;
/// The path to which we should output a Swift reference dependencies file. /// The path to which we should output a Swift reference dependencies file.
/// It is valid whenever there are any inputs.
std::string ReferenceDependenciesFilePath; std::string ReferenceDependenciesFilePath;
/// Path to a file which should contain serialized diagnostics for this /// Path to a file which should contain serialized diagnostics for this
@@ -40,9 +50,11 @@ struct SupplementaryOutputPaths {
std::string SerializedDiagnosticsPath; std::string SerializedDiagnosticsPath;
/// The path to which we should output a loaded module trace file. /// The path to which we should output a loaded module trace file.
/// It is currently only used with WMO, but could be generalized.
std::string LoadedModuleTracePath; std::string LoadedModuleTracePath;
/// The path to which we should output a TBD file. /// The path to which we should output a TBD file.
/// It is currently only used with WMO, but could be generalized.
std::string TBDPath; std::string TBDPath;
SupplementaryOutputPaths() = default; SupplementaryOutputPaths() = default;

View File

@@ -43,7 +43,7 @@ public:
Diags(diags) {} Diags(diags) {}
bool convert(std::vector<std::string> &mainOutputs, bool convert(std::vector<std::string> &mainOutputs,
SupplementaryOutputPaths &supplementaryOutputs); std::vector<SupplementaryOutputPaths> &supplementaryOutputs);
/// Try to read an output file list file. /// Try to read an output file list file.
/// \returns `None` if it could not open the filelist. /// \returns `None` if it could not open the filelist.
@@ -57,7 +57,7 @@ class OutputFilesComputer {
const FrontendInputsAndOutputs &InputsAndOutputs; const FrontendInputsAndOutputs &InputsAndOutputs;
const std::vector<std::string> OutputFileArguments; const std::vector<std::string> OutputFileArguments;
const std::string OutputDirectoryArgument; const std::string OutputDirectoryArgument;
const StringRef FirstInput; const std::string FirstInput;
const FrontendOptions::ActionType RequestedAction; const FrontendOptions::ActionType RequestedAction;
const llvm::opt::Arg *const ModuleNameArg; const llvm::opt::Arg *const ModuleNameArg;
const StringRef Suffix; const StringRef Suffix;

View File

@@ -174,15 +174,6 @@ public:
return SearchPathOpts.SDKPath; return SearchPathOpts.SDKPath;
} }
void setSerializedDiagnosticsPath(StringRef Path) {
FrontendOpts.InputsAndOutputs.supplementaryOutputs()
.SerializedDiagnosticsPath = Path;
}
StringRef getSerializedDiagnosticsPath() const {
return FrontendOpts.InputsAndOutputs.supplementaryOutputs()
.SerializedDiagnosticsPath;
}
LangOptions &getLangOptions() { LangOptions &getLangOptions() {
return LangOpts; return LangOpts;
} }
@@ -245,8 +236,7 @@ public:
return FrontendOpts.ModuleName; return FrontendOpts.ModuleName;
} }
std::string getOutputFilename() const {
StringRef getOutputFilename() const {
return FrontendOpts.InputsAndOutputs.getSingleOutputFilename(); return FrontendOpts.InputsAndOutputs.getSingleOutputFilename();
} }
@@ -302,11 +292,25 @@ public:
return FrontendOpts.InputKind == InputFileKind::IFK_Swift_Library; return FrontendOpts.InputKind == InputFileKind::IFK_Swift_Library;
} }
PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const; const PrimarySpecificPaths &
PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
const PrimarySpecificPaths &
getPrimarySpecificPathsForPrimary(StringRef filename) const; getPrimarySpecificPathsForPrimary(StringRef filename) const;
PrimarySpecificPaths const PrimarySpecificPaths &
getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const; getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;
std::string getOutputFilenameForAtMostOnePrimary() const;
std::string getMainInputFilenameForDebugInfoForAtMostOnePrimary() const;
std::string getObjCHeaderOutputPathForAtMostOnePrimary() const;
std::string getModuleOutputPathForAtMostOnePrimary() const;
std::string
getReferenceDependenciesFilePathForPrimary(StringRef filename) const;
std::string getSerializedDiagnosticsPathForAtMostOnePrimary() const;
/// TBDPath only makes sense in whole module compilation mode,
/// so return the TBDPath when in that mode and fail an assert
/// if not in that mode.
std::string getTBDPathForWholeModule() const;
}; };
/// A class which manages the state and execution of the compiler. /// A class which manages the state and execution of the compiler.
@@ -584,12 +588,13 @@ private:
void finishTypeChecking(OptionSet<TypeCheckingFlags> TypeCheckOptions); void finishTypeChecking(OptionSet<TypeCheckingFlags> TypeCheckOptions);
public: public:
PrimarySpecificPaths const PrimarySpecificPaths &
getPrimarySpecificPathsForWholeModuleOptimizationMode() const; getPrimarySpecificPathsForWholeModuleOptimizationMode() const;
PrimarySpecificPaths const PrimarySpecificPaths &
getPrimarySpecificPathsForPrimary(StringRef filename) const; getPrimarySpecificPathsForPrimary(StringRef filename) const;
PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const; const PrimarySpecificPaths &
PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
const PrimarySpecificPaths &
getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const; getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;
}; };

View File

@@ -35,8 +35,8 @@ class FrontendInputsAndOutputs {
friend class ArgsToFrontendInputsConverter; friend class ArgsToFrontendInputsConverter;
std::vector<InputFile> AllInputs; std::vector<InputFile> AllInputs;
llvm::StringMap<unsigned> PrimaryInputsByName;
llvm::StringMap<unsigned> PrimaryInputs; std::vector<unsigned> PrimaryInputsInOrder;
/// In Single-threaded WMO mode, all inputs are used /// In Single-threaded WMO mode, all inputs are used
/// both for importing and compiling. /// both for importing and compiling.
@@ -45,25 +45,10 @@ class FrontendInputsAndOutputs {
/// Punt where needed to enable batch mode experiments. /// Punt where needed to enable batch mode experiments.
bool AreBatchModeChecksBypassed = false; bool AreBatchModeChecksBypassed = false;
SupplementaryOutputPaths SupplementaryOutputs;
public: public:
bool areBatchModeChecksBypassed() const { return AreBatchModeChecksBypassed; } bool areBatchModeChecksBypassed() const { return AreBatchModeChecksBypassed; }
void setBypassBatchModeChecks(bool bbc) { AreBatchModeChecksBypassed = bbc; } void setBypassBatchModeChecks(bool bbc) { AreBatchModeChecksBypassed = bbc; }
const SupplementaryOutputPaths &supplementaryOutputs() const {
return SupplementaryOutputs;
}
SupplementaryOutputPaths &supplementaryOutputs() {
return SupplementaryOutputs;
}
/// When performing a compilation for zero or one primary input file,
/// this will hold the PrimarySpecificPaths.
/// In a future PR, each InputFile will hold its own PrimarySpecificPaths and
/// this will go away.
PrimarySpecificPaths PrimarySpecificPathsForAtMostOnePrimary;
FrontendInputsAndOutputs() = default; FrontendInputsAndOutputs() = default;
FrontendInputsAndOutputs(const FrontendInputsAndOutputs &other); FrontendInputsAndOutputs(const FrontendInputsAndOutputs &other);
FrontendInputsAndOutputs &operator=(const FrontendInputsAndOutputs &other); FrontendInputsAndOutputs &operator=(const FrontendInputsAndOutputs &other);
@@ -88,6 +73,9 @@ public:
std::vector<std::string> getInputFilenames() const; std::vector<std::string> getInputFilenames() const;
/// \return nullptr if not a primary input file.
const InputFile *primaryInputNamed(StringRef name) const;
unsigned inputCount() const { return AllInputs.size(); } unsigned inputCount() const { return AllInputs.size(); }
bool hasInputs() const { return !AllInputs.empty(); } bool hasInputs() const { return !AllInputs.empty(); }
@@ -99,21 +87,23 @@ public:
const InputFile &lastInput() const { return AllInputs.back(); } const InputFile &lastInput() const { return AllInputs.back(); }
StringRef getFilenameOfFirstInput() const; const std::string &getFilenameOfFirstInput() const;
bool isReadingFromStdin() const; bool isReadingFromStdin() const;
void forEachInput(llvm::function_ref<void(const InputFile &)> fn) const; /// If \p fn returns true, exits early and returns true.
bool forEachInput(llvm::function_ref<bool(const InputFile &)> fn) const;
// Primaries: // Primaries:
const InputFile &firstPrimaryInput() const; const InputFile &firstPrimaryInput() const;
const InputFile &lastPrimaryInput() const; const InputFile &lastPrimaryInput() const;
void /// If \p fn returns true, exit early and return true.
forEachPrimaryInput(llvm::function_ref<void(const InputFile &)> fn) const; bool
forEachPrimaryInput(llvm::function_ref<bool(const InputFile &)> fn) const;
unsigned primaryInputCount() const { return PrimaryInputs.size(); } unsigned primaryInputCount() const { return PrimaryInputsInOrder.size(); }
// Primary count readers: // Primary count readers:
@@ -143,11 +133,8 @@ public:
const InputFile &getRequiredUniquePrimaryInput() const; const InputFile &getRequiredUniquePrimaryInput() const;
/// \return the name of the unique primary input, or an empty StrinRef if /// FIXME: Should combine all primaries for the result
/// there isn't one. /// instead of just answering "batch" if there is more than one primary.
StringRef getNameOfUniquePrimaryInputFile() const;
/// Combines all primaries for stats reporter
std::string getStatsFileMangledInputName() const; std::string getStatsFileMangledInputName() const;
bool isInputPrimary(StringRef file) const; bool isInputPrimary(StringRef file) const;
@@ -181,9 +168,9 @@ public:
private: private:
friend class ArgsToFrontendOptionsConverter; friend class ArgsToFrontendOptionsConverter;
void void setMainAndSupplementaryOutputs(
setMainAndSupplementaryOutputs(ArrayRef<std::string> outputFiles, ArrayRef<std::string> outputFiles,
SupplementaryOutputPaths supplementaryOutputs); ArrayRef<SupplementaryOutputPaths> supplementaryOutputs);
public: public:
unsigned countOfInputsProducingMainOutputs() const; unsigned countOfInputsProducingMainOutputs() const;
@@ -198,17 +185,18 @@ public:
/// Under single-threaded WMO, we pretend that the first input /// Under single-threaded WMO, we pretend that the first input
/// generates the main output, even though it will include code /// generates the main output, even though it will include code
/// generated from all of them. /// generated from all of them.
void forEachInputProducingAMainOutputFile( ///
llvm::function_ref<void(const InputFile &)> fn) const; /// If \p fn returns true, return early and return true.
bool forEachInputProducingAMainOutputFile(
llvm::function_ref<bool(const InputFile &)> fn) const;
std::vector<std::string> copyOutputFilenames() const; std::vector<std::string> copyOutputFilenames() const;
void void forEachOutputFilename(llvm::function_ref<void(StringRef)> fn) const;
forEachOutputFilename(llvm::function_ref<void(const std::string &)> fn) const;
/// Gets the name of the specified output filename. /// Gets the name of the specified output filename.
/// If multiple files are specified, the last one is returned. /// If multiple files are specified, the last one is returned.
StringRef getSingleOutputFilename() const; std::string getSingleOutputFilename() const;
bool isOutputFilenameStdout() const; bool isOutputFilenameStdout() const;
bool isOutputFileDirectory() const; bool isOutputFileDirectory() const;
@@ -218,17 +206,22 @@ public:
unsigned countOfFilesProducingSupplementaryOutput() const; unsigned countOfFilesProducingSupplementaryOutput() const;
void forEachInputProducingSupplementaryOutput( /// If \p fn returns true, exit early and return true.
llvm::function_ref<void(const InputFile &)> fn) const; bool forEachInputProducingSupplementaryOutput(
llvm::function_ref<bool(const InputFile &)> fn) const;
/// Assumes there is not more than one primary input file, if any. /// Assumes there is not more than one primary input file, if any.
/// Otherwise, you would need to call getPrimarySpecificPathsForPrimary /// Otherwise, you would need to call getPrimarySpecificPathsForPrimary
/// to tell it which primary input you wanted the outputs for. /// to tell it which primary input you wanted the outputs for.
const PrimarySpecificPaths &
getPrimarySpecificPathsForAtMostOnePrimary() const;
PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const; const PrimarySpecificPaths &
getPrimarySpecificPathsForPrimary(StringRef) const;
PrimarySpecificPaths bool hasSupplementaryOutputPath(
getPrimarySpecificPathsForPrimary(StringRef filename) const; llvm::function_ref<const std::string &(const SupplementaryOutputPaths &)>
extractorFn) const;
bool hasDependenciesPath() const; bool hasDependenciesPath() const;
bool hasReferenceDependenciesPath() const; bool hasReferenceDependenciesPath() const;

View File

@@ -39,7 +39,7 @@ public:
InputFileKind InputKind = InputFileKind::IFK_Swift; InputFileKind InputKind = InputFileKind::IFK_Swift;
void forAllOutputPaths(const InputFile &input, void forAllOutputPaths(const InputFile &input,
std::function<void(const std::string &)> fn) const; std::function<void(StringRef)> fn) const;
bool isOutputFileDirectory() const; bool isOutputFileDirectory() const;
@@ -273,8 +273,6 @@ public:
return llvm::hash_value(0); return llvm::hash_value(0);
} }
StringRef originalPath() const;
StringRef determineFallbackModuleName() const; StringRef determineFallbackModuleName() const;
bool isCompilingExactlyOneSwiftFile() const { bool isCompilingExactlyOneSwiftFile() const {
@@ -282,8 +280,10 @@ public:
InputsAndOutputs.hasSingleInput(); InputsAndOutputs.hasSingleInput();
} }
PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const; const PrimarySpecificPaths &
PrimarySpecificPaths getPrimarySpecificPathsForPrimary(StringRef) const; getPrimarySpecificPathsForAtMostOnePrimary() const;
const PrimarySpecificPaths &
getPrimarySpecificPathsForPrimary(StringRef) const;
private: private:
static bool canActionEmitDependencies(ActionType); static bool canActionEmitDependencies(ActionType);

View File

@@ -13,6 +13,8 @@
#ifndef SWIFT_FRONTEND_INPUTFILE_H #ifndef SWIFT_FRONTEND_INPUTFILE_H
#define SWIFT_FRONTEND_INPUTFILE_H #define SWIFT_FRONTEND_INPUTFILE_H
#include "swift/Basic/PrimarySpecificPaths.h"
#include "swift/Basic/SupplementaryOutputPaths.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -37,10 +39,12 @@ class InputFile {
/// none. /// none.
llvm::MemoryBuffer *Buffer; llvm::MemoryBuffer *Buffer;
/// Contains the name of the main output file, that is, the .o file for this /// If there are explicit primary inputs (i.e. designated with -primary-input
/// input. If there is no such file, contains an empty string. If the output /// or -primary-filelist), the paths specific to those inputs (other than the
/// is to be written to stdout, contains "-". /// input file path itself) are kept here. If there are no explicit primary
std::string OutputFilename; /// inputs (for instance for whole module optimization), the corresponding
/// paths are kept in the first input file.
PrimarySpecificPaths PSPs;
public: public:
/// Does not take ownership of \p buffer. Does take ownership of (copy) a /// Does not take ownership of \p buffer. Does take ownership of (copy) a
@@ -50,13 +54,13 @@ public:
StringRef outputFilename = StringRef()) StringRef outputFilename = StringRef())
: Filename( : Filename(
convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(name)), convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(name)),
IsPrimary(isPrimary), Buffer(buffer), OutputFilename(outputFilename) { IsPrimary(isPrimary), Buffer(buffer), PSPs(PrimarySpecificPaths()) {
assert(!name.empty()); assert(!name.empty());
} }
bool isPrimary() const { return IsPrimary; } bool isPrimary() const { return IsPrimary; }
llvm::MemoryBuffer *buffer() const { return Buffer; } llvm::MemoryBuffer *buffer() const { return Buffer; }
StringRef file() const { const std::string &file() const {
assert(!Filename.empty()); assert(!Filename.empty());
return Filename; return Filename;
} }
@@ -68,13 +72,26 @@ public:
return filename.equals("<stdin>") ? "-" : filename; return filename.equals("<stdin>") ? "-" : filename;
} }
const std::string &outputFilename() const { return OutputFilename; } std::string outputFilename() const { return PSPs.OutputFilename; }
void setOutputFilename(StringRef outputFilename) { const PrimarySpecificPaths &getPrimarySpecificPaths() const { return PSPs; }
OutputFilename = outputFilename;
void setPrimarySpecificPaths(const PrimarySpecificPaths &PSPs) {
this->PSPs = PSPs;
}
// The next set of functions provides access to those primary-specific paths
// accessed directly from an InputFile, as opposed to via
// FrontendInputsAndOutputs. They merely make the call sites
// a bit shorter. Add more forwarding methods as needed.
std::string dependenciesFilePath() const {
return getPrimarySpecificPaths().SupplementaryOutputs.DependenciesFilePath;
}
std::string loadedModuleTracePath() const {
return getPrimarySpecificPaths().SupplementaryOutputs.LoadedModuleTracePath;
} }
}; };
} // namespace swift } // namespace swift
#endif /* SWIFT_FRONTEND_INPUTFILE_H */ #endif /* SWIFT_FRONTEND_INPUTFILE_H */

View File

@@ -427,12 +427,12 @@ bool ArgsToFrontendOptionsConverter::computeFallbackModuleName() {
OutputFilesComputer::getOutputFilenamesFromCommandLineOrFilelist(Args, OutputFilesComputer::getOutputFilenamesFromCommandLineOrFilelist(Args,
Diags); Diags);
auto nameToStem = std::string nameToStem =
outputFilenames && outputFilenames->size() == 1 && outputFilenames && outputFilenames->size() == 1 &&
outputFilenames->front() != "-" && outputFilenames->front() != "-" &&
!llvm::sys::fs::is_directory(outputFilenames->front()) !llvm::sys::fs::is_directory(outputFilenames->front())
? outputFilenames->front() ? outputFilenames->front()
: Opts.InputsAndOutputs.getFilenameOfFirstInput().str(); : Opts.InputsAndOutputs.getFilenameOfFirstInput();
Opts.ModuleName = llvm::sys::path::stem(nameToStem); Opts.ModuleName = llvm::sys::path::stem(nameToStem);
return false; return false;
@@ -441,7 +441,7 @@ bool ArgsToFrontendOptionsConverter::computeFallbackModuleName() {
bool ArgsToFrontendOptionsConverter:: bool ArgsToFrontendOptionsConverter::
computeMainAndSupplementaryOutputFilenames() { computeMainAndSupplementaryOutputFilenames() {
std::vector<std::string> mainOutputs; std::vector<std::string> mainOutputs;
SupplementaryOutputPaths supplementaryOutputs; std::vector<SupplementaryOutputPaths> supplementaryOutputs;
const bool hadError = ArgsToFrontendOutputsConverter( const bool hadError = ArgsToFrontendOutputsConverter(
Args, Opts.ModuleName, Opts.InputsAndOutputs, Diags) Args, Opts.ModuleName, Opts.InputsAndOutputs, Diags)
.convert(mainOutputs, supplementaryOutputs); .convert(mainOutputs, supplementaryOutputs);
@@ -487,9 +487,7 @@ void ArgsToFrontendOptionsConverter::computeImportObjCHeaderOptions() {
using namespace options; using namespace options;
if (const Arg *A = Args.getLastArgNoClaim(OPT_import_objc_header)) { if (const Arg *A = Args.getLastArgNoClaim(OPT_import_objc_header)) {
Opts.ImplicitObjCHeaderPath = A->getValue(); Opts.ImplicitObjCHeaderPath = A->getValue();
Opts.SerializeBridgingHeader |= Opts.SerializeBridgingHeader |= !Opts.InputsAndOutputs.hasPrimaryInputs();
!Opts.InputsAndOutputs.hasPrimaryInputs() &&
!Opts.InputsAndOutputs.supplementaryOutputs().ModuleOutputPath.empty();
} }
} }
void ArgsToFrontendOptionsConverter::computeImplicitImportModuleNames() { void ArgsToFrontendOptionsConverter::computeImplicitImportModuleNames() {

View File

@@ -33,7 +33,7 @@ using namespace llvm::opt;
bool ArgsToFrontendOutputsConverter::convert( bool ArgsToFrontendOutputsConverter::convert(
std::vector<std::string> &mainOutputs, std::vector<std::string> &mainOutputs,
SupplementaryOutputPaths &supplementaryOutputs) { std::vector<SupplementaryOutputPaths> &supplementaryOutputs) {
Optional<OutputFilesComputer> ofc = Optional<OutputFilesComputer> ofc =
OutputFilesComputer::create(Args, Diags, InputsAndOutputs); OutputFilesComputer::create(Args, Diags, InputsAndOutputs);
@@ -51,10 +51,7 @@ bool ArgsToFrontendOutputsConverter::convert(
return true; return true;
mainOutputs = std::move(*mains); mainOutputs = std::move(*mains);
assert(supplementaries->size() <= 1 && supplementaryOutputs = std::move(*supplementaries);
"Have not implemented multiple primaries yet");
if (!supplementaries->empty())
supplementaryOutputs = std::move(supplementaries->front());
return false; return false;
} }
@@ -103,9 +100,10 @@ OutputFilesComputer::create(const llvm::opt::ArgList &args,
ArrayRef<std::string> outputFileArguments = ArrayRef<std::string> outputFileArguments =
outputDirectoryArgument.empty() ? ArrayRef<std::string>(*outputArguments) outputDirectoryArgument.empty() ? ArrayRef<std::string>(*outputArguments)
: ArrayRef<std::string>(); : ArrayRef<std::string>();
const StringRef firstInput = inputsAndOutputs.hasSingleInput() const StringRef firstInput =
? inputsAndOutputs.getFilenameOfFirstInput() inputsAndOutputs.hasSingleInput()
: StringRef(); ? StringRef(inputsAndOutputs.getFilenameOfFirstInput())
: StringRef();
const FrontendOptions::ActionType requestedAction = const FrontendOptions::ActionType requestedAction =
ArgsToFrontendOptionsConverter::determineRequestedAction(args); ArgsToFrontendOptionsConverter::determineRequestedAction(args);
@@ -143,21 +141,19 @@ OutputFilesComputer::OutputFilesComputer(
Optional<std::vector<std::string>> Optional<std::vector<std::string>>
OutputFilesComputer::computeOutputFiles() const { OutputFilesComputer::computeOutputFiles() const {
std::vector<std::string> outputFiles; std::vector<std::string> outputFiles;
bool hadError = false;
unsigned i = 0; unsigned i = 0;
InputsAndOutputs.forEachInputProducingAMainOutputFile( bool hadError = InputsAndOutputs.forEachInputProducingAMainOutputFile(
[&](const InputFile &input) -> void { [&](const InputFile &input) -> bool {
StringRef outputArg = OutputFileArguments.empty() StringRef outputArg = OutputFileArguments.empty()
? StringRef() ? StringRef()
: StringRef(OutputFileArguments[i++]); : StringRef(OutputFileArguments[i++]);
Optional<std::string> outputFile = computeOutputFile(outputArg, input); Optional<std::string> outputFile = computeOutputFile(outputArg, input);
if (!outputFile) { if (!outputFile)
hadError = true; return true;
return;
}
outputFiles.push_back(*outputFile); outputFiles.push_back(*outputFile);
return false;
}); });
return hadError ? None : Optional<std::vector<std::string>>(outputFiles); return hadError ? None : Optional<std::vector<std::string>>(outputFiles);
} }
@@ -208,7 +204,7 @@ Optional<std::string> OutputFilesComputer::deriveOutputFileForDirectory(
std::string std::string
OutputFilesComputer::determineBaseNameOfOutput(const InputFile &input) const { OutputFilesComputer::determineBaseNameOfOutput(const InputFile &input) const {
StringRef nameToStem = std::string nameToStem =
input.isPrimary() input.isPrimary()
? input.file() ? input.file()
: ModuleNameArg ? ModuleNameArg->getValue() : FirstInput; : ModuleNameArg ? ModuleNameArg->getValue() : FirstInput;
@@ -256,15 +252,15 @@ SupplementaryOutputPathsComputer::computeOutputPaths() const {
std::vector<SupplementaryOutputPaths> outputPaths; std::vector<SupplementaryOutputPaths> outputPaths;
unsigned i = 0; unsigned i = 0;
bool hadError = false; bool hadError = InputsAndOutputs.forEachInputProducingSupplementaryOutput(
InputsAndOutputs.forEachInputProducingSupplementaryOutput( [&](const InputFile &input) -> bool {
[&](const InputFile &input) -> void {
if (auto suppPaths = computeOutputPathsForOneInput( if (auto suppPaths = computeOutputPathsForOneInput(
OutputFiles[i], (*pathsFromUser)[i], input)) OutputFiles[i], (*pathsFromUser)[i], input)) {
++i;
outputPaths.push_back(*suppPaths); outputPaths.push_back(*suppPaths);
else return false;
hadError = true; }
++i; return true;
}); });
if (hadError) if (hadError)
return None; return None;

View File

@@ -675,12 +675,12 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_debug_on_sil)) { if (Args.hasArg(OPT_debug_on_sil)) {
// Derive the name of the SIL file for debugging from // Derive the name of the SIL file for debugging from
// the regular outputfile. // the regular outputfile.
StringRef BaseName = FEOpts.InputsAndOutputs.getSingleOutputFilename(); std::string BaseName = FEOpts.InputsAndOutputs.getSingleOutputFilename();
// If there are no or multiple outputfiles, derive the name // If there are no or multiple outputfiles, derive the name
// from the module name. // from the module name.
if (BaseName.empty()) if (BaseName.empty())
BaseName = FEOpts.ModuleName; BaseName = FEOpts.ModuleName;
Opts.SILOutputFileNameForDebugging = BaseName.str(); Opts.SILOutputFileNameForDebugging = BaseName;
} }
if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ)) { if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ)) {

View File

@@ -56,21 +56,58 @@ std::string CompilerInvocation::getPCHHash() const {
return llvm::APInt(64, Code).toString(36, /*Signed=*/false); return llvm::APInt(64, Code).toString(36, /*Signed=*/false);
} }
PrimarySpecificPaths const PrimarySpecificPaths &
CompilerInvocation::getPrimarySpecificPathsForAtMostOnePrimary() const { CompilerInvocation::getPrimarySpecificPathsForAtMostOnePrimary() const {
return getFrontendOptions().getPrimarySpecificPathsForAtMostOnePrimary(); return getFrontendOptions().getPrimarySpecificPathsForAtMostOnePrimary();
} }
PrimarySpecificPaths CompilerInvocation::getPrimarySpecificPathsForPrimary( const PrimarySpecificPaths &
CompilerInvocation::getPrimarySpecificPathsForPrimary(
StringRef filename) const { StringRef filename) const {
return getFrontendOptions().getPrimarySpecificPathsForPrimary(filename); return getFrontendOptions().getPrimarySpecificPathsForPrimary(filename);
} }
PrimarySpecificPaths CompilerInvocation::getPrimarySpecificPathsForSourceFile( const PrimarySpecificPaths &
CompilerInvocation::getPrimarySpecificPathsForSourceFile(
const SourceFile &SF) const { const SourceFile &SF) const {
return getPrimarySpecificPathsForPrimary(SF.getFilename()); return getPrimarySpecificPathsForPrimary(SF.getFilename());
} }
std::string CompilerInvocation::getOutputFilenameForAtMostOnePrimary() const {
return getPrimarySpecificPathsForAtMostOnePrimary().OutputFilename;
}
std::string
CompilerInvocation::getMainInputFilenameForDebugInfoForAtMostOnePrimary()
const {
return getPrimarySpecificPathsForAtMostOnePrimary()
.MainInputFilenameForDebugInfo;
}
std::string
CompilerInvocation::getObjCHeaderOutputPathForAtMostOnePrimary() const {
return getPrimarySpecificPathsForAtMostOnePrimary()
.SupplementaryOutputs.ObjCHeaderOutputPath;
}
std::string CompilerInvocation::getModuleOutputPathForAtMostOnePrimary() const {
return getPrimarySpecificPathsForAtMostOnePrimary()
.SupplementaryOutputs.ModuleOutputPath;
}
std::string CompilerInvocation::getReferenceDependenciesFilePathForPrimary(
StringRef filename) const {
return getPrimarySpecificPathsForPrimary(filename)
.SupplementaryOutputs.ReferenceDependenciesFilePath;
}
std::string
CompilerInvocation::getSerializedDiagnosticsPathForAtMostOnePrimary() const {
return getPrimarySpecificPathsForAtMostOnePrimary()
.SupplementaryOutputs.SerializedDiagnosticsPath;
}
std::string CompilerInvocation::getTBDPathForWholeModule() const {
assert(getFrontendOptions().InputsAndOutputs.isWholeModule() &&
"TBDPath only makes sense in WMO mode");
return getPrimarySpecificPathsForAtMostOnePrimary()
.SupplementaryOutputs.TBDPath;
}
void CompilerInstance::createSILModule() { void CompilerInstance::createSILModule() {
assert(MainModule && "main module not created yet"); assert(MainModule && "main module not created yet");
// Assume WMO if a -primary-file option was not provided. // Assume WMO if a -primary-file option was not provided.
@@ -103,9 +140,7 @@ bool CompilerInstance::setup(const CompilerInvocation &Invok) {
// If we are asked to emit a module documentation file, configure lexing and // If we are asked to emit a module documentation file, configure lexing and
// parsing to remember comments. // parsing to remember comments.
if (!Invocation.getFrontendOptions() if (Invocation.getFrontendOptions().InputsAndOutputs.hasModuleDocOutputPath())
.InputsAndOutputs.supplementaryOutputs()
.ModuleDocOutputPath.empty())
Invocation.getLangOptions().AttachCommentsToDecls = true; Invocation.getLangOptions().AttachCommentsToDecls = true;
// If we are doing index-while-building, configure lexing and parsing to // If we are doing index-while-building, configure lexing and parsing to
@@ -240,7 +275,6 @@ bool CompilerInstance::setUpForInput(const InputFile &input) {
} }
if (input.isPrimary()) { if (input.isPrimary()) {
assert(PrimaryBufferIDs.empty() && "re-setting PrimaryBufferID");
recordPrimaryInputBuffer(*bufferID); recordPrimaryInputBuffer(*bufferID);
} }
return false; return false;
@@ -849,20 +883,21 @@ void CompilerInstance::freeASTContext() {
void CompilerInstance::freeSILModule() { TheSILModule.reset(); } void CompilerInstance::freeSILModule() { TheSILModule.reset(); }
PrimarySpecificPaths const PrimarySpecificPaths &
CompilerInstance::getPrimarySpecificPathsForWholeModuleOptimizationMode() CompilerInstance::getPrimarySpecificPathsForWholeModuleOptimizationMode()
const { const {
return getPrimarySpecificPathsForAtMostOnePrimary(); return getPrimarySpecificPathsForAtMostOnePrimary();
} }
PrimarySpecificPaths const PrimarySpecificPaths &
CompilerInstance::getPrimarySpecificPathsForAtMostOnePrimary() const { CompilerInstance::getPrimarySpecificPathsForAtMostOnePrimary() const {
return Invocation.getPrimarySpecificPathsForAtMostOnePrimary(); return Invocation.getPrimarySpecificPathsForAtMostOnePrimary();
} }
PrimarySpecificPaths const PrimarySpecificPaths &
CompilerInstance::getPrimarySpecificPathsForPrimary(StringRef filename) const { CompilerInstance::getPrimarySpecificPathsForPrimary(StringRef filename) const {
return Invocation.getPrimarySpecificPathsForPrimary(filename); return Invocation.getPrimarySpecificPathsForPrimary(filename);
} }
PrimarySpecificPaths CompilerInstance::getPrimarySpecificPathsForSourceFile( const PrimarySpecificPaths &
CompilerInstance::getPrimarySpecificPathsForSourceFile(
const SourceFile &SF) const { const SourceFile &SF) const {
return Invocation.getPrimarySpecificPathsForSourceFile(SF); return Invocation.getPrimarySpecificPathsForSourceFile(SF);
} }

View File

@@ -36,9 +36,6 @@ FrontendInputsAndOutputs::FrontendInputsAndOutputs(
for (InputFile input : other.AllInputs) for (InputFile input : other.AllInputs)
addInput(input); addInput(input);
IsSingleThreadedWMO = other.IsSingleThreadedWMO; IsSingleThreadedWMO = other.IsSingleThreadedWMO;
SupplementaryOutputs = other.SupplementaryOutputs;
PrimarySpecificPathsForAtMostOnePrimary =
other.PrimarySpecificPathsForAtMostOnePrimary;
} }
FrontendInputsAndOutputs &FrontendInputsAndOutputs:: FrontendInputsAndOutputs &FrontendInputsAndOutputs::
@@ -47,9 +44,6 @@ operator=(const FrontendInputsAndOutputs &other) {
for (InputFile input : other.AllInputs) for (InputFile input : other.AllInputs)
addInput(input); addInput(input);
IsSingleThreadedWMO = other.IsSingleThreadedWMO; IsSingleThreadedWMO = other.IsSingleThreadedWMO;
SupplementaryOutputs = other.SupplementaryOutputs;
PrimarySpecificPathsForAtMostOnePrimary =
other.PrimarySpecificPathsForAtMostOnePrimary;
return *this; return *this;
} }
@@ -67,43 +61,40 @@ bool FrontendInputsAndOutputs::isReadingFromStdin() const {
return hasSingleInput() && getFilenameOfFirstInput() == "-"; return hasSingleInput() && getFilenameOfFirstInput() == "-";
} }
StringRef FrontendInputsAndOutputs::getFilenameOfFirstInput() const { const std::string &FrontendInputsAndOutputs::getFilenameOfFirstInput() const {
assert(hasInputs()); assert(hasInputs());
const InputFile &inp = AllInputs[0]; const InputFile &inp = AllInputs[0];
StringRef f = inp.file(); const std::string &f = inp.file();
assert(!f.empty()); assert(!f.empty());
return f; return f;
} }
void FrontendInputsAndOutputs::forEachInput( bool FrontendInputsAndOutputs::forEachInput(
llvm::function_ref<void(const InputFile &)> fn) const { llvm::function_ref<bool(const InputFile &)> fn) const {
for (const InputFile &input : AllInputs) for (const InputFile &input : AllInputs)
fn(input); if (fn(input))
return true;
return false;
} }
// Primaries: // Primaries:
const InputFile &FrontendInputsAndOutputs::firstPrimaryInput() const { const InputFile &FrontendInputsAndOutputs::firstPrimaryInput() const {
assert(!PrimaryInputs.empty()); assert(!PrimaryInputsInOrder.empty());
for (const auto &f : AllInputs) return AllInputs[PrimaryInputsInOrder.front()];
if (f.isPrimary())
return f;
llvm_unreachable("no first primary?!");
} }
const InputFile &FrontendInputsAndOutputs::lastPrimaryInput() const { const InputFile &FrontendInputsAndOutputs::lastPrimaryInput() const {
assert(!PrimaryInputs.empty()); assert(!PrimaryInputsInOrder.empty());
for (const auto &f : reversed(AllInputs)) return AllInputs[PrimaryInputsInOrder.back()];
if (f.isPrimary())
return f;
llvm_unreachable("no last primary?!");
} }
void FrontendInputsAndOutputs::forEachPrimaryInput( bool FrontendInputsAndOutputs::forEachPrimaryInput(
llvm::function_ref<void(const InputFile &)> fn) const { llvm::function_ref<bool(const InputFile &)> fn) const {
for (auto &f : AllInputs) for (unsigned i : PrimaryInputsInOrder)
if (f.isPrimary()) if (fn(AllInputs[i]))
fn(f); return true;
return false;
} }
void FrontendInputsAndOutputs::assertMustNotBeMoreThanOnePrimaryInput() const { void FrontendInputsAndOutputs::assertMustNotBeMoreThanOnePrimaryInput() const {
@@ -120,8 +111,9 @@ void FrontendInputsAndOutputs::
const InputFile *FrontendInputsAndOutputs::getUniquePrimaryInput() const { const InputFile *FrontendInputsAndOutputs::getUniquePrimaryInput() const {
assertMustNotBeMoreThanOnePrimaryInput(); assertMustNotBeMoreThanOnePrimaryInput();
const auto b = PrimaryInputs.begin(); return PrimaryInputsInOrder.empty()
return b == PrimaryInputs.end() ? nullptr : &AllInputs[b->second]; ? nullptr
: &AllInputs[PrimaryInputsInOrder.front()];
} }
const InputFile & const InputFile &
@@ -131,11 +123,6 @@ FrontendInputsAndOutputs::getRequiredUniquePrimaryInput() const {
llvm_unreachable("No primary when one is required"); llvm_unreachable("No primary when one is required");
} }
StringRef FrontendInputsAndOutputs::getNameOfUniquePrimaryInputFile() const {
const auto *input = getUniquePrimaryInput();
return input == nullptr ? StringRef() : input->file();
}
std::string FrontendInputsAndOutputs::getStatsFileMangledInputName() const { std::string FrontendInputsAndOutputs::getStatsFileMangledInputName() const {
// FIXME: "batch" should probably be some concatenation of all the primary // FIXME: "batch" should probably be some concatenation of all the primary
// input names, in order to keep the stats file names unique. (Or perhaps just // input names, in order to keep the stats file names unique. (Or perhaps just
@@ -146,25 +133,18 @@ std::string FrontendInputsAndOutputs::getStatsFileMangledInputName() const {
} }
bool FrontendInputsAndOutputs::isInputPrimary(StringRef file) const { bool FrontendInputsAndOutputs::isInputPrimary(StringRef file) const {
StringRef correctedFile = return primaryInputNamed(file) != nullptr;
InputFile::convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(
file);
auto iterator = PrimaryInputs.find(correctedFile);
if (iterator == PrimaryInputs.end())
return false;
assert(AllInputs[iterator->second].isPrimary() &&
"PrimaryInputs should only hold primaries");
return true;
} }
unsigned FrontendInputsAndOutputs::numberOfPrimaryInputsEndingWith( unsigned FrontendInputsAndOutputs::numberOfPrimaryInputsEndingWith(
const char *extension) const { const char *extension) const {
return count_if( unsigned n = 0;
PrimaryInputs, [&](const llvm::StringMapEntry<unsigned> &elem) -> bool { (void)forEachPrimaryInput([&](const InputFile &input) -> bool {
StringRef filename = AllInputs[elem.second].file(); if (llvm::sys::path::extension(input.file()).endswith(extension))
++n;
return llvm::sys::path::extension(filename).endswith(extension); return false;
}); });
return n;
} }
// Input queries // Input queries
@@ -182,7 +162,7 @@ bool FrontendInputsAndOutputs::shouldTreatAsSIL() const {
if (hasSingleInput()) { if (hasSingleInput()) {
// If we have exactly one input filename, and its extension is "sil", // If we have exactly one input filename, and its extension is "sil",
// treat the input as SIL. // treat the input as SIL.
StringRef Input(getFilenameOfFirstInput()); const std::string &Input(getFilenameOfFirstInput());
return llvm::sys::path::extension(Input).endswith(SIL_EXTENSION); return llvm::sys::path::extension(Input).endswith(SIL_EXTENSION);
} }
// If we have one primary input and it's a filename with extension "sil", // If we have one primary input and it's a filename with extension "sil",
@@ -245,13 +225,17 @@ bool FrontendInputsAndOutputs::verifyInputs(DiagnosticEngine &diags,
void FrontendInputsAndOutputs::clearInputs() { void FrontendInputsAndOutputs::clearInputs() {
AllInputs.clear(); AllInputs.clear();
PrimaryInputs.clear(); PrimaryInputsByName.clear();
PrimaryInputsInOrder.clear();
} }
void FrontendInputsAndOutputs::addInput(const InputFile &input) { void FrontendInputsAndOutputs::addInput(const InputFile &input) {
if (!input.file().empty() && input.isPrimary()) const unsigned index = AllInputs.size();
PrimaryInputs.insert(std::make_pair(input.file(), AllInputs.size()));
AllInputs.push_back(input); AllInputs.push_back(input);
if (input.isPrimary()) {
PrimaryInputsInOrder.push_back(index);
PrimaryInputsByName.insert(std::make_pair(AllInputs.back().file(), index));
}
} }
void FrontendInputsAndOutputs::addInputFile(StringRef file, void FrontendInputsAndOutputs::addInputFile(StringRef file,
@@ -284,62 +268,77 @@ const InputFile &FrontendInputsAndOutputs::lastInputProducingOutput() const {
: hasPrimaryInputs() ? lastPrimaryInput() : lastInput(); : hasPrimaryInputs() ? lastPrimaryInput() : lastInput();
} }
void FrontendInputsAndOutputs::forEachInputProducingAMainOutputFile( bool FrontendInputsAndOutputs::forEachInputProducingAMainOutputFile(
llvm::function_ref<void(const InputFile &)> fn) const { llvm::function_ref<bool(const InputFile &)> fn) const {
isSingleThreadedWMO() return isSingleThreadedWMO()
? fn(firstInput()) ? fn(firstInput())
: hasPrimaryInputs() ? forEachPrimaryInput(fn) : forEachInput(fn); : hasPrimaryInputs() ? forEachPrimaryInput(fn) : forEachInput(fn);
} }
void FrontendInputsAndOutputs::setMainAndSupplementaryOutputs( void FrontendInputsAndOutputs::setMainAndSupplementaryOutputs(
ArrayRef<std::string> outputFiles, ArrayRef<std::string> outputFiles,
SupplementaryOutputPaths supplementaryOutputs) { ArrayRef<SupplementaryOutputPaths> supplementaryOutputs) {
if (AllInputs.empty()) {
assert(outputFiles.empty() && "Cannot have outputs without inputs");
assert(supplementaryOutputs.empty() &&
"Cannot have supplementary outputs without inputs");
return;
}
if (hasPrimaryInputs()) { if (hasPrimaryInputs()) {
unsigned i = 0; const auto N = primaryInputCount();
for (auto index : indices(AllInputs)) { assert(outputFiles.size() == N && "Must have one main output per primary");
InputFile &f = AllInputs[index]; assert(supplementaryOutputs.size() == N &&
if (f.isPrimary()) "Must have one set of supplementary outputs per primary");
f.setOutputFilename(outputFiles[i++]);
}
} else if (isSingleThreadedWMO()) {
AllInputs[0].setOutputFilename(outputFiles[0]);
} else {
for (auto i : indices(AllInputs))
AllInputs[i].setOutputFilename(outputFiles[i]);
}
SupplementaryOutputs = supplementaryOutputs;
if (hasUniquePrimaryInput() || (hasInputs() && isWholeModule())) { unsigned i = 0;
// When batch mode is fully implemented, each InputFile will own for (auto &input : AllInputs) {
// a PrimarySpecificPaths. if (input.isPrimary()) {
PrimarySpecificPathsForAtMostOnePrimary.OutputFilename = input.setPrimarySpecificPaths(PrimarySpecificPaths(
getSingleOutputFilename(); outputFiles[i], input.file(), supplementaryOutputs[i]));
PrimarySpecificPathsForAtMostOnePrimary.MainInputFilenameForDebugInfo = ++i;
hasInputsProducingMainOutputs() ? firstInputProducingOutput().file() }
: StringRef(); }
PrimarySpecificPathsForAtMostOnePrimary.SupplementaryOutputs = return;
supplementaryOutputs;
} }
assert(supplementaryOutputs.size() == 1 &&
"WMO only ever produces one set of supplementary outputs");
if (outputFiles.size() == 1) {
AllInputs.front().setPrimarySpecificPaths(PrimarySpecificPaths(
outputFiles.front(), firstInputProducingOutput().file(),
supplementaryOutputs.front()));
return;
}
assert(outputFiles.size() == AllInputs.size() &&
"Multi-threaded WMO requires one main output per input");
for (auto i : indices(AllInputs))
AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
outputFiles[i], outputFiles[i],
i == 0 ? supplementaryOutputs.front() : SupplementaryOutputPaths()));
} }
std::vector<std::string> FrontendInputsAndOutputs::copyOutputFilenames() const { std::vector<std::string> FrontendInputsAndOutputs::copyOutputFilenames() const {
std::vector<std::string> outputs; std::vector<std::string> outputs;
forEachInputProducingAMainOutputFile([&](const InputFile &input) -> void { (void)forEachInputProducingAMainOutputFile(
outputs.push_back(input.outputFilename()); [&](const InputFile &input) -> bool {
}); outputs.push_back(input.outputFilename());
return false;
});
return outputs; return outputs;
} }
void FrontendInputsAndOutputs::forEachOutputFilename( void FrontendInputsAndOutputs::forEachOutputFilename(
llvm::function_ref<void(const std::string &)> fn) const { llvm::function_ref<void(StringRef)> fn) const {
forEachInputProducingAMainOutputFile( (void)forEachInputProducingAMainOutputFile(
[&](const InputFile &input) -> void { fn(input.outputFilename()); }); [&](const InputFile &input) -> bool {
fn(input.outputFilename());
return false;
});
} }
StringRef FrontendInputsAndOutputs::getSingleOutputFilename() const { std::string FrontendInputsAndOutputs::getSingleOutputFilename() const {
assertMustNotBeMoreThanOnePrimaryInputUnlessBatchModeChecksHaveBeenBypassed(); assertMustNotBeMoreThanOnePrimaryInputUnlessBatchModeChecksHaveBeenBypassed();
return hasInputs() ? StringRef(lastInputProducingOutput().outputFilename()) return hasInputs() ? lastInputProducingOutput().outputFilename()
: StringRef(); : std::string();
} }
bool FrontendInputsAndOutputs::isOutputFilenameStdout() const { bool FrontendInputsAndOutputs::isOutputFilenameStdout() const {
@@ -362,34 +361,63 @@ FrontendInputsAndOutputs::countOfFilesProducingSupplementaryOutput() const {
return hasPrimaryInputs() ? primaryInputCount() : hasInputs() ? 1 : 0; return hasPrimaryInputs() ? primaryInputCount() : hasInputs() ? 1 : 0;
} }
void FrontendInputsAndOutputs::forEachInputProducingSupplementaryOutput( bool FrontendInputsAndOutputs::forEachInputProducingSupplementaryOutput(
llvm::function_ref<void(const InputFile &)> fn) const { llvm::function_ref<bool(const InputFile &)> fn) const {
if (hasPrimaryInputs()) return hasPrimaryInputs() ? forEachPrimaryInput(fn)
forEachPrimaryInput(fn); : hasInputs() ? fn(firstInput()) : false;
else if (hasInputs()) }
fn(firstInput());
bool FrontendInputsAndOutputs::hasSupplementaryOutputPath(
llvm::function_ref<const std::string &(const SupplementaryOutputPaths &)>
extractorFn) const {
return forEachInputProducingSupplementaryOutput([&](const InputFile &input)
-> bool {
return !extractorFn(input.getPrimarySpecificPaths().SupplementaryOutputs)
.empty();
});
} }
bool FrontendInputsAndOutputs::hasDependenciesPath() const { bool FrontendInputsAndOutputs::hasDependenciesPath() const {
return !supplementaryOutputs().DependenciesFilePath.empty(); return hasSupplementaryOutputPath(
[](const SupplementaryOutputPaths &outs) -> const std::string & {
return outs.DependenciesFilePath;
});
} }
bool FrontendInputsAndOutputs::hasReferenceDependenciesPath() const { bool FrontendInputsAndOutputs::hasReferenceDependenciesPath() const {
return !supplementaryOutputs().ReferenceDependenciesFilePath.empty(); return hasSupplementaryOutputPath(
[](const SupplementaryOutputPaths &outs) -> const std::string & {
return outs.ReferenceDependenciesFilePath;
});
} }
bool FrontendInputsAndOutputs::hasObjCHeaderOutputPath() const { bool FrontendInputsAndOutputs::hasObjCHeaderOutputPath() const {
return !supplementaryOutputs().ObjCHeaderOutputPath.empty(); return hasSupplementaryOutputPath(
[](const SupplementaryOutputPaths &outs) -> const std::string & {
return outs.ObjCHeaderOutputPath;
});
} }
bool FrontendInputsAndOutputs::hasLoadedModuleTracePath() const { bool FrontendInputsAndOutputs::hasLoadedModuleTracePath() const {
return !supplementaryOutputs().LoadedModuleTracePath.empty(); return hasSupplementaryOutputPath(
[](const SupplementaryOutputPaths &outs) -> const std::string & {
return outs.LoadedModuleTracePath;
});
} }
bool FrontendInputsAndOutputs::hasModuleOutputPath() const { bool FrontendInputsAndOutputs::hasModuleOutputPath() const {
return !supplementaryOutputs().ModuleOutputPath.empty(); return hasSupplementaryOutputPath(
[](const SupplementaryOutputPaths &outs) -> const std::string & {
return outs.ModuleOutputPath;
});
} }
bool FrontendInputsAndOutputs::hasModuleDocOutputPath() const { bool FrontendInputsAndOutputs::hasModuleDocOutputPath() const {
return !supplementaryOutputs().ModuleDocOutputPath.empty(); return hasSupplementaryOutputPath(
[](const SupplementaryOutputPaths &outs) -> const std::string & {
return outs.ModuleDocOutputPath;
});
} }
bool FrontendInputsAndOutputs::hasTBDPath() const { bool FrontendInputsAndOutputs::hasTBDPath() const {
return !supplementaryOutputs().TBDPath.empty(); return hasSupplementaryOutputPath(
[](const SupplementaryOutputPaths &outs) -> const std::string & {
return outs.TBDPath;
});
} }
bool FrontendInputsAndOutputs::hasDependencyTrackerPath() const { bool FrontendInputsAndOutputs::hasDependencyTrackerPath() const {
@@ -397,13 +425,31 @@ bool FrontendInputsAndOutputs::hasDependencyTrackerPath() const {
hasLoadedModuleTracePath(); hasLoadedModuleTracePath();
} }
PrimarySpecificPaths const PrimarySpecificPaths &
FrontendInputsAndOutputs::getPrimarySpecificPathsForAtMostOnePrimary() const { FrontendInputsAndOutputs::getPrimarySpecificPathsForAtMostOnePrimary() const {
return PrimarySpecificPathsForAtMostOnePrimary; assertMustNotBeMoreThanOnePrimaryInputUnlessBatchModeChecksHaveBeenBypassed();
static auto emptyPaths = PrimarySpecificPaths();
return hasInputs() ? firstInputProducingOutput().getPrimarySpecificPaths()
: emptyPaths;
} }
PrimarySpecificPaths const PrimarySpecificPaths &
FrontendInputsAndOutputs::getPrimarySpecificPathsForPrimary( FrontendInputsAndOutputs::getPrimarySpecificPathsForPrimary(
StringRef filename) const { StringRef filename) const {
return getPrimarySpecificPathsForAtMostOnePrimary(); // just a stub for now const InputFile *f = primaryInputNamed(filename);
return f->getPrimarySpecificPaths();
}
const InputFile *
FrontendInputsAndOutputs::primaryInputNamed(StringRef name) const {
assert(!name.empty() && "input files have names");
StringRef correctedFile =
InputFile::convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(
name);
auto iterator = PrimaryInputsByName.find(correctedFile);
if (iterator == PrimaryInputsByName.end())
return nullptr;
const InputFile *f = &AllInputs[iterator->second];
assert(f->isPrimary() && "PrimaryInputsByName should only include primries");
return f;
} }

View File

@@ -108,7 +108,7 @@ bool FrontendOptions::shouldActionOnlyParse(ActionType action) {
} }
void FrontendOptions::forAllOutputPaths( void FrontendOptions::forAllOutputPaths(
const InputFile &input, std::function<void(const std::string &)> fn) const { const InputFile &input, std::function<void(StringRef)> fn) const {
if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly && if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly &&
RequestedAction != FrontendOptions::ActionType::MergeModules) { RequestedAction != FrontendOptions::ActionType::MergeModules) {
if (InputsAndOutputs.isWholeModule()) if (InputsAndOutputs.isWholeModule())
@@ -116,28 +116,19 @@ void FrontendOptions::forAllOutputPaths(
else else
fn(input.outputFilename()); fn(input.outputFilename());
} }
const std::string *outputs[] = { (void)InputsAndOutputs.forEachInputProducingSupplementaryOutput(
&InputsAndOutputs.supplementaryOutputs().ModuleOutputPath, [&](const InputFile &inp) -> bool {
&InputsAndOutputs.supplementaryOutputs().ModuleDocOutputPath, const SupplementaryOutputPaths &outs =
&InputsAndOutputs.supplementaryOutputs().ObjCHeaderOutputPath}; inp.getPrimarySpecificPaths().SupplementaryOutputs;
for (const std::string *next : outputs) { const std::string *outputs[] = {&outs.ModuleOutputPath,
if (!next->empty()) &outs.ModuleDocOutputPath,
fn(*next); &outs.ObjCHeaderOutputPath};
} for (const std::string *next : outputs) {
} if (!next->empty())
fn(*next);
}
StringRef FrontendOptions::originalPath() const { return false;
if (InputsAndOutputs.hasNamedOutputFile()) });
// Put the serialized diagnostics file next to the output file.
return InputsAndOutputs.getSingleOutputFilename();
// If we have a primary input, so use that as the basis for the name of the
// serialized diagnostics file, otherwise fall back on the
// module name.
const auto input = InputsAndOutputs.getUniquePrimaryInput();
return input ? llvm::sys::path::filename(input->file())
: StringRef(ModuleName);
} }
const char * const char *
@@ -387,12 +378,12 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) {
} }
} }
PrimarySpecificPaths const PrimarySpecificPaths &
FrontendOptions::getPrimarySpecificPathsForAtMostOnePrimary() const { FrontendOptions::getPrimarySpecificPathsForAtMostOnePrimary() const {
return InputsAndOutputs.getPrimarySpecificPathsForAtMostOnePrimary(); return InputsAndOutputs.getPrimarySpecificPathsForAtMostOnePrimary();
} }
PrimarySpecificPaths const PrimarySpecificPaths &
FrontendOptions::getPrimarySpecificPathsForPrimary(StringRef filename) const { FrontendOptions::getPrimarySpecificPathsForPrimary(StringRef filename) const {
return InputsAndOutputs.getPrimarySpecificPathsForPrimary(filename); return InputsAndOutputs.getPrimarySpecificPathsForPrimary(filename);
} }

View File

@@ -99,20 +99,20 @@ static std::string displayName(StringRef MainExecutablePath) {
} }
/// Emits a Make-style dependencies file. /// Emits a Make-style dependencies file.
static bool emitMakeDependencies(DiagnosticEngine &diags, static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
DependencyTracker &depTracker, DependencyTracker *depTracker,
const FrontendOptions &opts, const FrontendOptions &opts,
const InputFile &input) { const InputFile &input) {
const std::string &dependenciesFilePath = input.dependenciesFilePath();
if (dependenciesFilePath.empty())
return false;
std::error_code EC; std::error_code EC;
llvm::raw_fd_ostream out( llvm::raw_fd_ostream out(dependenciesFilePath, EC, llvm::sys::fs::F_None);
opts.InputsAndOutputs.supplementaryOutputs().DependenciesFilePath, EC,
llvm::sys::fs::F_None);
if (out.has_error() || EC) { if (out.has_error() || EC) {
diags.diagnose( diags.diagnose(SourceLoc(), diag::error_opening_output,
SourceLoc(), diag::error_opening_output, dependenciesFilePath, EC.message());
opts.InputsAndOutputs.supplementaryOutputs().DependenciesFilePath,
EC.message());
out.clear_error(); out.clear_error();
return true; return true;
} }
@@ -139,7 +139,7 @@ static bool emitMakeDependencies(DiagnosticEngine &diags,
// FIXME: Xcode can't currently handle multiple targets in a single // FIXME: Xcode can't currently handle multiple targets in a single
// dependency line. // dependency line.
opts.forAllOutputPaths(input, [&](StringRef targetName) { opts.forAllOutputPaths(input, [&](const StringRef targetName) {
out << escape(targetName) << " :"; out << escape(targetName) << " :";
// First include all other files in the module. Make-style dependencies // First include all other files in the module. Make-style dependencies
// need to be conservative! // need to be conservative!
@@ -148,7 +148,7 @@ static bool emitMakeDependencies(DiagnosticEngine &diags,
out << ' ' << escape(path); out << ' ' << escape(path);
// Then print dependencies we've picked up during compilation. // Then print dependencies we've picked up during compilation.
for (auto const &path : for (auto const &path :
reversePathSortedFilenames(depTracker.getDependencies())) reversePathSortedFilenames(depTracker->getDependencies()))
out << ' ' << escape(path); out << ' ' << escape(path);
out << '\n'; out << '\n';
}); });
@@ -156,15 +156,13 @@ static bool emitMakeDependencies(DiagnosticEngine &diags,
return false; return false;
} }
static bool emitMakeDependencies(DiagnosticEngine &diags, static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
DependencyTracker &depTracker, DependencyTracker *depTracker,
const FrontendOptions &opts) { const FrontendOptions &opts) {
bool hadError = false; return opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput( [&](const InputFile &f) -> bool {
[&](const InputFile &f) -> void { return emitMakeDependenciesIfNeeded(diags, depTracker, opts, f);
hadError = emitMakeDependencies(diags, depTracker, opts, f) || hadError;
}); });
return hadError;
} }
namespace { namespace {
@@ -189,20 +187,16 @@ template <> struct ObjectTraits<LoadedModuleTraceFormat> {
static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt, static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt,
DependencyTracker *depTracker, DependencyTracker *depTracker,
const FrontendOptions &opts) { StringRef loadedModuleTracePath,
if (opts.InputsAndOutputs.supplementaryOutputs() StringRef moduleName) {
.LoadedModuleTracePath.empty()) if (loadedModuleTracePath.empty())
return false; return false;
std::error_code EC; std::error_code EC;
llvm::raw_fd_ostream out( llvm::raw_fd_ostream out(loadedModuleTracePath, EC, llvm::sys::fs::F_Append);
opts.InputsAndOutputs.supplementaryOutputs().LoadedModuleTracePath, EC,
llvm::sys::fs::F_Append);
if (out.has_error() || EC) { if (out.has_error() || EC) {
ctxt.Diags.diagnose( ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
SourceLoc(), diag::error_opening_output, loadedModuleTracePath, EC.message());
opts.InputsAndOutputs.supplementaryOutputs().LoadedModuleTracePath,
EC.message());
out.clear_error(); out.clear_error();
return true; return true;
} }
@@ -235,7 +229,7 @@ static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt,
} }
LoadedModuleTraceFormat trace = { LoadedModuleTraceFormat trace = {
/*name=*/opts.ModuleName, /*name=*/moduleName,
/*arch=*/ctxt.LangOpts.Target.getArchName(), /*arch=*/ctxt.LangOpts.Target.getArchName(),
/*swiftmodules=*/reversePathSortedFilenames(swiftModules)}; /*swiftmodules=*/reversePathSortedFilenames(swiftModules)};
@@ -255,6 +249,16 @@ static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt,
return true; return true;
} }
static bool
emitLoadedModuleTraceForAllPrimariesIfNeeded(ASTContext &ctxt,
DependencyTracker *depTracker,
const FrontendOptions &opts) {
return opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
[&](const InputFile &input) -> bool {
return emitLoadedModuleTraceIfNeeded(
ctxt, depTracker, input.loadedModuleTracePath(), opts.ModuleName);
});
}
/// Gets an output stream for the provided output filename, or diagnoses to the /// Gets an output stream for the provided output filename, or diagnoses to the
/// provided AST Context and returns null if there was an error getting the /// provided AST Context and returns null if there was an error getting the
@@ -306,7 +310,7 @@ static bool writeSIL(SILModule &SM, const PrimarySpecificPaths &PSPs,
PSPs.OutputFilename, opts.EmitSortedSIL); PSPs.OutputFilename, opts.EmitSortedSIL);
} }
static bool printAsObjCIfNeeded(const std::string &outputPath, ModuleDecl *M, static bool printAsObjCIfNeeded(StringRef outputPath, ModuleDecl *M,
StringRef bridgingHeader, bool moduleIsPublic) { StringRef bridgingHeader, bool moduleIsPublic) {
using namespace llvm::sys; using namespace llvm::sys;
@@ -739,19 +743,18 @@ static Optional<bool> dumpASTIfNeeded(CompilerInvocation &Invocation,
static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded( static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded(
CompilerInvocation &Invocation, CompilerInstance &Instance) { CompilerInvocation &Invocation, CompilerInstance &Instance) {
if (Invocation.getFrontendOptions() if (Invocation.getFrontendOptions()
.InputsAndOutputs.supplementaryOutputs() .InputsAndOutputs.hasReferenceDependenciesPath() &&
.ReferenceDependenciesFilePath.empty()) Instance.getPrimarySourceFiles().empty()) {
return;
if (Instance.getPrimarySourceFiles().empty()) {
Instance.getASTContext().Diags.diagnose( Instance.getASTContext().Diags.diagnose(
SourceLoc(), diag::emit_reference_dependencies_without_primary_file); SourceLoc(), diag::emit_reference_dependencies_without_primary_file);
return; return;
} }
for (auto *SF : Instance.getPrimarySourceFiles()) { for (auto *SF : Instance.getPrimarySourceFiles()) {
std::string referenceDependenciesFilePath = const std::string &referenceDependenciesFilePath =
Invocation.getPrimarySpecificPathsForSourceFile(*SF) Invocation.getReferenceDependenciesFilePathForPrimary(
.SupplementaryOutputs.ReferenceDependenciesFilePath; SF->getFilename());
emitReferenceDependenciesIfNeeded(Instance.getASTContext().Diags, SF, if (!referenceDependenciesFilePath.empty())
(void)emitReferenceDependencies(Instance.getASTContext().Diags, SF,
*Instance.getDependencyTracker(), *Instance.getDependencyTracker(),
referenceDependenciesFilePath); referenceDependenciesFilePath);
} }
@@ -759,11 +762,13 @@ static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded(
static bool writeTBDIfNeeded(CompilerInvocation &Invocation, static bool writeTBDIfNeeded(CompilerInvocation &Invocation,
CompilerInstance &Instance) { CompilerInstance &Instance) {
StringRef TBDPath = Invocation.getFrontendOptions() if (!Invocation.getFrontendOptions().InputsAndOutputs.hasTBDPath())
.InputsAndOutputs.supplementaryOutputs()
.TBDPath;
if (TBDPath.empty())
return false; return false;
const std::string &TBDPath = Invocation.getTBDPathForWholeModule();
assert(!TBDPath.empty() &&
"If not WMO, getTBDPathForWholeModule should have failed");
auto installName = Invocation.getFrontendOptions().TBDInstallName.empty() auto installName = Invocation.getFrontendOptions().TBDInstallName.empty()
? "lib" + Invocation.getModuleName().str() + ".dylib" ? "lib" + Invocation.getModuleName().str() + ".dylib"
: Invocation.getFrontendOptions().TBDInstallName; : Invocation.getFrontendOptions().TBDInstallName;
@@ -822,7 +827,7 @@ generateSILModules(CompilerInvocation &Invocation, CompilerInstance &Instance) {
SASTF->getFilename())) { SASTF->getFilename())) {
assert(PSGIs.empty() && "Can only handle one primary AST input"); assert(PSGIs.empty() && "Can only handle one primary AST input");
auto SM = performSILGeneration(*SASTF, SILOpts, None); auto SM = performSILGeneration(*SASTF, SILOpts, None);
const PrimarySpecificPaths PSPs = const PrimarySpecificPaths &PSPs =
Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename()); Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename());
PSGIs.push_back( PSGIs.push_back(
PostSILGenInputs{std::move(SM), !fileIsSIB(SASTF), mod, PSPs}); PostSILGenInputs{std::move(SM), !fileIsSIB(SASTF), mod, PSPs});
@@ -831,6 +836,18 @@ generateSILModules(CompilerInvocation &Invocation, CompilerInstance &Instance) {
return PSGIs; return PSGIs;
} }
/// Emits index data for all primary inputs, or the main module.
static bool
emitIndexData(CompilerInvocation &Invocation, CompilerInstance &Instance) {
bool hadEmitIndexDataError = false;
if (Instance.getPrimarySourceFiles().empty())
return emitIndexDataIfNeeded(nullptr, Invocation, Instance);
for (SourceFile *SF : Instance.getPrimarySourceFiles())
hadEmitIndexDataError = emitIndexDataIfNeeded(SF, Invocation, Instance) ||
hadEmitIndexDataError;
return hadEmitIndexDataError;
}
static bool performCompileStepsPostSILGen( static bool performCompileStepsPostSILGen(
CompilerInstance &Instance, CompilerInvocation &Invocation, CompilerInstance &Instance, CompilerInvocation &Invocation,
std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL, std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL,
@@ -905,20 +922,17 @@ static bool performCompile(CompilerInstance &Instance,
if (opts.PrintClangStats && Context.getClangModuleLoader()) if (opts.PrintClangStats && Context.getClangModuleLoader())
Context.getClangModuleLoader()->printStatistics(); Context.getClangModuleLoader()->printStatistics();
if (!opts.InputsAndOutputs.supplementaryOutputs() (void)emitMakeDependenciesIfNeeded(Context.Diags,
.DependenciesFilePath.empty()) Instance.getDependencyTracker(), opts);
(void)emitMakeDependencies(Context.Diags, *Instance.getDependencyTracker(),
opts);
emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Invocation, Instance); emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Invocation, Instance);
(void)emitLoadedModuleTraceIfNeeded(Context, Instance.getDependencyTracker(), (void)emitLoadedModuleTraceForAllPrimariesIfNeeded(
opts); Context, Instance.getDependencyTracker(), opts);
if (Context.hadError()) { if (Context.hadError()) {
// Emit the index store data even if there were compiler errors. // Emit the index store data even if there were compiler errors.
(void)emitIndexDataIfNeeded(Instance.getPrimarySourceFile(), Invocation, (void)emitIndexData(Invocation, Instance);
Instance);
return true; return true;
} }
@@ -932,11 +946,11 @@ static bool performCompile(CompilerInstance &Instance,
// We've just been told to perform a typecheck, so we can return now. // We've just been told to perform a typecheck, so we can return now.
if (Action == FrontendOptions::ActionType::Typecheck) { if (Action == FrontendOptions::ActionType::Typecheck) {
const bool hadPrintAsObjCError = printAsObjCIfNeeded( const bool hadPrintAsObjCError = printAsObjCIfNeeded(
opts.InputsAndOutputs.supplementaryOutputs().ObjCHeaderOutputPath, Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(),
Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic);
const bool hadEmitIndexDataError = emitIndexDataIfNeeded( const bool hadEmitIndexDataError = emitIndexData(Invocation, Instance);
Instance.getPrimarySourceFile(), Invocation, Instance);
return hadPrintAsObjCError || hadEmitIndexDataError || Context.hadError(); return hadPrintAsObjCError || hadEmitIndexDataError || Context.hadError();
} }
@@ -1008,7 +1022,7 @@ computeSerializationOptions(const CompilerInvocation &Invocation,
serializationOpts.OutputPath = outs.ModuleOutputPath.c_str(); serializationOpts.OutputPath = outs.ModuleOutputPath.c_str();
serializationOpts.DocOutputPath = outs.ModuleDocOutputPath.c_str(); serializationOpts.DocOutputPath = outs.ModuleDocOutputPath.c_str();
serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str(); serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str();
if (opts.SerializeBridgingHeader) if (opts.SerializeBridgingHeader && !outs.ModuleOutputPath.empty())
serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath; serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath;
serializationOpts.ModuleLinkName = opts.ModuleLinkName; serializationOpts.ModuleLinkName = opts.ModuleLinkName;
serializationOpts.ExtraClangOptions = serializationOpts.ExtraClangOptions =
@@ -1144,7 +1158,7 @@ static bool validateTBDIfNeeded(CompilerInvocation &Invocation,
} }
static bool generateCode(CompilerInvocation &Invocation, static bool generateCode(CompilerInvocation &Invocation,
CompilerInstance &Instance, std::string OutputFilename, CompilerInstance &Instance, StringRef OutputFilename,
llvm::Module *IRModule, llvm::Module *IRModule,
llvm::GlobalVariable *HashGlobal, llvm::GlobalVariable *HashGlobal,
UnifiedStatsReporter *Stats) { UnifiedStatsReporter *Stats) {
@@ -1263,21 +1277,21 @@ static bool performCompileStepsPostSILGen(
if (Action == FrontendOptions::ActionType::EmitSIB) if (Action == FrontendOptions::ActionType::EmitSIB)
return serializeSIB(SM.get(), PSPs, Instance.getASTContext(), MSF); return serializeSIB(SM.get(), PSPs, Instance.getASTContext(), MSF);
const bool haveModulePath = {
!PSPs.SupplementaryOutputs.ModuleOutputPath.empty() || const bool haveModulePath = PSPs.haveModuleOrModuleDocOutputPaths();
!PSPs.SupplementaryOutputs.ModuleDocOutputPath.empty(); if (haveModulePath && !SM->isSerialized())
if (haveModulePath && !SM->isSerialized()) SM->serialize();
SM->serialize();
if (haveModulePath) { if (haveModulePath) {
if (Action == FrontendOptions::ActionType::MergeModules || if (Action == FrontendOptions::ActionType::MergeModules ||
Action == FrontendOptions::ActionType::EmitModuleOnly) { Action == FrontendOptions::ActionType::EmitModuleOnly) {
// What if MSF is a module? // What if MSF is a module?
// emitIndexDataIfNeeded already handles that case; // emitIndexDataIfNeeded already handles that case;
// it'll index everything. // it'll index everything.
return emitIndexDataIfNeeded(MSF.dyn_cast<SourceFile *>(), Invocation, return emitIndexDataIfNeeded(MSF.dyn_cast<SourceFile *>(), Invocation,
Instance) || Instance) ||
Context.hadError(); Context.hadError();
}
} }
} }
@@ -1360,15 +1374,18 @@ static bool emitIndexDataIfNeeded(SourceFile *PrimarySourceFile,
} }
if (PrimarySourceFile) { if (PrimarySourceFile) {
if (index::indexAndRecord( const PrimarySpecificPaths &PSPs =
PrimarySourceFile, opts.InputsAndOutputs.getSingleOutputFilename(), opts.InputsAndOutputs.getPrimarySpecificPathsForPrimary(
opts.IndexStorePath, opts.IndexSystemModules, isDebugCompilation, PrimarySourceFile->getFilename());
Invocation.getTargetTriple(), *Instance.getDependencyTracker())) { if (index::indexAndRecord(PrimarySourceFile, PSPs.OutputFilename,
opts.IndexStorePath, opts.IndexSystemModules,
isDebugCompilation, Invocation.getTargetTriple(),
*Instance.getDependencyTracker())) {
return true; return true;
} }
} else { } else {
StringRef moduleToken = std::string moduleToken =
opts.InputsAndOutputs.supplementaryOutputs().ModuleOutputPath; Invocation.getModuleOutputPathForAtMostOnePrimary();
if (moduleToken.empty()) if (moduleToken.empty())
moduleToken = opts.InputsAndOutputs.getSingleOutputFilename(); moduleToken = opts.InputsAndOutputs.getSingleOutputFilename();
@@ -1472,7 +1489,7 @@ computeStatsReporter(const CompilerInvocation &Invocation, CompilerInstance *Ins
std::string InputName = std::string InputName =
FEOpts.InputsAndOutputs.getStatsFileMangledInputName(); FEOpts.InputsAndOutputs.getStatsFileMangledInputName();
StringRef OptType = silOptModeArgStr(SILOpts.OptMode); StringRef OptType = silOptModeArgStr(SILOpts.OptMode);
StringRef OutFile = const std::string &OutFile =
FEOpts.InputsAndOutputs.lastInputProducingOutput().outputFilename(); FEOpts.InputsAndOutputs.lastInputProducingOutput().outputFilename();
StringRef OutputType = llvm::sys::path::extension(OutFile); StringRef OutputType = llvm::sys::path::extension(OutFile);
std::string TripleName = LangOpts.Target.normalize(); std::string TripleName = LangOpts.Target.normalize();
@@ -1606,12 +1623,13 @@ int swift::performFrontend(ArrayRef<const char *> Args,
// arguments are generated by the driver, not directly by a user. The driver // arguments are generated by the driver, not directly by a user. The driver
// is responsible for emitting diagnostics for its own errors. See SR-2683 // is responsible for emitting diagnostics for its own errors. See SR-2683
// for details. // for details.
//
// FIXME: Do we need one SerializedConsumer per primary? Owned by the
// SourceFile?
std::unique_ptr<DiagnosticConsumer> SerializedConsumer; std::unique_ptr<DiagnosticConsumer> SerializedConsumer;
{ {
const std::string &SerializedDiagnosticsPath = const std::string &SerializedDiagnosticsPath =
Invocation.getFrontendOptions() Invocation.getSerializedDiagnosticsPathForAtMostOnePrimary();
.InputsAndOutputs.supplementaryOutputs()
.SerializedDiagnosticsPath;
if (!SerializedDiagnosticsPath.empty()) { if (!SerializedDiagnosticsPath.empty()) {
SerializedConsumer.reset( SerializedConsumer.reset(
serialized_diagnostics::createConsumer(SerializedDiagnosticsPath)); serialized_diagnostics::createConsumer(SerializedDiagnosticsPath));
@@ -1646,17 +1664,13 @@ int swift::performFrontend(ArrayRef<const char *> Args,
} }
DependencyTracker depTracker; DependencyTracker depTracker;
if (!Invocation.getFrontendOptions() {
.InputsAndOutputs.supplementaryOutputs() const FrontendInputsAndOutputs &io =
.DependenciesFilePath.empty() || Invocation.getFrontendOptions().InputsAndOutputs;
!Invocation.getFrontendOptions() if (io.hasDependencyTrackerPath() ||
.InputsAndOutputs.supplementaryOutputs() !Invocation.getFrontendOptions().IndexStorePath.empty()) {
.ReferenceDependenciesFilePath.empty() || Instance->setDependencyTracker(&depTracker);
!Invocation.getFrontendOptions().IndexStorePath.empty() || }
!Invocation.getFrontendOptions()
.InputsAndOutputs.supplementaryOutputs()
.LoadedModuleTracePath.empty()) {
Instance->setDependencyTracker(&depTracker);
} }
if (Instance->setup(Invocation)) { if (Instance->setup(Invocation)) {

View File

@@ -46,7 +46,7 @@ static void findAllClangImports(const clang::Module *module,
bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule,
const FrontendOptions &opts) { const FrontendOptions &opts) {
auto path = opts.InputsAndOutputs.getSingleOutputFilename(); std::string path = opts.InputsAndOutputs.getSingleOutputFilename();
std::error_code EC; std::error_code EC;
llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None); llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None);

View File

@@ -123,20 +123,11 @@ swift::reversePathSortedFilenames(const ArrayRef<std::string> elts) {
return tmp; return tmp;
} }
bool swift::emitReferenceDependenciesIfNeeded(DiagnosticEngine &diags, bool swift::emitReferenceDependencies(DiagnosticEngine &diags, SourceFile *SF,
SourceFile *SF, DependencyTracker &depTracker,
DependencyTracker &depTracker, StringRef outputPath) {
StringRef outputPath) {
assert(SF && "Cannot emit reference dependencies without a SourceFile"); assert(SF && "Cannot emit reference dependencies without a SourceFile");
const ReferencedNameTracker *const tracker = SF->getReferencedNameTracker();
if (!tracker) {
assert(outputPath.empty());
return false;
}
assert(!outputPath.empty());
// Before writing to the dependencies file path, preserve any previous file // Before writing to the dependencies file path, preserve any previous file
// that may have been there. No error handling -- this is just a nicety, it // that may have been there. No error handling -- this is just a nicety, it
// doesn't matter if it fails. // doesn't matter if it fails.
@@ -342,6 +333,9 @@ bool swift::emitReferenceDependenciesIfNeeded(DiagnosticEngine &diags,
return pairs; return pairs;
}; };
const ReferencedNameTracker *const tracker = SF->getReferencedNameTracker();
assert(tracker && "Cannot emit reference dependencies without a tracker");
out << "depends-top-level:\n"; out << "depends-top-level:\n";
for (auto &entry : sortedByName(tracker->getTopLevelNames())) { for (auto &entry : sortedByName(tracker->getTopLevelNames())) {
assert(!entry.first.empty()); assert(!entry.first.empty());

View File

@@ -32,9 +32,9 @@ std::vector<std::string>
reversePathSortedFilenames(const llvm::ArrayRef<std::string> paths); reversePathSortedFilenames(const llvm::ArrayRef<std::string> paths);
/// Emit a Swift-style dependencies file for \p SF. /// Emit a Swift-style dependencies file for \p SF.
bool emitReferenceDependenciesIfNeeded(DiagnosticEngine &diags, SourceFile *SF, bool emitReferenceDependencies(DiagnosticEngine &diags, SourceFile *SF,
DependencyTracker &depTracker, DependencyTracker &depTracker,
StringRef outputPath); StringRef outputPath);
} // end namespace swift } // end namespace swift
#endif #endif

View File

@@ -24,8 +24,8 @@ class ModuleDecl;
class FileUnit; class FileUnit;
class FrontendOptions; class FrontendOptions;
bool writeTBD(ModuleDecl *M, bool hasMultipleIGMs, bool writeTBD(ModuleDecl *M, bool hasMultipleIGMs, StringRef OutputFilename,
llvm::StringRef OutputFilename, llvm::StringRef installName); llvm::StringRef installName);
bool inputFileKindCanHaveTBDValidated(InputFileKind kind); bool inputFileKindCanHaveTBDValidated(InputFileKind kind);
bool validateTBD(ModuleDecl *M, llvm::Module &IRModule, bool hasMultipleIGMs, bool validateTBD(ModuleDecl *M, llvm::Module &IRModule, bool hasMultipleIGMs,
bool diagnoseExtraSymbolsInTBD); bool diagnoseExtraSymbolsInTBD);

View File

@@ -665,8 +665,7 @@ static void initLLVMModule(const IRGenModule &IGM) {
} }
std::pair<IRGenerator *, IRGenModule *> std::pair<IRGenerator *, IRGenModule *>
swift::irgen::createIRGenModule(SILModule *SILMod, swift::irgen::createIRGenModule(SILModule *SILMod, StringRef OutputFilename,
StringRef OutputFilename,
StringRef MainInputFilenameForDebugInfo, StringRef MainInputFilenameForDebugInfo,
llvm::LLVMContext &LLVMContext) { llvm::LLVMContext &LLVMContext) {

View File

@@ -1049,11 +1049,9 @@ public:
/// ///
/// The \p SF is the source file for which the llvm module is generated when /// The \p SF is the source file for which the llvm module is generated when
/// doing multi-threaded whole-module compilation. Otherwise it is null. /// doing multi-threaded whole-module compilation. Otherwise it is null.
IRGenModule(IRGenerator &irgen, IRGenModule(IRGenerator &irgen, std::unique_ptr<llvm::TargetMachine> &&target,
std::unique_ptr<llvm::TargetMachine> &&target,
SourceFile *SF, llvm::LLVMContext &LLVMContext, SourceFile *SF, llvm::LLVMContext &LLVMContext,
StringRef ModuleName, StringRef ModuleName, StringRef OutputFilename,
StringRef OutputFilename,
StringRef MainInputFilenameForDebugInfo); StringRef MainInputFilenameForDebugInfo);
~IRGenModule(); ~IRGenModule();

View File

@@ -897,10 +897,11 @@ private:
if (!ShouldRun) if (!ShouldRun)
return true; return true;
const PrimarySpecificPaths PSPs =
CI.getPrimarySpecificPathsForAtMostOnePrimary();
// IRGen the current line(s). // IRGen the current line(s).
// FIXME: We shouldn't need to use the global context here, but // FIXME: We shouldn't need to use the global context here, but
// something is persisting across calls to performIRGeneration. // something is persisting across calls to performIRGeneration.
const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary();
auto LineModule = performIRGeneration( auto LineModule = performIRGeneration(
IRGenOpts, REPLInputFile, std::move(sil), "REPLLine", PSPs, IRGenOpts, REPLInputFile, std::move(sil), "REPLLine", PSPs,
getGlobalLLVMContext(), RC.CurIRGenElem); getGlobalLLVMContext(), RC.CurIRGenElem);

View File

@@ -439,7 +439,6 @@ bool SwiftASTManager::initCompilerInvocation(CompilerInvocation &Invocation,
ImporterOpts.DetailedPreprocessingRecord = true; ImporterOpts.DetailedPreprocessingRecord = true;
assert(!Invocation.getModuleName().empty()); assert(!Invocation.getModuleName().empty());
Invocation.setSerializedDiagnosticsPath(StringRef());
Invocation.getLangOptions().AttachCommentsToDecls = true; Invocation.getLangOptions().AttachCommentsToDecls = true;
Invocation.getLangOptions().DiagnosticsEditorMode = true; Invocation.getLangOptions().DiagnosticsEditorMode = true;
Invocation.getLangOptions().CollectParsedToken = true; Invocation.getLangOptions().CollectParsedToken = true;
@@ -700,7 +699,7 @@ bool ASTProducer::shouldRebuild(SwiftASTManager::Implementation &MgrImpl,
Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount()); Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
for (const auto &input : for (const auto &input :
Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) { Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
StringRef File = input.file(); const std::string &File = input.file();
bool FoundSnapshot = false; bool FoundSnapshot = false;
for (auto &Snap : Snapshots) { for (auto &Snap : Snapshots) {
if (Snap->getFilename() == File) { if (Snap->getFilename() == File) {
@@ -887,7 +886,7 @@ void ASTProducer::findSnapshotAndOpenFiles(
const InvocationOptions &Opts = InvokRef->Impl.Opts; const InvocationOptions &Opts = InvokRef->Impl.Opts;
for (const auto &input : for (const auto &input :
Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) { Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
StringRef File = input.file(); const std::string &File = input.file();
bool IsPrimary = input.isPrimary(); bool IsPrimary = input.isPrimary();
bool FoundSnapshot = false; bool FoundSnapshot = false;
for (auto &Snap : Snapshots) { for (auto &Snap : Snapshots) {

View File

@@ -427,9 +427,9 @@ int main(int argc, char **argv) {
} else { } else {
auto *SILMod = CI.getSILModule(); auto *SILMod = CI.getSILModule();
{ {
const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary();
auto T = irgen::createIRGenModule( auto T = irgen::createIRGenModule(
SILMod, PSPs.OutputFilename, PSPs.MainInputFilenameForDebugInfo, SILMod, Invocation.getOutputFilenameForAtMostOnePrimary(),
Invocation.getMainInputFilenameForDebugInfoForAtMostOnePrimary(),
getGlobalLLVMContext()); getGlobalLLVMContext());
runCommandLineSelectedPasses(SILMod, T.second); runCommandLineSelectedPasses(SILMod, T.second);
irgen::deleteIRGenModule(T); irgen::deleteIRGenModule(T);