]> granicus.if.org Git - clang/commitdiff
Teach ModuleManager::addModule() to check whether a particular module
authorDouglas Gregor <dgregor@apple.com>
Fri, 19 Aug 2011 02:29:29 +0000 (02:29 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 19 Aug 2011 02:29:29 +0000 (02:29 +0000)
has already been loaded before allocating a new Module structure. If
the module has already been loaded (uniquing based on file name), then
just return the existing module rather than trying to load it again.

This allows us to load a DAG of modules. Introduce a simple test case
that forms a diamond-shaped module graph, and illustrates that a
source file importing the bottom of the diamond can see declarations
in all four of the modules that make up the diamond.

Note that this version moves the file-opening logic into the module
manager, rather than splitting it between the module manager and the
AST reader. More importantly, it properly handles the
weird-but-possibly-useful case of loading an AST file from "-".

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138030 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Serialization/ASTReader.h
lib/Serialization/ASTReader.cpp
test/Modules/Inputs/diamond_bottom.h [new file with mode: 0644]
test/Modules/Inputs/diamond_left.h [new file with mode: 0644]
test/Modules/Inputs/diamond_right.h [new file with mode: 0644]
test/Modules/Inputs/diamond_top.h [new file with mode: 0644]
test/Modules/diamond.c [new file with mode: 0644]

index 514d36db919c45462d1b660d7fd3c42361afd669..4ed86480c8f9d2c3629c578822703a62fa452e1d 100644 (file)
@@ -507,8 +507,15 @@ public:
   ///
   /// \param ImportedBy The module that is importing this module, or NULL if
   /// this module is imported directly by the user.
-  Module &addModule(StringRef FileName, ModuleKind Type,
-                    Module *ImportedBy);
+  ///
+  /// \param ErrorStr Will be set to a non-empty string if any errors occurred
+  /// while trying to load the module.
+  ///
+  /// \return A pointer to the module that corresponds to this file name,
+  /// and a boolean indicating whether the module was newly added.
+  std::pair<Module *, bool> 
+  addModule(StringRef FileName, ModuleKind Type, Module *ImportedBy,
+            std::string &ErrorStr);
   
   /// \brief Add an in-memory buffer the list of known buffers
   void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);
index d81e9d8a36a47a4198a8be78bc546f26bb97c981..840b665cd7681d149da0815acf4990fb351fca3f 100644 (file)
@@ -2831,37 +2831,33 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
 ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
                                                 ModuleKind Type,
                                                 Module *ImportedBy) {
-  Module &F = ModuleMgr.addModule(FileName, Type, ImportedBy);
+  Module *M;
+  bool NewModule;
+  std::string ErrorStr;
+  llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy,
+                                                ErrorStr);
+
+  if (!M) {
+    // We couldn't load the module.
+    std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+      + ErrorStr;
+    Error(Msg);
+    return Failure;
+  }
+
+  if (!NewModule) {
+    // We've already loaded this module.
+    return Success;
+  }
 
+  // FIXME: This seems rather a hack. Should CurrentDir be part of the
+  // module?
   if (FileName != "-") {
     CurrentDir = llvm::sys::path::parent_path(FileName);
     if (CurrentDir.empty()) CurrentDir = ".";
   }
 
-  if (llvm::MemoryBuffer *Buffer = ModuleMgr.lookupBuffer(FileName)) {
-    F.Buffer.reset(Buffer);
-    assert(F.Buffer && "Passed null buffer");
-  } else {
-    // Open the AST file.
-    //
-    // FIXME: This shouldn't be here, we should just take a raw_ostream.
-    std::string ErrStr;
-    llvm::error_code ec;
-    if (FileName == "-") {
-      ec = llvm::MemoryBuffer::getSTDIN(F.Buffer);
-      if (ec)
-        ErrStr = ec.message();
-    } else
-      F.Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrStr));
-    if (!F.Buffer) {
-      Error(ErrStr.c_str());
-      return IgnorePCH;
-    }
-  }
-
-  // Initialize the stream
-  F.StreamFile.init((const unsigned char *)F.Buffer->getBufferStart(),
-                    (const unsigned char *)F.Buffer->getBufferEnd());
+  Module &F = *M;
   llvm::BitstreamCursor &Stream = F.Stream;
   Stream.init(F.StreamFile);
   F.SizeInBits = F.Buffer->getBufferSize() * 8;
@@ -5709,25 +5705,57 @@ llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
   return InMemoryBuffers[Entry];
 }
 
-/// \brief Creates a new module and adds it to the list of known modules
-Module &ModuleManager::addModule(StringRef FileName, ModuleKind Type,
-                                 Module *ImportedBy) {
-  Module *Current = new Module(Type);
-  Current->FileName = FileName.str();
-  Chain.push_back(Current);
-
+std::pair<Module *, bool>
+ModuleManager::addModule(StringRef FileName, ModuleKind Type, 
+                         Module *ImportedBy, std::string &ErrorStr) {
   const FileEntry *Entry = FileMgr.getFile(FileName);
-  // FIXME: Check whether we already loaded this module, before 
-  Modules[Entry] = Current;
+  if (!Entry && FileName != "-") {
+    ErrorStr = "file not found";
+    return std::make_pair(static_cast<Module*>(0), false);
+  }
+
+  // Check whether we already loaded this module, before 
+  Module *&ModuleEntry = Modules[Entry];
+  bool NewModule = false;
+  if (!ModuleEntry) {
+    // Allocate a new module.
+    Module *New = new Module(Type);
+    New->FileName = FileName.str();
+    Chain.push_back(New);
+    NewModule = true;
+    ModuleEntry = New;
+
+    // Load the contents of the module
+    if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
+      // The buffer was already provided for us.
+      assert(Buffer && "Passed null buffer");
+      New->Buffer.reset(Buffer);
+    } else {
+      // Open the AST file.
+      llvm::error_code ec;
+      if (FileName == "-") {
+        ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
+        if (ec)
+          ErrorStr = ec.message();
+      } else
+        New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
+
+      if (!New->Buffer)
+        return std::make_pair(static_cast<Module*>(0), false);
+    }
+
+    // Initialize the stream
+    New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
+                         (const unsigned char *)New->Buffer->getBufferEnd());     }
 
   if (ImportedBy) {
-    Current->ImportedBy.insert(ImportedBy);
-    ImportedBy->Imports.insert(Current);
+    ModuleEntry->ImportedBy.insert(ImportedBy);
+    ImportedBy->Imports.insert(ModuleEntry);
   } else {
-    Current->DirectlyImported = true;
+    ModuleEntry->DirectlyImported = true;
   }
   
-  return *Current;
+  return std::make_pair(ModuleEntry, NewModule);
 }
 
 void ModuleManager::addInMemoryBuffer(StringRef FileName, 
diff --git a/test/Modules/Inputs/diamond_bottom.h b/test/Modules/Inputs/diamond_bottom.h
new file mode 100644 (file)
index 0000000..40afc9b
--- /dev/null
@@ -0,0 +1 @@
+char bottom(char *x);
diff --git a/test/Modules/Inputs/diamond_left.h b/test/Modules/Inputs/diamond_left.h
new file mode 100644 (file)
index 0000000..dfdd803
--- /dev/null
@@ -0,0 +1 @@
+float left(float *);
diff --git a/test/Modules/Inputs/diamond_right.h b/test/Modules/Inputs/diamond_right.h
new file mode 100644 (file)
index 0000000..bbed7ec
--- /dev/null
@@ -0,0 +1 @@
+double right(double *);
diff --git a/test/Modules/Inputs/diamond_top.h b/test/Modules/Inputs/diamond_top.h
new file mode 100644 (file)
index 0000000..189687a
--- /dev/null
@@ -0,0 +1 @@
+int top(int *);
diff --git a/test/Modules/diamond.c b/test/Modules/diamond.c
new file mode 100644 (file)
index 0000000..fdec7b3
--- /dev/null
@@ -0,0 +1,14 @@
+// in diamond-bottom.h: expected-note{{passing argument to parameter 'x' here}}
+void test_diamond(int i, float f, double d, char c) {
+  top(&i);
+  left(&f);
+  right(&d);
+  bottom(&c);
+  bottom(&d); // expected-warning{{incompatible pointer types passing 'double *' to parameter of type 'char *'}}
+}
+
+// RUN: %clang_cc1 -emit-pch -o %t_top.h.pch %S/Inputs/diamond_top.h
+// RUN: %clang_cc1 -import-module %t_top.h.pch -emit-pch -o %t_left.h.pch %S/Inputs/diamond_left.h
+// RUN: %clang_cc1 -import-module %t_top.h.pch -emit-pch -o %t_right.h.pch %S/Inputs/diamond_right.h
+// RUN: %clang_cc1 -import-module %t_left.h.pch -import-module %t_right.h.pch -emit-pch -o %t_bottom.h.pch %S/Inputs/diamond_bottom.h
+// RUN: %clang_cc1 -import-module %t_bottom.h.pch -verify %s