Merge pull request #13268 from davidungar/PR3A-rb

FrontendInputs data structure redo, rebased.
This commit is contained in:
David Ungar
2017-12-11 20:44:10 -08:00
committed by GitHub
30 changed files with 626 additions and 599 deletions

View File

@@ -121,41 +121,9 @@ class ArgsToFrontendInputsConverter {
std::unique_ptr<llvm::MemoryBuffer> FilelistBuffer;
llvm::StringMap<unsigned> FileIndices;
std::vector<StringRef> PrimaryFiles;
StringRef filelistPath() { return FilelistPathArg->getValue(); }
void addPrimary(StringRef file) { PrimaryFiles.push_back(file); }
void addInput(StringRef file) {
FileIndices.insert({file, Inputs.inputFilenameCount()});
Inputs.addInputFilename(file);
}
bool arePrimariesOnCommandLineAlsoAppearingInFilelist() {
return FilelistPathArg != nullptr;
}
enum class Whence {
PrimaryFromCommandLine,
SecondaryFromCommandLine,
SecondaryFromFileList
};
void addFile(StringRef file, Whence whence) {
switch (whence) {
case Whence::PrimaryFromCommandLine:
addPrimary(file);
if (!arePrimariesOnCommandLineAlsoAppearingInFilelist())
addInput(file);
break;
case Whence::SecondaryFromCommandLine:
case Whence::SecondaryFromFileList:
addInput(file);
break;
}
}
llvm::SetVector<StringRef> Files;
public:
ArgsToFrontendInputsConverter(DiagnosticEngine &Diags, const ArgList &Args,
@@ -166,36 +134,62 @@ public:
bool convert() {
if (enforceFilelistExclusion())
return true;
getFilesFromCommandLine();
if (getFilesFromFilelist())
bool hadError = getFilesFromCommandLine();
if (hadError)
return true;
return setPrimaryFiles();
hadError = getFilesFromFilelist();
if (hadError)
return true;
llvm::StringSet<> PrimaryFiles = getPrimaries();
for (auto file : Files) {
bool isPrimary = PrimaryFiles.count(file) > 0;
Inputs.addInput(InputFile(file, isPrimary));
if (isPrimary)
PrimaryFiles.erase(file);
}
for (auto &file : PrimaryFiles) {
// Catch "swiftc -frontend -c -filelist foo -primary-file
// some-file-not-in-foo".
assert(doesCommandLineIncludeFilelist() &&
"Missing primary with no filelist");
Diags.diagnose(SourceLoc(), diag::error_primary_file_not_found,
file.getKey(), filelistPath());
}
return !PrimaryFiles.empty();
}
private:
bool enforceFilelistExclusion() {
if (Args.hasArg(options::OPT_INPUT) && FilelistPathArg != nullptr) {
if (Args.hasArg(options::OPT_INPUT) && doesCommandLineIncludeFilelist()) {
Diags.diagnose(SourceLoc(),
diag::error_cannot_have_input_files_with_file_list);
return true;
}
return false;
}
void getFilesFromCommandLine() {
bool getFilesFromCommandLine() {
bool hadDuplicates = false;
for (const Arg *A :
Args.filtered(options::OPT_INPUT, options::OPT_primary_file)) {
StringRef file = A->getValue();
if (A->getOption().matches(options::OPT_INPUT))
addFile(file, Whence::SecondaryFromCommandLine);
else if (A->getOption().matches(options::OPT_primary_file))
addFile(file, Whence::PrimaryFromCommandLine);
else
llvm_unreachable("Unknown input-related argument!");
if (A->getOption().matches(options::OPT_primary_file) &&
mustPrimaryFilesOnCommandLineAlsoAppearInFileList())
continue;
hadDuplicates = addFile(A->getValue()) || hadDuplicates;
}
return false; // FIXME: Don't bail out for duplicates, too many tests depend
// on it.
}
bool doesCommandLineIncludeFilelist() { return FilelistPathArg; }
bool mustPrimaryFilesOnCommandLineAlsoAppearInFileList() {
return doesCommandLineIncludeFilelist();
}
bool getFilesFromFilelist() {
if (FilelistPathArg == nullptr)
if (!doesCommandLineIncludeFilelist())
return false;
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> filelistBufferOrError =
llvm::MemoryBuffer::getFile(filelistPath());
@@ -206,28 +200,26 @@ private:
}
// Keep buffer alive because code passes around StringRefs.
FilelistBuffer = std::move(*filelistBufferOrError);
bool hadDuplicates = false;
for (auto file : llvm::make_range(llvm::line_iterator(*FilelistBuffer),
llvm::line_iterator())) {
addFile(file, Whence::SecondaryFromFileList);
}
return false;
llvm::line_iterator()))
hadDuplicates = addFile(file) || hadDuplicates;
return false; // FIXME: Don't bail out for duplicates, too many tests depend
// on it.
}
bool setPrimaryFiles() {
for (StringRef primaryFile : PrimaryFiles) {
const auto iterator = FileIndices.find(primaryFile);
// Catch "swiftc -frontend -c -filelist foo -primary-file
// some-file-not-in-foo".
if (iterator == FileIndices.end()) {
assert(FilelistPathArg != nullptr &&
"Missing primary with no filelist");
Diags.diagnose(SourceLoc(), diag::error_primary_file_not_found,
primaryFile, filelistPath());
return true;
}
Inputs.addPrimaryInputFilename(iterator->second);
}
return false;
bool addFile(StringRef file) {
if (Files.insert(file))
return false;
Diags.diagnose(SourceLoc(), diag::error_duplicate_input_file, file);
return true;
}
llvm::StringSet<> getPrimaries() const {
llvm::StringSet<> primaryFiles;
for (const Arg *A : Args.filtered(options::OPT_primary_file))
primaryFiles.insert(A->getValue());
return primaryFiles;
}
};
class FrontendArgsToOptionsConverter {
@@ -278,6 +270,8 @@ private:
std::string determineBaseNameOfOutput() const;
void deriveOutputFilenameFromParts(StringRef dir, StringRef base);
void determineSupplementaryOutputFilenames();
/// Returns the output filenames on the command line or in the output
@@ -659,10 +653,10 @@ bool FrontendArgsToOptionsConverter::computeFallbackModuleName() {
Opts.ModuleName = "REPL";
return false;
}
if (!Opts.Inputs.hasInputFilenames()) {
// In order to pass some tests, must leave ModuleName empty.
if (!Opts.Inputs.hasInputs()) {
Opts.ModuleName = StringRef();
// FIXME: This is a bug that should not happen, but does in tests.
// The current behavior is needed to pass the tests.
// The compiler should bail out earlier, where "no frontend action was
// selected".
return false;
@@ -675,7 +669,7 @@ bool FrontendArgsToOptionsConverter::computeFallbackModuleName() {
!llvm::sys::fs::is_directory(outputFilenames[0]);
std::string nameToStem = isOutputAUniqueOrdinaryFile
? outputFilenames[0]
: Opts.Inputs.getFilenameOfFirstInput();
: Opts.Inputs.getFilenameOfFirstInput().str();
Opts.ModuleName = llvm::sys::path::stem(nameToStem);
return false;
}
@@ -728,11 +722,7 @@ bool FrontendArgsToOptionsConverter::deriveOutputFilenameFromInputFile() {
}
return false;
}
llvm::SmallString<128> path(baseName);
StringRef suffix = FrontendOptions::suffixForPrincipalOutputFileForAction(
Opts.RequestedAction);
llvm::sys::path::replace_extension(path, suffix);
Opts.OutputFilenames.push_back(path.str());
deriveOutputFilenameFromParts("", baseName);
return false;
}
@@ -745,25 +735,29 @@ bool FrontendArgsToOptionsConverter::deriveOutputFilenameForDirectory(
outputDir);
return true;
}
llvm::SmallString<128> path(outputDir);
llvm::sys::path::append(path, baseName);
deriveOutputFilenameFromParts(outputDir, baseName);
return false;
}
void FrontendArgsToOptionsConverter::deriveOutputFilenameFromParts(
StringRef dir, StringRef base) {
assert(!base.empty());
llvm::SmallString<128> path(dir);
llvm::sys::path::append(path, base);
StringRef suffix = FrontendOptions::suffixForPrincipalOutputFileForAction(
Opts.RequestedAction);
llvm::sys::path::replace_extension(path, suffix);
Opts.OutputFilenames.push_back(path.str());
return false;
}
std::string FrontendArgsToOptionsConverter::determineBaseNameOfOutput() const {
std::string nameToStem;
if (Opts.Inputs.hasAPrimaryInputFile()) {
assert(Opts.Inputs.hasUniquePrimaryInput() &&
"Cannot handle multiple primaries yet");
nameToStem = Opts.Inputs.primaryInputFilenameIfAny();
if (Opts.Inputs.hasPrimaryInputs()) {
nameToStem = Opts.Inputs.getRequiredUniquePrimaryInput().file();
} else if (auto UserSpecifiedModuleName =
Args.getLastArg(options::OPT_module_name)) {
nameToStem = UserSpecifiedModuleName->getValue();
} else if (Opts.Inputs.inputFilenameCount() == 1) {
} else if (Opts.Inputs.hasSingleInput()) {
nameToStem = Opts.Inputs.getFilenameOfFirstInput();
} else
nameToStem = "";
@@ -1650,10 +1644,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
// in other classes.
if (!SILOpts.SILOutputFileNameForDebugging.empty()) {
Opts.MainInputFilename = SILOpts.SILOutputFileNameForDebugging;
} else if (const Optional<StringRef> filename =
FrontendOpts.Inputs.getOptionalUniquePrimaryInputFilename()) {
Opts.MainInputFilename = filename.getValue();
} else if (FrontendOpts.Inputs.hasUniqueInputFilename()) {
} else if (const InputFile *input =
FrontendOpts.Inputs.getUniquePrimaryInput()) {
Opts.MainInputFilename = input->file();
} else if (FrontendOpts.Inputs.hasSingleInput()) {
Opts.MainInputFilename = FrontendOpts.Inputs.getFilenameOfFirstInput();
}
Opts.OutputFilenames = FrontendOpts.OutputFilenames;
@@ -1886,7 +1880,7 @@ CompilerInvocation::loadFromSerializedAST(StringRef data) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
CompilerInvocation::setUpInputForSILTool(
StringRef inputFilename, StringRef moduleNameArg,
bool alwaysSetModuleToMain,
bool alwaysSetModuleToMain, bool bePrimary,
serialization::ExtendedValidationInfo &extendedInfo) {
// Load the input file.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileBufOrErr =
@@ -1897,7 +1891,8 @@ CompilerInvocation::setUpInputForSILTool(
// If it looks like we have an AST, set the source file kind to SIL and the
// name of the module to the file's name.
addInputBuffer(fileBufOrErr.get().get());
getFrontendOptions().Inputs.addInput(
InputFile(inputFilename, bePrimary, fileBufOrErr.get().get()));
auto result = serialization::validateSerializedAST(
fileBufOrErr.get()->getBuffer(), &extendedInfo);