[cfe-commits] r147387 - in /cfe/trunk: include/clang/Basic/ include/clang/Lex/ include/clang/Serialization/ lib/Basic/ lib/Frontend/ lib/Lex/ lib/Serialization/ test/Modules/ test/Modules/Inputs/DependsOnModule.framework/ test/Modules/Inputs/DependsOnModule.framework/Headers/

Douglas Gregor dgregor at apple.com
Fri Dec 30 20:05:45 PST 2011


Author: dgregor
Date: Fri Dec 30 22:05:44 2011
New Revision: 147387

URL: http://llvm.org/viewvc/llvm-project?rev=147387&view=rev
Log:
Implement support for module requirements, which indicate the language
features needed for a particular module to be available. This allows
mixed-language modules, where certain headers only work under some
language variants (e.g., in C++, std.tuple might only be available in
C++11 mode).

Added:
    cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h   (with props)
    cfe/trunk/test/Modules/requires.m
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Basic/Module.h
    cfe/trunk/include/clang/Lex/HeaderSearch.h
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/Basic/Module.cpp
    cfe/trunk/lib/Frontend/ASTUnit.cpp
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/Lex/HeaderSearch.cpp
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Lex/PPLexerChange.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module.map
    cfe/trunk/test/Modules/subframeworks.m

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Fri Dec 30 22:05:44 2011
@@ -143,4 +143,6 @@
   InGroup<IncompleteUmbrella>;
 def err_module_map_temp_file : Error<
   "unable to write temporary module map file '%0'">, DefaultFatal;
+def err_module_unavailable : Error<"module '%0' requires feature '%1'">;
+
 }

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Fri Dec 30 22:05:44 2011
@@ -421,7 +421,8 @@
   "'explicit' is not permitted on top-level modules">;
 def err_mmap_nested_submodule_id : Error<
   "qualified module name can only be used to define modules at the top level">;
-  
+def err_mmap_expected_feature : Error<"expected a feature name">;
+
 def warn_auto_module_import : Warning<
   "treating #%select{include|import|include_next|__include_macros}0 as an "
   "import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;

Modified: cfe/trunk/include/clang/Basic/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Module.h (original)
+++ cfe/trunk/include/clang/Basic/Module.h Fri Dec 30 22:05:44 2011
@@ -29,8 +29,9 @@
 
 namespace clang {
   
-class FileEntry;
 class DirectoryEntry;
+class FileEntry;
+class LangOptions;
   
 /// \brief Describes the name of a module.
 typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
@@ -57,7 +58,18 @@
   
   /// \brief The headers that are part of this module.
   llvm::SmallVector<const FileEntry *, 2> Headers;
-  
+
+  /// \brief The set of language features required to use this module.
+  ///
+  /// If any of these features is not present, the \c IsAvailable bit
+  /// will be false to indicate that this (sub)module is not
+  /// available.
+  llvm::SmallVector<std::string, 2> Requires;
+
+  /// \brief Whether this module is available in the current
+  /// translation unit.
+  unsigned IsAvailable : 1;
+
   /// \brief Whether this module was loaded from a module file.
   unsigned IsFromModuleFile : 1;
   
@@ -134,21 +146,40 @@
   explicit Module(StringRef Name, SourceLocation DefinitionLoc,
                   bool IsFramework)
     : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), Umbrella(),
-      IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(false),
-      InferSubmodules(false), InferExplicitSubmodules(false),
+      IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), 
+      IsExplicit(false), InferSubmodules(false), InferExplicitSubmodules(false),
       InferExportWildcard(false), NameVisibility(Hidden) { }
   
   /// \brief Construct  a new module or submodule.
   Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, 
          bool IsFramework, bool IsExplicit)
     : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), 
-      Umbrella(), IsFromModuleFile(false), IsFramework(IsFramework), 
-      IsExplicit(IsExplicit), InferSubmodules(false), 
+      Umbrella(), IsAvailable(true), IsFromModuleFile(false), 
+      IsFramework(IsFramework), IsExplicit(IsExplicit), InferSubmodules(false), 
       InferExplicitSubmodules(false), InferExportWildcard(false),
-      NameVisibility(Hidden) { }
+      NameVisibility(Hidden) 
+  { 
+    if (Parent && !Parent->isAvailable())
+      IsAvailable = false;
+  }
   
   ~Module();
   
+  /// \brief Determine whether this module is available for use within the
+  /// current translation unit.
+  bool isAvailable() const { return IsAvailable; }
+
+  /// \brief Determine whether this module is available for use within the
+  /// current translation unit.
+  ///
+  /// \param LangOpts The language options used for the current
+  /// translation unit.
+  ///
+  /// \param Feature If this module is unavailable, this parameter
+  /// will be set to one of the features that is required for use of
+  /// this module (but is not available).
+  bool isAvailable(const LangOptions &LangOpts, StringRef &Feature) const;
+
   /// \brief Determine whether this module is a submodule.
   bool isSubModule() const { return Parent != 0; }
   
@@ -203,7 +234,17 @@
   bool hasUmbrellaDir() const {
     return Umbrella && Umbrella.is<const DirectoryEntry *>();
   }
-  
+
+  /// \briaf Add the given feature requirement to the list of features
+  /// required by this module.
+  ///
+  /// \param Feature The feature that is required by this module (and
+  /// its submodules).
+  ///
+  /// \param LangOpts The set of language options that will be used to
+  /// evaluate the availability of this feature.
+  void addRequirement(StringRef Feature, const LangOptions &LangOpts);
+
   /// \brief Print the module map for this module to the given stream. 
   ///
   void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;

Modified: cfe/trunk/include/clang/Lex/HeaderSearch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/HeaderSearch.h?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/HeaderSearch.h (original)
+++ cfe/trunk/include/clang/Lex/HeaderSearch.h Fri Dec 30 22:05:44 2011
@@ -185,7 +185,8 @@
   explicit HeaderSearch(const HeaderSearch&);
   void operator=(const HeaderSearch&);
 public:
-  HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags);
+  HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+               const LangOptions &LangOpts);
   ~HeaderSearch();
 
   FileManager &getFileMgr() const { return FileMgr; }
@@ -369,6 +370,8 @@
   bool hasModuleMap(StringRef Filename, const DirectoryEntry *Root);
   
   /// \brief Retrieve the module that corresponds to the given file, if any.
+  ///
+  /// \param File The header that we wish to map to a module.
   Module *findModuleForHeader(const FileEntry *File);
   
   

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Fri Dec 30 22:05:44 2011
@@ -38,8 +38,13 @@
 class ModuleMap {
   SourceManager *SourceMgr;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
-  LangOptions LangOpts;
-  
+  const LangOptions &LangOpts;
+
+  /// \brief Language options used to parse the module map itself.
+  ///
+  /// These are always simple C language options.
+  LangOptions MMapLangOpts;
+
   /// \brief The top-level modules that are known.
   llvm::StringMap<Module *> Modules;
   
@@ -82,7 +87,10 @@
   ///
   /// \param DC A diagnostic consumer that will be cloned for use in generating
   /// diagnostics.
-  ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC);
+  ///
+  /// \param LangOpts Language options for this translation unit.
+  ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
+            const LangOptions &LangOpts);
 
   /// \brief Destroy the module map.
   ///
@@ -96,6 +104,10 @@
   /// that no module owns this header file.
   Module *findModuleForHeader(const FileEntry *File);
 
+  /// \brief Determine whether the given header is part of a module
+  /// marked 'unavailable'.
+  bool isHeaderInUnavailableModule(const FileEntry *Header);
+
   /// \brief Retrieve a module with the given name.
   ///
   /// \param The name of the module to look up.
@@ -188,7 +200,7 @@
 
   /// \brief Adds this header to the given module.
   void addHeader(Module *Mod, const FileEntry *Header);
-  
+
   /// \brief Parse the given module map file, and record any modules we 
   /// encounter.
   ///

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Fri Dec 30 22:05:44 2011
@@ -527,7 +527,9 @@
       SUBMODULE_IMPORTS = 5,
       /// \brief Specifies the submodules that are re-exported from this 
       /// submodule.
-      SUBMODULE_EXPORTS = 6
+      SUBMODULE_EXPORTS = 6,
+      /// \brief Specifies a required feature.
+      SUBMODULE_REQUIRES = 7
     };
     
     /// \defgroup ASTAST AST file AST constants

Modified: cfe/trunk/lib/Basic/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Module.cpp (original)
+++ cfe/trunk/lib/Basic/Module.cpp Fri Dec 30 22:05:44 2011
@@ -13,7 +13,11 @@
 //===----------------------------------------------------------------------===//
 #include "clang/Basic/Module.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
 using namespace clang;
 
 Module::~Module() {
@@ -25,6 +29,36 @@
   
 }
 
+/// \brief Determine whether a translation unit built using the current
+/// language options has the given feature.
+static bool hasFeature(StringRef Feature, const LangOptions &LangOpts) {
+  return llvm::StringSwitch<bool>(Feature)
+           .Case("blocks", LangOpts.Blocks)
+           .Case("cplusplus", LangOpts.CPlusPlus)
+           .Case("cplusplus11", LangOpts.CPlusPlus0x)
+           .Case("objc", LangOpts.ObjC1)
+           .Case("objc_arc", LangOpts.ObjCAutoRefCount)
+           .Default(false);
+}
+
+bool 
+Module::isAvailable(const LangOptions &LangOpts, StringRef &Feature) const {
+  if (IsAvailable)
+    return true;
+
+  for (const Module *Current = this; Current; Current = Current->Parent) {
+    for (unsigned I = 0, N = Current->Requires.size(); I != N; ++I) {
+      if (!hasFeature(Current->Requires[I], LangOpts)) {
+        Feature = Current->Requires[I];
+        return false;
+      }
+    }
+  }
+
+  llvm_unreachable("could not find a reason why module is unavailable");
+  return false;
+}
+
 bool Module::isSubModuleOf(Module *Other) const {
   const Module *This = this;
   do {
@@ -72,6 +106,35 @@
   return Umbrella.dyn_cast<const DirectoryEntry *>();
 }
 
+void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts) {
+  Requires.push_back(Feature);
+
+  // If this feature is currently available, we're done.
+  if (hasFeature(Feature, LangOpts))
+    return;
+
+  if (!IsAvailable)
+    return;
+
+  llvm::SmallVector<Module *, 2> Stack;
+  Stack.push_back(this);
+  while (!Stack.empty()) {
+    Module *Current = Stack.back();
+    Stack.pop_back();
+
+    if (!Current->IsAvailable)
+      continue;
+
+    Current->IsAvailable = false;
+    for (llvm::StringMap<Module *>::iterator Sub = Current->SubModules.begin(),
+                                          SubEnd = Current->SubModules.end();
+         Sub != SubEnd; ++Sub) {
+      if (Sub->second->IsAvailable)
+        Stack.push_back(Sub->second);
+    }
+  }
+}
+
 static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
   for (unsigned I = 0, N = Id.size(); I != N; ++I) {
     if (I)
@@ -87,6 +150,17 @@
   if (IsExplicit)
     OS << "explicit ";
   OS << "module " << Name << " {\n";
+
+  if (!Requires.empty()) {
+    OS.indent(Indent + 2);
+    OS << "requires ";
+    for (unsigned I = 0, N = Requires.size(); I != N; ++I) {
+      if (I)
+        OS << ", ";
+      OS << Requires[I];
+    }
+    OS << "\n";
+  }
   
   if (const FileEntry *UmbrellaHeader = getUmbrellaHeader()) {
     OS.indent(Indent + 2);

Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Fri Dec 30 22:05:44 2011
@@ -667,7 +667,8 @@
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
                                      AST->getFileManager());
   AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
-                                         AST->getDiagnostics()));
+                                         AST->getDiagnostics(),
+                                         AST->ASTFileLangOpts));
   
   for (unsigned I = 0; I != NumRemappedFiles; ++I) {
     FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Fri Dec 30 22:05:44 2011
@@ -252,7 +252,8 @@
 
   // Create the Preprocessor.
   HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager(), 
-                                              getDiagnostics());
+                                              getDiagnostics(),
+                                              getLangOpts());
   PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(),
                         getSourceManager(), *HeaderInfo, *this, PTHMgr,
                         /*OwnsHeaderSearch=*/true);
@@ -1284,6 +1285,19 @@
       
       return 0;
     }
+
+    // Check whether this module is available.
+    StringRef Feature;
+    if (!Module->isAvailable(getLangOpts(), Feature)) {
+      getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
+        << Module->getFullModuleName()
+        << Feature
+        << SourceRange(Path.front().second, Path.back().second);
+      LastModuleImportLoc = ImportLoc;
+      LastModuleImportResult = 0;
+      return 0;
+    }
+
     ModuleManager->makeModuleVisible(Module, Visibility);
   }
   

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Fri Dec 30 22:05:44 2011
@@ -136,6 +136,10 @@
 static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
                                         clang::Module *Module,
                                         llvm::SmallString<256> &Includes) {
+  // Don't collect any headers for unavailable modules.
+  if (!Module->isAvailable())
+    return;
+
   // Add includes for each of these headers.
   for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
     if (LangOpts.ObjC1)
@@ -222,7 +226,17 @@
     
     return false;
   }
-  
+
+  // Check whether we can build this module at all.
+  StringRef Feature;
+  if (!Module->isAvailable(CI.getLangOpts(), Feature)) {
+    CI.getDiagnostics().Report(diag::err_module_unavailable)
+      << Module->getFullModuleName()
+      << Feature;
+
+    return false;
+  }
+
   // Do we have an umbrella header for this module?
   const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
   

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Fri Dec 30 22:05:44 2011
@@ -38,9 +38,10 @@
 
 ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
 
-HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags)
+HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+                           const LangOptions &LangOpts)
   : FileMgr(FM), Diags(Diags), FrameworkMap(64), 
-    ModMap(FileMgr, *Diags.getClient()) 
+    ModMap(FileMgr, *Diags.getClient(), LangOpts) 
 {
   AngledDirIdx = 0;
   SystemDirIdx = 0;
@@ -803,8 +804,8 @@
 }
 
 Module *HeaderSearch::findModuleForHeader(const FileEntry *File) {
-  if (Module *Module = ModMap.findModuleForHeader(File))
-    return Module;
+  if (Module *Mod = ModMap.findModuleForHeader(File))
+    return Mod;
   
   return 0;
 }

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Fri Dec 30 22:05:44 2011
@@ -69,7 +69,10 @@
   return Module::ExportDecl(Context, Unresolved.Wildcard);
 }
 
-ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC) {
+ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
+                     const LangOptions &LangOpts)
+  : LangOpts(LangOpts)
+{
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
   Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
             new DiagnosticsEngine(DiagIDs));
@@ -90,8 +93,14 @@
 Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
   llvm::DenseMap<const FileEntry *, Module *>::iterator Known
     = Headers.find(File);
-  if (Known != Headers.end())
+  if (Known != Headers.end()) {
+    // If a header corresponds to an unavailable module, don't report
+    // that it maps to anything.
+    if (!Known->second->isAvailable())
+      return 0;
+
     return Known->second;
+  }
   
   const DirectoryEntry *Dir = File->getDir();
   llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
@@ -110,7 +119,7 @@
       Module *UmbrellaModule = Result;
       while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
         UmbrellaModule = UmbrellaModule->Parent;
-      
+
       if (UmbrellaModule->InferSubmodules) {
         // Infer submodules for each of the directories we found between
         // the directory of the umbrella header and the directory where 
@@ -149,6 +158,12 @@
       }
       
       Headers[File] = Result;
+
+      // If a header corresponds to an unavailable module, don't report
+      // that it maps to anything.
+      if (!Result->isAvailable())
+        return 0;
+
       return Result;
     }
     
@@ -166,6 +181,67 @@
   return 0;
 }
 
+bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
+  llvm::DenseMap<const FileEntry *, Module *>::iterator Known
+    = Headers.find(Header);
+  if (Known != Headers.end())
+    return !Known->second->isAvailable();
+  
+  const DirectoryEntry *Dir = Header->getDir();
+  llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+  StringRef DirName = Dir->getName();
+
+  // Keep walking up the directory hierarchy, looking for a directory with
+  // an umbrella header.
+  do {    
+    llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
+      = UmbrellaDirs.find(Dir);
+    if (KnownDir != UmbrellaDirs.end()) {
+      Module *Found = KnownDir->second;
+      if (!Found->isAvailable())
+        return true;
+
+      // Search up the module stack until we find a module with an umbrella
+      // directory.
+      Module *UmbrellaModule = Found;
+      while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+        UmbrellaModule = UmbrellaModule->Parent;
+
+      if (UmbrellaModule->InferSubmodules) {
+        for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+          // Find or create the module that corresponds to this directory name.
+          StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+          Found = lookupModuleQualified(Name, Found);
+          if (!Found)
+            return false;
+          if (!Found->isAvailable())
+            return true;
+        }
+        
+        // Infer a submodule with the same name as this header file.
+        StringRef Name = llvm::sys::path::stem(Header->getName());
+        Found = lookupModuleQualified(Name, Found);
+        if (!Found)
+          return false;
+      }
+
+      return !Found->isAvailable();
+    }
+    
+    SkippedDirs.push_back(Dir);
+    
+    // Retrieve our parent path.
+    DirName = llvm::sys::path::parent_path(DirName);
+    if (DirName.empty())
+      break;
+    
+    // Resolve the parent path to a directory entry.
+    Dir = SourceMgr->getFileManager().getDirectory(DirName);
+  } while (Dir);
+  
+  return false;
+}
+
 Module *ModuleMap::findModule(StringRef Name) {
   llvm::StringMap<Module *>::iterator Known = Modules.find(Name);
   if (Known != Modules.end())
@@ -375,6 +451,7 @@
   /// \brief A token in a module map file.
   struct MMToken {
     enum TokenKind {
+      Comma,
       EndOfFile,
       HeaderKeyword,
       Identifier,
@@ -384,6 +461,7 @@
       ModuleKeyword,
       Period,
       UmbrellaKeyword,
+      RequiresKeyword,
       Star,
       StringLiteral,
       LBrace,
@@ -449,6 +527,7 @@
       ModuleId;
     bool parseModuleId(ModuleId &Id);
     void parseModuleDecl();
+    void parseRequiresDecl();
     void parseHeaderDecl(SourceLocation UmbrellaLoc);
     void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
     void parseExportDecl();
@@ -494,10 +573,15 @@
                  .Case("export", MMToken::ExportKeyword)
                  .Case("framework", MMToken::FrameworkKeyword)
                  .Case("module", MMToken::ModuleKeyword)
+                 .Case("requires", MMToken::RequiresKeyword)
                  .Case("umbrella", MMToken::UmbrellaKeyword)
                  .Default(MMToken::Identifier);
     break;
-      
+
+  case tok::comma:
+    Tok.Kind = MMToken::Comma;
+    break;
+
   case tok::eof:
     Tok.Kind = MMToken::EndOfFile;
     break;
@@ -614,6 +698,7 @@
 ///     'explicit'[opt] 'framework'[opt] 'module' module-id { module-member* }
 ///
 ///   module-member:
+///     requires-declaration
 ///     header-declaration
 ///     submodule-declaration
 ///     export-declaration
@@ -755,6 +840,10 @@
       parseExportDecl();
       break;
         
+    case MMToken::RequiresKeyword:
+      parseRequiresDecl();
+      break;
+
     case MMToken::UmbrellaKeyword: {
       SourceLocation UmbrellaLoc = consumeToken();
       if (Tok.is(MMToken::HeaderKeyword))
@@ -787,6 +876,43 @@
   ActiveModule = PreviousActiveModule;
 }
 
+/// \brief Parse a requires declaration.
+///
+///   requires-declaration:
+///     'requires' feature-list
+///
+///   feature-list:
+///     identifier ',' feature-list
+///     identifier
+void ModuleMapParser::parseRequiresDecl() {
+  assert(Tok.is(MMToken::RequiresKeyword));
+
+  // Parse 'requires' keyword.
+  consumeToken();
+
+  // Parse the feature-list.
+  do {
+    if (!Tok.is(MMToken::Identifier)) {
+      Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
+      HadError = true;
+      return;
+    }
+
+    // Consume the feature name.
+    std::string Feature = Tok.getString();
+    consumeToken();
+
+    // Add this feature.
+    ActiveModule->addRequirement(Feature, Map.LangOpts);
+
+    if (!Tok.is(MMToken::Comma))
+      break;
+
+    // Consume the comma.
+    consumeToken();
+  } while (true);
+}
+
 /// \brief Append to \p Paths the set of paths needed to get to the 
 /// subframework in which the given module lives.
 void appendSubframeworkPaths(Module *Mod, llvm::SmallVectorImpl<char> &Path) {
@@ -1123,12 +1249,14 @@
       parseModuleDecl();
       break;
       
+    case MMToken::Comma:
     case MMToken::ExportKeyword:
     case MMToken::HeaderKeyword:
     case MMToken::Identifier:
     case MMToken::LBrace:
     case MMToken::Period:
     case MMToken::RBrace:
+    case MMToken::RequiresKeyword:
     case MMToken::Star:
     case MMToken::StringLiteral:
     case MMToken::UmbrellaKeyword:
@@ -1149,8 +1277,8 @@
     return true;
   
   // Parse this module map file.
-  Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, LangOpts);
-  Diags->getClient()->BeginSourceFile(LangOpts);
+  Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
+  Diags->getClient()->BeginSourceFile(MMapLangOpts);
   ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir());
   bool Result = Parser.parseModuleMapFile();
   Diags->getClient()->EndSourceFile();

Modified: cfe/trunk/lib/Lex/PPLexerChange.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPLexerChange.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPLexerChange.cpp (original)
+++ cfe/trunk/lib/Lex/PPLexerChange.cpp Fri Dec 30 22:05:44 2011
@@ -355,6 +355,7 @@
       if (getDiagnostics().getDiagnosticLevel(
             diag::warn_uncovered_module_header, 
             StartLoc) != DiagnosticsEngine::Ignored) {
+        ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
         typedef llvm::sys::fs::recursive_directory_iterator
           recursive_directory_iterator;
         const DirectoryEntry *Dir = Mod->getUmbrellaDir();
@@ -363,20 +364,22 @@
              Entry != End && !EC; Entry.increment(EC)) {
           using llvm::StringSwitch;
           
-          // Check whether this entry has an extension typically associated with 
+          // Check whether this entry has an extension typically associated with
           // headers.
           if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->path()))
-              .Cases(".h", ".H", ".hh", ".hpp", true)
-              .Default(false))
+                 .Cases(".h", ".H", ".hh", ".hpp", true)
+                 .Default(false))
             continue;
 
           if (const FileEntry *Header = getFileManager().getFile(Entry->path()))
             if (!getSourceManager().hasFileInfo(Header)) {
-              // Find the 
-              llvm::SmallString<128> RelativePath;
-              computeRelativePath(FileMgr, Dir, Header, RelativePath);              
-              Diag(StartLoc, diag::warn_uncovered_module_header)
-                << RelativePath;
+              if (!ModMap.isHeaderInUnavailableModule(Header)) {
+                // Find the relative path that would access this header.
+                llvm::SmallString<128> RelativePath;
+                computeRelativePath(FileMgr, Dir, Header, RelativePath);              
+                Diag(StartLoc, diag::warn_uncovered_module_header)
+                  << RelativePath;
+              }
             }
         }
       }

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Dec 30 22:05:44 2011
@@ -2523,6 +2523,11 @@
       continue;
     }
     
+    if (!Mod->isAvailable()) {
+      // Modules that aren't available cannot be made visible.
+      continue;
+    }
+
     // Update the module's name visibility.
     Mod->NameVisibility = NameVisibility;
     
@@ -3247,6 +3252,19 @@
       CurrentModule->UnresolvedExports.clear();
       break;
     }
+    case SUBMODULE_REQUIRES: {
+      if (First) {
+        Error("missing submodule metadata record at beginning of block");
+        return Failure;
+      }
+
+      if (!CurrentModule)
+        break;
+
+      CurrentModule->addRequirement(StringRef(BlobStart, BlobLen), 
+                                    Context.getLangOptions());
+      break;
+    }
     }
   }
 

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Fri Dec 30 22:05:44 2011
@@ -1916,6 +1916,11 @@
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
   unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
 
+  Abbrev = new BitCodeAbbrev();
+  Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
+  unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
+
   // Write the submodule metadata block.
   RecordData Record;
   Record.push_back(getNumberOfModules(WritingModule));
@@ -1947,6 +1952,15 @@
     Record.push_back(Mod->InferExportWildcard);
     Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
     
+    // Emit the requirements.
+    for (unsigned I = 0, N = Mod->Requires.size(); I != N; ++I) {
+      Record.clear();
+      Record.push_back(SUBMODULE_REQUIRES);
+      Stream.EmitRecordWithBlob(RequiresAbbrev, Record,
+                                Mod->Requires[I].data(),
+                                Mod->Requires[I].size());
+    }
+
     // Emit the umbrella header, if there is one.
     if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) {
       Record.clear();

Added: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h?rev=147387&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h (added)
+++ cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h Fri Dec 30 22:05:44 2011
@@ -0,0 +1,5 @@
+class CXXOnly {
+ public:
+  CXXOnly();
+  ~CXXOnly();
+};

Propchange: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module.map?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module.map Fri Dec 30 22:05:44 2011
@@ -4,6 +4,11 @@
   module * {
     export *
   }
+  explicit module CXX {
+    requires cplusplus
+    header "cxx_other.h"
+  }
+
   explicit framework module SubFramework {
     umbrella header "SubFramework.h"
 

Added: cfe/trunk/test/Modules/requires.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/requires.m?rev=147387&view=auto
==============================================================================
--- cfe/trunk/test/Modules/requires.m (added)
+++ cfe/trunk/test/Modules/requires.m Fri Dec 30 22:05:44 2011
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
+
+__import_module__ DependsOnModule.CXX; // expected-error{{module 'DependsOnModule.CXX' requires feature 'cplusplus'}}
+

Modified: cfe/trunk/test/Modules/subframeworks.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/subframeworks.m?rev=147387&r1=147386&r2=147387&view=diff
==============================================================================
--- cfe/trunk/test/Modules/subframeworks.m (original)
+++ cfe/trunk/test/Modules/subframeworks.m Fri Dec 30 22:05:44 2011
@@ -1,5 +1,6 @@
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -x objective-c++ -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
 
 __import_module__ DependsOnModule;
 
@@ -14,3 +15,8 @@
   double *sfo1 = sub_framework_other;
 }
 
+#ifdef __cplusplus
+__import_module__ DependsOnModule.CXX;
+
+CXXOnly cxxonly;
+#endif





More information about the cfe-commits mailing list