Introduce module attributes into the module map grammar, along with a
single attribute ("system") that allows us to mark a module as being a
"system" module. Each of the headers that makes up a system module is
considered to be a system header, so that we (for example) suppress
warnings there.

If a module is being inferred for a framework, and that framework
directory is within a system frameworks directory, infer it as a
system framework.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149143 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 7af7c93..ff63bdb 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -134,7 +134,9 @@
         llvm::sys::path::append(FrameworkDirName, ModuleName + ".framework");
         if (const DirectoryEntry *FrameworkDir 
               = FileMgr.getDirectory(FrameworkDirName)) {
-          Module = getFrameworkModule(ModuleName, FrameworkDir);
+          bool IsSystem
+            = SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User;
+          Module = getFrameworkModule(ModuleName, FrameworkDir, IsSystem);
           if (Module)
             break;
         }
@@ -319,8 +321,10 @@
   Module *Module = 0;
   if (SuggestedModule) {
     if (const DirectoryEntry *FrameworkDir
-                                    = FileMgr.getDirectory(FrameworkName))
-      Module = HS.getFrameworkModule(ModuleName, FrameworkDir);
+                                        = FileMgr.getDirectory(FrameworkName)) {
+      bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
+      Module = HS.getFrameworkModule(ModuleName, FrameworkDir, IsSystem);
+    }
   }
   
   // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
@@ -858,7 +862,8 @@
 }
   
 Module *HeaderSearch::getFrameworkModule(StringRef Name, 
-                                         const DirectoryEntry *Dir) {
+                                         const DirectoryEntry *Dir,
+                                         bool IsSystem) {
   if (Module *Module = ModMap.findModule(Name))
     return Module;
   
@@ -907,7 +912,8 @@
   
   // Try to infer a module map from the top-level framework directory.
   Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(), 
-                                               TopFrameworkDir, 
+                                               TopFrameworkDir,
+                                               IsSystem,
                                                /*Parent=*/0);
   
   // Follow the submodule path to find the requested (sub)framework module
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 08a1e23..708da94 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -284,6 +284,7 @@
 Module *
 ModuleMap::inferFrameworkModule(StringRef ModuleName, 
                                 const DirectoryEntry *FrameworkDir,
+                                bool IsSystem,
                                 Module *Parent) {
   // Check whether we've already found this module.
   if (Module *Mod = lookupModuleQualified(ModuleName, Parent))
@@ -305,6 +306,9 @@
   
   Module *Result = new Module(ModuleName, SourceLocation(), Parent,
                               /*IsFramework=*/true, /*IsExplicit=*/false);
+  if (IsSystem)
+    Result->IsSystem = IsSystem;
+  
   if (!Parent)
     Modules[ModuleName] = Result;
   
@@ -338,7 +342,7 @@
           = FileMgr.getDirectory(Dir->path())) {
       // FIXME: Do we want to warn about subframeworks without umbrella headers?
       inferFrameworkModule(llvm::sys::path::stem(Dir->path()), SubframeworkDir,
-                           Result);
+                           IsSystem, Result);
     }
   }
 
@@ -454,7 +458,9 @@
       Star,
       StringLiteral,
       LBrace,
-      RBrace
+      RBrace,
+      LSquare,
+      RSquare
     } Kind;
     
     unsigned Location;
@@ -579,6 +585,10 @@
     Tok.Kind = MMToken::LBrace;
     break;
 
+  case tok::l_square:
+    Tok.Kind = MMToken::LSquare;
+    break;
+      
   case tok::period:
     Tok.Kind = MMToken::Period;
     break;
@@ -587,6 +597,10 @@
     Tok.Kind = MMToken::RBrace;
     break;
       
+  case tok::r_square:
+    Tok.Kind = MMToken::RSquare;
+    break;
+      
   case tok::star:
     Tok.Kind = MMToken::Star;
     break;
@@ -625,27 +639,42 @@
 
 void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
   unsigned braceDepth = 0;
+  unsigned squareDepth = 0;
   do {
     switch (Tok.Kind) {
     case MMToken::EndOfFile:
       return;
 
     case MMToken::LBrace:
-      if (Tok.is(K) && braceDepth == 0)
+      if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
         return;
         
       ++braceDepth;
       break;
-    
+
+    case MMToken::LSquare:
+      if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
+        return;
+      
+      ++squareDepth;
+      break;
+
     case MMToken::RBrace:
       if (braceDepth > 0)
         --braceDepth;
       else if (Tok.is(K))
         return;
       break;
-        
+
+    case MMToken::RSquare:
+      if (squareDepth > 0)
+        --squareDepth;
+      else if (Tok.is(K))
+        return;
+      break;
+
     default:
-      if (braceDepth == 0 && Tok.is(K))
+      if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))
         return;
       break;
     }
@@ -681,10 +710,28 @@
   return false;
 }
 
+namespace {
+  /// \brief Enumerates the known attributes.
+  enum AttributeKind {
+    /// \brief An unknown attribute.
+    AT_unknown,
+    /// \brief The 'system' attribute.
+    AT_system
+  };
+}
+
 /// \brief Parse a module declaration.
 ///
 ///   module-declaration:
-///     'explicit'[opt] 'framework'[opt] 'module' module-id { module-member* }
+///     'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt] 
+///       { module-member* }
+///
+///   attributes:
+///     attribute attributes
+///     attribute
+///
+///   attribute:
+///     [ identifier ]
 ///
 ///   module-member:
 ///     requires-declaration
@@ -777,6 +824,49 @@
   StringRef ModuleName = Id.back().first;
   SourceLocation ModuleNameLoc = Id.back().second;
   
+  // Parse the optional attribute list.
+  bool IsSystem = false;
+  while (Tok.is(MMToken::LSquare)) {
+    // Consume the '['.
+    SourceLocation LSquareLoc = consumeToken();
+    
+    // Check whether we have an attribute name here.
+    if (!Tok.is(MMToken::Identifier)) {
+      Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
+      skipUntil(MMToken::RSquare);
+      if (Tok.is(MMToken::RSquare))
+        consumeToken();
+      continue;
+    }
+    
+    // Decode the attribute name.
+    AttributeKind Attribute 
+      = llvm::StringSwitch<AttributeKind>(Tok.getString())
+        .Case("system", AT_system)
+        .Default(AT_unknown);
+    switch (Attribute) {
+    case AT_unknown:
+      Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
+        << Tok.getString();
+      break;
+        
+    case AT_system:
+      IsSystem = true;
+      break;
+    }
+    consumeToken();
+    
+    // Consume the ']'.
+    if (!Tok.is(MMToken::RSquare)) {
+      Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
+      Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
+      skipUntil(MMToken::RSquare);
+    }
+
+    if (Tok.is(MMToken::RSquare))
+      consumeToken();
+  }
+  
   // Parse the opening brace.
   if (!Tok.is(MMToken::LBrace)) {
     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
@@ -818,6 +908,8 @@
   ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
                                         Explicit).first;
   ActiveModule->DefinitionLoc = ModuleNameLoc;
+  if (IsSystem)
+    ActiveModule->IsSystem = true;
   
   bool Done = false;
   do {
@@ -1251,8 +1343,10 @@
     case MMToken::HeaderKeyword:
     case MMToken::Identifier:
     case MMToken::LBrace:
+    case MMToken::LSquare:
     case MMToken::Period:
     case MMToken::RBrace:
+    case MMToken::RSquare:
     case MMToken::RequiresKeyword:
     case MMToken::Star:
     case MMToken::StringLiteral: