]> granicus.if.org Git - clang/commitdiff
Detect cyclic module dependencies in a manner that is rather more
authorDouglas Gregor <dgregor@apple.com>
Thu, 15 Sep 2011 20:40:10 +0000 (20:40 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 15 Sep 2011 20:40:10 +0000 (20:40 +0000)
graceful than running out of stack space.

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

include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Frontend/PreprocessorOptions.h
lib/Frontend/CompilerInstance.cpp

index 25df8c9bd03fd6dd1bd83f29b46b6722d26f1a5a..7639b5b05145dd8e87c794e4a39aa7387066be3b 100644 (file)
@@ -61,7 +61,9 @@ def err_deleted_non_function : Error<
   "only functions can have deleted definitions">;
 def err_module_not_found : Error<"module '%0' not found">, DefaultFatal;
 def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal;
-  
+def err_module_cycle : Error<"cyclic dependency in module '%0': %1">, 
+  DefaultFatal;
+
 // Sema && Lex
 def ext_longlong : Extension<
   "'long long' is an extension when C99 mode is not enabled">,
index c95efec99fa5ab7c2e8a31253a1e94fe3582d2a3..0259cfd26038b54e226dc3af88a3ddde42ede835 100644 (file)
@@ -117,6 +117,14 @@ public:
   /// by providing appropriate definitions to retrofit the standard library
   /// with support for lifetime-qualified pointers.
   ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary;
+    
+  /// \brief The path of modules being build, which is used to detect
+  /// cycles in the module dependency graph as modules are being built.
+  ///
+  /// There is no way to set this value from the command line. If we ever need
+  /// to do so (e.g., if on-demand module construction moves out-of-process),
+  /// we can add a cc1-level option to do so.
+  SmallVector<std::string, 2> ModuleBuildPath;
   
   typedef std::vector<std::pair<std::string, std::string> >::iterator
     remapped_file_iterator;
index 07d438b556a40078c9788895e839ffd4c654b56f..e3689c0c52a77d50fb51efc93162efec4f0314f3 100644 (file)
@@ -660,6 +660,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
     (new CompilerInvocation(ImportingInstance.getInvocation()));
   Invocation->getLangOpts().resetNonModularOptions();
   Invocation->getPreprocessorOpts().resetNonModularOptions();
+  Invocation->getPreprocessorOpts().ModuleBuildPath.push_back(ModuleName);
   
   FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
   FrontendOpts.OutputFile = ModuleFileName.str();
@@ -671,6 +672,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
   
   Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
   
+  
   assert(ImportingInstance.getInvocation().getModuleHash() ==
            Invocation->getModuleHash() && "Module hash mismatch!");
   
@@ -691,6 +693,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
   
   // Tell the diagnostic client that it's (re-)starting to process a source
   // file.
+  // FIXME: This is a hack. We probably want to clone the diagnostic client.
   ImportingInstance.getDiagnosticClient()
     .BeginSourceFile(ImportingInstance.getLangOpts(),
                      &ImportingInstance.getPreprocessor());
@@ -720,6 +723,26 @@ ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
     // We didn't find the module, but there is an umbrella header that
     // can be used to create the module file. Create a separate compilation
     // module to do so.
+    
+    // Check whether there is a cycle in the module graph.
+    SmallVectorImpl<std::string> &ModuleBuildPath
+      = getPreprocessorOpts().ModuleBuildPath;
+    SmallVectorImpl<std::string>::iterator Pos 
+      = std::find(ModuleBuildPath.begin(), ModuleBuildPath.end(),
+                  ModuleName.getName());
+    if (Pos != ModuleBuildPath.end()) {
+      llvm::SmallString<256> CyclePath;
+      for (; Pos != ModuleBuildPath.end(); ++Pos) {
+        CyclePath += *Pos;
+        CyclePath += " -> ";
+      }
+      CyclePath += ModuleName.getName();
+      
+      getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
+        << ModuleName.getName() << CyclePath;
+      return 0;
+    }
+    
     BuildingModule = true;
     compileModule(*this, ModuleName.getName(), ModuleFileName, UmbrellaHeader);
     ModuleFile = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName());