From d987b61b1dce9948801ac37704477e7c257100b1 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Mon, 25 Jan 2021 12:29:10 -0800 Subject: [PATCH] [flang] Search for #include "file" in right directory Make the #include "file" preprocessing directive begin its search in the same directory as the file containing the directive, as other preprocessors and our Fortran INCLUDE statement do. Avoid current working directory for all source files after the original. Differential Revision: https://reviews.llvm.org/D95388 --- flang/include/flang/Parser/provenance.h | 8 ++++---- flang/include/flang/Parser/source.h | 6 ++++-- flang/lib/Parser/parsing.cpp | 9 +++++---- flang/lib/Parser/preprocessor.cpp | 10 +++++++++- flang/lib/Parser/prescan.cpp | 11 ++++------- flang/lib/Parser/provenance.cpp | 26 ++++++++++++++++--------- flang/lib/Parser/source.cpp | 10 ++++------ flang/tools/f18/f18.cpp | 2 +- 8 files changed, 48 insertions(+), 34 deletions(-) diff --git a/flang/include/flang/Parser/provenance.h b/flang/include/flang/Parser/provenance.h index 73661d954854..08afcf1c0539 100644 --- a/flang/include/flang/Parser/provenance.h +++ b/flang/include/flang/Parser/provenance.h @@ -148,9 +148,9 @@ public: return *this; } - void PushSearchPathDirectory(std::string); - std::string PopSearchPathDirectory(); - const SourceFile *Open(std::string path, llvm::raw_ostream &error); + void AppendSearchPathDirectory(std::string); // new last directory + const SourceFile *Open(std::string path, llvm::raw_ostream &error, + const std::optional &prependPath); const SourceFile *ReadStandardInput(llvm::raw_ostream &error); ProvenanceRange AddIncludedFile( @@ -210,7 +210,7 @@ private: ProvenanceRange range_; std::map compilerInsertionProvenance_; std::vector> ownedSourceFiles_; - std::vector searchPath_; + std::list searchPath_; Encoding encoding_{Encoding::UTF_8}; }; diff --git a/flang/include/flang/Parser/source.h b/flang/include/flang/Parser/source.h index e0d1a5308fdf..4f387bdc0288 100644 --- a/flang/include/flang/Parser/source.h +++ b/flang/include/flang/Parser/source.h @@ -17,6 +17,8 @@ #include "characters.h" #include "llvm/Support/MemoryBuffer.h" #include +#include +#include #include #include #include @@ -28,8 +30,8 @@ class raw_ostream; namespace Fortran::parser { std::string DirectoryName(std::string path); -std::string LocateSourceFile( - std::string name, const std::vector &searchPath); +std::optional LocateSourceFile( + std::string name, const std::list &searchPath); class SourceFile; diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp index 7f3a4a623f46..0bd542c518b6 100644 --- a/flang/lib/Parser/parsing.cpp +++ b/flang/lib/Parser/parsing.cpp @@ -25,7 +25,7 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) { AllSources &allSources{allCooked_.allSources()}; if (options.isModuleFile) { for (const auto &path : options.searchDirectories) { - allSources.PushSearchPathDirectory(path); + allSources.AppendSearchPathDirectory(path); } } @@ -35,7 +35,8 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) { if (path == "-") { sourceFile = allSources.ReadStandardInput(fileError); } else { - sourceFile = allSources.Open(path, fileError); + std::optional currentDirectory{"."}; + sourceFile = allSources.Open(path, fileError, currentDirectory); } if (!fileError.str().empty()) { ProvenanceRange range{allSources.AddCompilerInsertion(path)}; @@ -46,12 +47,12 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) { if (!options.isModuleFile) { // For .mod files we always want to look in the search directories. - // For normal source files we don't push them until after the primary + // For normal source files we don't add them until after the primary // source file has been opened. If foo.f is missing from the current // working directory, we don't want to accidentally read another foo.f // from another directory that's on the search path. for (const auto &path : options.searchDirectories) { - allSources.PushSearchPathDirectory(path); + allSources.AppendSearchPathDirectory(path); } } diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp index c5422cc0070f..14c9e54eb01e 100644 --- a/flang/lib/Parser/preprocessor.cpp +++ b/flang/lib/Parser/preprocessor.cpp @@ -399,6 +399,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { if (j == tokens) { return; } + CHECK(prescanner); // TODO: change to reference if (dir.TokenAt(j).ToString() != "#") { prescanner->Say(dir.GetTokenProvenanceRange(j), "missing '#'"_err_en_US); return; @@ -578,6 +579,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { return; } std::string include; + std::optional prependPath; if (dir.TokenAt(j).ToString() == "<") { // #include std::size_t k{j + 1}; if (k >= tokens) { @@ -598,6 +600,12 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } else if ((include = dir.TokenAt(j).ToString()).substr(0, 1) == "\"" && include.substr(include.size() - 1, 1) == "\"") { // #include "foo" include = include.substr(1, include.size() - 2); + // #include "foo" starts search in directory of file containing + // the directive + auto prov{dir.GetTokenProvenanceRange(dirOffset).start()}; + if (const auto *currentFile{allSources_.GetSourceFile(prov)}) { + prependPath = DirectoryName(currentFile->path()); + } } else { prescanner->Say(dir.GetTokenProvenanceRange(j < tokens ? j : tokens - 1), "#include: expected name of file to include"_err_en_US); @@ -615,7 +623,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } std::string buf; llvm::raw_string_ostream error{buf}; - const SourceFile *included{allSources_.Open(include, error)}; + const SourceFile *included{allSources_.Open(include, error, prependPath)}; if (!included) { prescanner->Say(dir.GetTokenProvenanceRange(dirOffset), "#include: %s"_err_en_US, error.str()); diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp index dc6fbe529769..7a78dd2757a7 100644 --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -760,14 +760,11 @@ void Prescanner::FortranInclude(const char *firstQuote) { std::string buf; llvm::raw_string_ostream error{buf}; Provenance provenance{GetProvenance(nextLine_)}; - const SourceFile *currentFile{allSources_.GetSourceFile(provenance)}; - if (currentFile) { - allSources_.PushSearchPathDirectory(DirectoryName(currentFile->path())); - } - const SourceFile *included{allSources_.Open(path, error)}; - if (currentFile) { - allSources_.PopSearchPathDirectory(); + std::optional prependPath; + if (const SourceFile * currentFile{allSources_.GetSourceFile(provenance)}) { + prependPath = DirectoryName(currentFile->path()); } + const SourceFile *included{allSources_.Open(path, error, prependPath)}; if (!included) { Say(provenance, "INCLUDE: %s"_err_en_US, error.str()); } else if (included->bytes() > 0) { diff --git a/flang/lib/Parser/provenance.cpp b/flang/lib/Parser/provenance.cpp index 46a0dc926822..bed90907d5a9 100644 --- a/flang/lib/Parser/provenance.cpp +++ b/flang/lib/Parser/provenance.cpp @@ -156,20 +156,28 @@ const char &AllSources::operator[](Provenance at) const { return origin[origin.covers.MemberOffset(at)]; } -void AllSources::PushSearchPathDirectory(std::string directory) { +void AllSources::AppendSearchPathDirectory(std::string directory) { // gfortran and ifort append to current path, PGI prepends searchPath_.push_back(directory); } -std::string AllSources::PopSearchPathDirectory() { - std::string directory{searchPath_.back()}; - searchPath_.pop_back(); - return directory; -} - -const SourceFile *AllSources::Open(std::string path, llvm::raw_ostream &error) { +const SourceFile *AllSources::Open(std::string path, llvm::raw_ostream &error, + const std::optional &prependPath) { std::unique_ptr source{std::make_unique(encoding_)}; - if (source->Open(LocateSourceFile(path, searchPath_), error)) { + if (prependPath) { + // Set to "." for the initial source file; set to the directory name + // of the including file for #include "quoted-file" directives & + // INCLUDE statements. + searchPath_.push_front(*prependPath); + } + std::optional found{LocateSourceFile(path, searchPath_)}; + if (prependPath) { + searchPath_.pop_front(); + } + if (!found) { + error << "Source file '" << path << "' was not found"; + return nullptr; + } else if (source->Open(*found, error)) { return ownedSourceFiles_.emplace_back(std::move(source)).get(); } else { return nullptr; diff --git a/flang/lib/Parser/source.cpp b/flang/lib/Parser/source.cpp index 11cd5916dedf..3fbbf78517d0 100644 --- a/flang/lib/Parser/source.cpp +++ b/flang/lib/Parser/source.cpp @@ -56,9 +56,9 @@ std::string DirectoryName(std::string path) { return pathBuf.str().str(); } -std::string LocateSourceFile( - std::string name, const std::vector &searchPath) { - if (name.empty() || name == "-" || llvm::sys::path::is_absolute(name)) { +std::optional LocateSourceFile( + std::string name, const std::list &searchPath) { + if (name == "-" || llvm::sys::path::is_absolute(name)) { return name; } for (const std::string &dir : searchPath) { @@ -70,7 +70,7 @@ std::string LocateSourceFile( return path.str().str(); } } - return name; + return std::nullopt; } std::size_t RemoveCarriageReturns(llvm::MutableArrayRef buf) { @@ -123,7 +123,6 @@ bool SourceFile::Open(std::string path, llvm::raw_ostream &error) { bool SourceFile::ReadStandardInput(llvm::raw_ostream &error) { Close(); path_ = "standard input"; - auto buf_or = llvm::MemoryBuffer::getSTDIN(); if (!buf_or) { auto err = buf_or.getError(); @@ -146,7 +145,6 @@ void SourceFile::ReadFile() { auto tmp_buf{llvm::WritableMemoryBuffer::getNewUninitMemBuffer( content().size() + 1)}; llvm::copy(content(), tmp_buf->getBufferStart()); - Close(); buf_ = std::move(tmp_buf); } buf_end_++; diff --git a/flang/tools/f18/f18.cpp b/flang/tools/f18/f18.cpp index 9a10aeda7b24..7cb0129fc494 100644 --- a/flang/tools/f18/f18.cpp +++ b/flang/tools/f18/f18.cpp @@ -84,7 +84,7 @@ struct DriverOptions { bool verbose{false}; // -v bool compileOnly{false}; // -c std::string outputPath; // -o path - std::vector searchDirectories{"."s}; // -I dir + std::vector searchDirectories; // -I dir std::string moduleDirectory{"."s}; // -module dir std::string moduleFileSuffix{".mod"}; // -moduleSuffix suff bool forcedForm{false}; // -Mfixed or -Mfree appeared