[flang-commits] [flang] 6110e77 - [flang] Search for #include "file" in right directory (take 2)

peter klausler via flang-commits flang-commits at lists.llvm.org
Wed Jan 27 15:41:39 PST 2021


Author: peter klausler
Date: 2021-01-27T15:41:29-08:00
New Revision: 6110e7716cd0000fdeb2a7edfbec7c9991f1a08a

URL: https://github.com/llvm/llvm-project/commit/6110e7716cd0000fdeb2a7edfbec7c9991f1a08a
DIFF: https://github.com/llvm/llvm-project/commit/6110e7716cd0000fdeb2a7edfbec7c9991f1a08a.diff

LOG: [flang] Search for #include "file" in right directory (take 2)

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 except the original.

Resolve tests.

Differential Revision: https://reviews.llvm.org/D95481

Added: 
    flang/test/Flang-Driver/Inputs/module-dir/basictestmoduleone.mod

Modified: 
    flang/include/flang/Parser/provenance.h
    flang/include/flang/Parser/source.h
    flang/lib/Frontend/FrontendActions.cpp
    flang/lib/Parser/parsing.cpp
    flang/lib/Parser/preprocessor.cpp
    flang/lib/Parser/prescan.cpp
    flang/lib/Parser/provenance.cpp
    flang/lib/Parser/source.cpp
    flang/test/Flang-Driver/Inputs/basictestmoduleone.mod
    flang/test/Flang-Driver/Inputs/module-dir/basictestmoduletwo.mod
    flang/test/Flang-Driver/include-header.f90
    flang/test/Flang-Driver/include-module.f90
    flang/tools/f18/f18.cpp
    flang/unittests/Frontend/FrontendActionTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Parser/provenance.h b/flang/include/flang/Parser/provenance.h
index 73661d954854..bce79809c766 100644
--- a/flang/include/flang/Parser/provenance.h
+++ b/flang/include/flang/Parser/provenance.h
@@ -148,9 +148,9 @@ class AllSources {
     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,
+      std::optional<std::string> &&prependPath = std::nullopt);
   const SourceFile *ReadStandardInput(llvm::raw_ostream &error);
 
   ProvenanceRange AddIncludedFile(
@@ -210,7 +210,7 @@ class AllSources {
   ProvenanceRange range_;
   std::map<char, Provenance> compilerInsertionProvenance_;
   std::vector<std::unique_ptr<SourceFile>> ownedSourceFiles_;
-  std::vector<std::string> searchPath_;
+  std::list<std::string> 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 <cstddef>
+#include <list>
+#include <optional>
 #include <string>
 #include <utility>
 #include <vector>
@@ -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<std::string> &searchPath);
+std::optional<std::string> LocateSourceFile(
+    std::string name, const std::list<std::string> &searchPath);
 
 class SourceFile;
 

diff  --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index c200d601a42c..a89ebf0b9f9a 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -28,7 +28,7 @@ void InputOutputTestAction::ExecuteAction() {
   CompilerInstance &ci = instance();
   Fortran::parser::AllSources &allSources{ci.allSources()};
   const Fortran::parser::SourceFile *sf;
-  sf = allSources.Open(path, error_stream);
+  sf = allSources.Open(path, error_stream, std::optional<std::string>{"."s});
   llvm::ArrayRef<char> fileContent = sf->content();
 
   // Output file descriptor to receive the content of input file.

diff  --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp
index 7f3a4a623f46..5845c75541a2 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<std::string> currentDirectory{"."};
+    sourceFile = allSources.Open(path, fileError, std::move(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..d3dd50a13389 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<std::string> prependPath;
     if (dir.TokenAt(j).ToString() == "<") { // #include <foo>
       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,8 @@ 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, std::move(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..edb62b35242d 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -760,14 +760,12 @@ 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<std::string> prependPath;
+  if (const SourceFile * currentFile{allSources_.GetSourceFile(provenance)}) {
+    prependPath = DirectoryName(currentFile->path());
   }
+  const SourceFile *included{
+      allSources_.Open(path, error, std::move(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..14124a546d1e 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,
+    std::optional<std::string> &&prependPath) {
   std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>(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_.emplace_front(std::move(*prependPath));
+  }
+  std::optional<std::string> 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<std::string> &searchPath) {
-  if (name.empty() || name == "-" || llvm::sys::path::is_absolute(name)) {
+std::optional<std::string> LocateSourceFile(
+    std::string name, const std::list<std::string> &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<char> 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/test/Flang-Driver/Inputs/basictestmoduleone.mod b/flang/test/Flang-Driver/Inputs/basictestmoduleone.mod
index 424a151bcf3d..e0563fe1a603 100644
--- a/flang/test/Flang-Driver/Inputs/basictestmoduleone.mod
+++ b/flang/test/Flang-Driver/Inputs/basictestmoduleone.mod
@@ -1 +1,5 @@
-NOT A REAL MODULE FILE - USE THIS ONLY FOR TESTING THE DRIVER
+!mod$ v1 sum:1f5a35ada852dc66
+module basictestmoduleone
+type::t1
+end type
+end

diff  --git a/flang/test/Flang-Driver/Inputs/module-dir/basictestmoduleone.mod b/flang/test/Flang-Driver/Inputs/module-dir/basictestmoduleone.mod
new file mode 100644
index 000000000000..1140a8414fa3
--- /dev/null
+++ b/flang/test/Flang-Driver/Inputs/module-dir/basictestmoduleone.mod
@@ -0,0 +1,5 @@
+!mod$ v1 sum:449b70509dd4bce3
+module basictestmoduleone
+type::t2
+end type
+end

diff  --git a/flang/test/Flang-Driver/Inputs/module-dir/basictestmoduletwo.mod b/flang/test/Flang-Driver/Inputs/module-dir/basictestmoduletwo.mod
index 424a151bcf3d..ea7d12d112ef 100644
--- a/flang/test/Flang-Driver/Inputs/module-dir/basictestmoduletwo.mod
+++ b/flang/test/Flang-Driver/Inputs/module-dir/basictestmoduletwo.mod
@@ -1 +1,3 @@
-NOT A REAL MODULE FILE - USE THIS ONLY FOR TESTING THE DRIVER
+!mod$ v1 sum:563b9a1f049282d2
+module basictestmoduletwo
+end

diff  --git a/flang/test/Flang-Driver/include-header.f90 b/flang/test/Flang-Driver/include-header.f90
index a171ed95c407..f3cafb78af0b 100644
--- a/flang/test/Flang-Driver/include-header.f90
+++ b/flang/test/Flang-Driver/include-header.f90
@@ -21,7 +21,7 @@
 !--------------------------------------------
 ! EXPECTED OUTPUT FOR MISSING INCLUDED FILE
 !--------------------------------------------
-! UNINCLUDED:No such file or directory
+! UNINCLUDED:#include: Source file 'basic-header-one.h' was not found
 ! UNINCLUDED-NOT:program b
 ! UNINCLUDED-NOT:program c
 

diff  --git a/flang/test/Flang-Driver/include-module.f90 b/flang/test/Flang-Driver/include-module.f90
index 7a551952a00b..e9530cc04c8c 100644
--- a/flang/test/Flang-Driver/include-module.f90
+++ b/flang/test/Flang-Driver/include-module.f90
@@ -1,5 +1,4 @@
 ! Ensure argument -I works as expected with module files.
-! The module files for this test are not real module files.
 
 ! REQUIRES: new-flang-driver
 
@@ -18,15 +17,21 @@
 !-----------------------------------------
 ! EXPECTED OUTPUT FOR MISSING MODULE FILE
 !-----------------------------------------
-! SINGLEINCLUDE:No such file or directory
+! SINGLEINCLUDE:Error reading module file for module 'basictestmoduletwo'
 ! SINGLEINCLUDE-NOT:Error reading module file for module 'basictestmoduletwo'
+! SINGLEINCLUDE-NOT:error: Derived type 't1' not found
+! SINGLEINCLUDE:error: Derived type 't2' not found
 
 !---------------------------------------
 ! EXPECTED OUTPUT FOR ALL MODULES FOUND
 !---------------------------------------
-! INCLUDED-NOT:No such file or directory
+! INCLUDED-NOT:Error reading module file
+! INCLUDED-NOT:error: Derived type 't1' not found
+! INCLUDED:error: Derived type 't2' not found
 
 program test_dash_I_with_mod_files
     USE basictestmoduleone
     USE basictestmoduletwo
+    type(t1) :: x1 ! t1 defined in Inputs/basictestmoduleone.mod
+    type(t2) :: x2 ! t2 defined in Inputs/module-dir/basictestmoduleone.mod
 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<std::string> searchDirectories{"."s}; // -I dir
+  std::vector<std::string> searchDirectories; // -I dir
   std::string moduleDirectory{"."s}; // -module dir
   std::string moduleFileSuffix{".mod"}; // -moduleSuffix suff
   bool forcedForm{false}; // -Mfixed or -Mfree appeared

diff  --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp
index fba46690171d..150f20d9b269 100644
--- a/flang/unittests/Frontend/FrontendActionTest.cpp
+++ b/flang/unittests/Frontend/FrontendActionTest.cpp
@@ -157,7 +157,7 @@ TEST_F(FrontendActionTest, ParseSyntaxOnly) {
   EXPECT_TRUE(!outputDiagBuffer.empty());
   EXPECT_TRUE(
       llvm::StringRef(outputDiagBuffer.data())
-          .startswith(
+          .contains(
               ":1:14: error: IF statement is not allowed in IF statement\n"));
 }
 } // namespace


        


More information about the flang-commits mailing list