From: Douglas Gregor Date: Thu, 15 Sep 2011 20:40:10 +0000 (+0000) Subject: Detect cyclic module dependencies in a manner that is rather more X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4ebd45f4279d84416568ada6adf56044bdf391b7;p=clang Detect cyclic module dependencies in a manner that is rather more graceful than running out of stack space. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139833 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 25df8c9bd0..7639b5b051 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -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">, diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index c95efec99f..0259cfd260 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -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 ModuleBuildPath; typedef std::vector >::iterator remapped_file_iterator; diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 07d438b556..e3689c0c52 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -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 &ModuleBuildPath + = getPreprocessorOpts().ModuleBuildPath; + SmallVectorImpl::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());