[cfe-commits] r149611 - in /cfe/trunk: include/clang/Lex/ lib/Basic/ lib/Frontend/ lib/Headers/ lib/Lex/ test/Modules/ test/Modules/Inputs/System/ test/Modules/Inputs/System/usr/ test/Modules/Inputs/System/usr/include/

Douglas Gregor dgregor at apple.com
Thu Feb 2 10:42:49 PST 2012


Author: dgregor
Date: Thu Feb  2 12:42:48 2012
New Revision: 149611

URL: http://llvm.org/viewvc/llvm-project?rev=149611&view=rev
Log:
Back out my heinous hack that tricked the module generation mechanism
into using non-absolute system includes (<foo>)...

... and introduce another hack that is simultaneously more heineous
and more effective. We whitelist Clang-supplied headers that augment
or override system headers (such as float.h, stdarg.h, and
tgmath.h). For these headers, Clang does not provide a module
mapping. Instead, a system-supplied module map can refer to these
headers in a system module, and Clang will look both in its own
include directory and wherever the system-supplied module map
suggests, then adds either or both headers. The end result is that
Clang-supplied headers get merged into the system-supplied module for
the C standard library.

As a drive-by, fix up a few dependencies in the _Builtin_instrinsics
module.


Added:
    cfe/trunk/test/Modules/Inputs/System/
    cfe/trunk/test/Modules/Inputs/System/usr/
    cfe/trunk/test/Modules/Inputs/System/usr/include/
    cfe/trunk/test/Modules/Inputs/System/usr/include/module.map
    cfe/trunk/test/Modules/Inputs/System/usr/include/stdbool.h
    cfe/trunk/test/Modules/Inputs/System/usr/include/stdint.h
    cfe/trunk/test/Modules/Inputs/System/usr/include/stdio.h
    cfe/trunk/test/Modules/cstd.m
Modified:
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/lib/Basic/Module.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/Frontend/InitHeaderSearch.cpp
    cfe/trunk/lib/Headers/module.map
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/test/Modules/compiler_builtins.m

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=149611&r1=149610&r2=149611&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Thu Feb  2 12:42:48 2012
@@ -41,6 +41,10 @@
   const LangOptions &LangOpts;
   const TargetInfo *Target;
   
+  /// \brief The directory used for Clang-supplied, builtin include headers,
+  /// such as "stdint.h".
+  const DirectoryEntry *BuiltinIncludeDir;
+  
   /// \brief Language options used to parse the module map itself.
   ///
   /// These are always simple C language options.
@@ -102,6 +106,12 @@
   /// \brief Set the target information.
   void setTarget(const TargetInfo &Target);
 
+  /// \brief Set the directory that contains Clang-supplied include
+  /// files, such as our stdarg.h or tgmath.h.
+  void setBuiltinIncludeDir(const DirectoryEntry *Dir) {
+    BuiltinIncludeDir = Dir;
+  }
+
   /// \brief Retrieve the module that owns the given header file, if any.
   ///
   /// \param File The header file that is likely to be included.

Modified: cfe/trunk/lib/Basic/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=149611&r1=149610&r2=149611&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Module.cpp (original)
+++ cfe/trunk/lib/Basic/Module.cpp Thu Feb  2 12:42:48 2012
@@ -32,6 +32,8 @@
   if (Parent) {
     if (!Parent->isAvailable())
       IsAvailable = false;
+    if (Parent->IsSystem)
+      IsSystem = true;
     
     Parent->SubModuleIndex[Name] = Parent->SubModules.size();
     Parent->SubModules.push_back(this);

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=149611&r1=149610&r2=149611&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Thu Feb  2 12:42:48 2012
@@ -126,32 +126,6 @@
                           Sysroot, OS);
 }
 
-/// \brief Add an appropriate #include/#import for the given header within
-/// the current module context.
-static void addHeaderInclude(StringRef Header, 
-                             bool IsBuiltinModule,
-                             const LangOptions &LangOpts,
-                             llvm::SmallString<256> &Includes) {
-  if (IsBuiltinModule) {
-    // Our own builtin headers play some evil tricks that depend both on
-    // knowing that our headers will be found first and on include_next. To
-    // Make sure these include_next tricks work, we include with <> and
-    // just the filename itself rather than using an absolutely path.
-    // FIXME: Is there some sensible way to generalize this?
-    Includes += "#include <";
-    Includes += llvm::sys::path::filename(Header);
-    Includes += ">\n";
-    return;
-  }
-  
-  if (LangOpts.ObjC1)
-    Includes += "#import \"";
-  else
-    Includes += "#include \"";  
-  Includes += Header;
-  Includes += "\"\n";
-}
-
 /// \brief Collect the set of header includes needed to construct the given 
 /// module.
 ///
@@ -163,21 +137,31 @@
                                         FileManager &FileMgr,
                                         ModuleMap &ModMap,
                                         clang::Module *Module,
-                                        bool IsBuiltinModule,
                                         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)
-    addHeaderInclude(Module->Headers[I]->getName(), IsBuiltinModule, LangOpts, 
-                     Includes);
+  for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
+    if (LangOpts.ObjC1)
+      Includes += "#import \"";
+    else
+      Includes += "#include \"";
+    Includes += Module->Headers[I]->getName();
+    Includes += "\"\n";
+  }
 
   if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
-    if (Module->Parent)
-      addHeaderInclude(UmbrellaHeader->getName(), IsBuiltinModule, LangOpts, 
-                       Includes);
+    if (Module->Parent) {
+      // Include the umbrella header for submodules.
+      if (LangOpts.ObjC1)
+        Includes += "#import \"";
+      else
+        Includes += "#include \"";
+      Includes += UmbrellaHeader->getName();
+      Includes += "\"\n";
+    }
   } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
     // Add all of the headers we find in this subdirectory.
     llvm::error_code EC;
@@ -199,8 +183,13 @@
         if (ModMap.isHeaderInUnavailableModule(Header))
           continue;
       
-      // Include this header.
-      addHeaderInclude(Dir->path(), IsBuiltinModule, LangOpts, Includes);
+      // Include this header umbrella header for submodules.
+      if (LangOpts.ObjC1)
+        Includes += "#import \"";
+      else
+        Includes += "#include \"";
+      Includes += Dir->path();
+      Includes += "\"\n";
     }
   }
   
@@ -208,8 +197,7 @@
   for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
                                       SubEnd = Module->submodule_end();
        Sub != SubEnd; ++Sub)
-    collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub, 
-                                IsBuiltinModule, Includes);
+    collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub, Includes);
 }
 
 bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, 
@@ -261,11 +249,10 @@
   const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
   
   // Collect the set of #includes we need to build the module.
-  bool IsBuiltinModule = StringRef(Module->Name).startswith("_Builtin_");
   llvm::SmallString<256> HeaderContents;
   collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(),
     CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
-    Module, IsBuiltinModule, HeaderContents);
+    Module, HeaderContents);
   if (UmbrellaHeader && HeaderContents.empty()) {
     // Simple case: we have an umbrella header and there are no additional
     // includes, we can just parse the umbrella header directly.

Modified: cfe/trunk/lib/Frontend/InitHeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/InitHeaderSearch.cpp?rev=149611&r1=149610&r2=149611&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/InitHeaderSearch.cpp (original)
+++ cfe/trunk/lib/Frontend/InitHeaderSearch.cpp Thu Feb  2 12:42:48 2012
@@ -666,5 +666,13 @@
 
   Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
 
+  if (HSOpts.UseBuiltinIncludes) {
+    // Set up the builtin include directory in the module map.
+    llvm::sys::Path P(HSOpts.ResourceDir);
+    P.appendComponent("include");
+    if (const DirectoryEntry *Dir = HS.getFileMgr().getDirectory(P.str()))
+      HS.getModuleMap().setBuiltinIncludeDir(Dir);
+  }
+
   Init.Realize(Lang);
 }

Modified: cfe/trunk/lib/Headers/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Headers/module.map?rev=149611&r1=149610&r2=149611&view=diff
==============================================================================
--- cfe/trunk/lib/Headers/module.map (original)
+++ cfe/trunk/lib/Headers/module.map Thu Feb  2 12:42:48 2012
@@ -1,42 +1,3 @@
-module _Builtin_stdlib [system] {
-  explicit module float_constants {
-    header "float.h"
-  }
-
-  explicit module iso646 {
-    header "iso646.h"
-  }
-
-  explicit module limits {
-    header "limits.h"
-  }
-
-  explicit module stdalign {
-    header "stdalign.h"
-  }
-
-  explicit module stdarg {
-    header "stdarg.h"
-  }
-
-  explicit module stdbool {
-    header "stdbool.h"
-  }
-
-  explicit module stddef {
-    header "stddef.h"
-  }
-
-  explicit module stdint {
-    header "stdint.h"
-  }
-
-  explicit module varargs {
-    requires unavailable
-    header "varargs.h"
-  }
-}
-
 module _Builtin_intrinsics [system] {
   explicit module altivec {
     requires altivec
@@ -45,10 +6,16 @@
 
   explicit module intel {
     requires x86
+    export *
 
     header "immintrin.h"
     header "x86intrin.h"
 
+    explicit module mm_malloc {
+      header "mm_malloc.h"
+      export * // note: for <stdlib.h> dependency
+    }
+
     explicit module cpuid {
       header "cpuid.h"
     }
@@ -61,6 +28,7 @@
     explicit module sse {
       requires sse
       export mmx
+      export * // note: for hackish <emmintrin.h> dependency
       header "xmmintrin.h"
     }
 
@@ -136,12 +104,5 @@
       requires mm3dnow
       header "mm3dnow.h"
     }
-
-    explicit module mm_malloc {
-      header "mm_malloc.h"
-    }
   }
-
-  // FIXME: tgmath.h
-  // FIXME: unwind.h
 }

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=149611&r1=149610&r2=149611&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Feb  2 12:42:48 2012
@@ -71,7 +71,7 @@
 
 ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
                      const LangOptions &LangOpts, const TargetInfo *Target)
-  : LangOpts(LangOpts), Target(Target)
+  : LangOpts(LangOpts), Target(Target), BuiltinIncludeDir(0)
 {
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
   Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
@@ -499,7 +499,10 @@
     
     /// \brief The directory that this module map resides in.
     const DirectoryEntry *Directory;
-    
+
+    /// \brief The directory containing Clang-supplied headers.
+    const DirectoryEntry *BuiltinIncludeDir;
+
     /// \brief Whether an error occurred.
     bool HadError;
     
@@ -540,9 +543,11 @@
     explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, 
                              DiagnosticsEngine &Diags,
                              ModuleMap &Map,
-                             const DirectoryEntry *Directory)
+                             const DirectoryEntry *Directory,
+                             const DirectoryEntry *BuiltinIncludeDir)
       : L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map), 
-        Directory(Directory), HadError(false), ActiveModule(0)
+        Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir), 
+        HadError(false), ActiveModule(0)
     {
       TargetOptions TargetOpts;
       TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
@@ -1028,6 +1033,24 @@
   }
 }
 
+/// \brief Determine whether the given file name is the name of a builtin
+/// header, supplied by Clang to replace, override, or augment existing system
+/// headers.
+static bool isBuiltinHeader(StringRef FileName) {
+  return llvm::StringSwitch<bool>(FileName)
+      .Case("float.h", true)
+      .Case("iso646.h", true)
+      .Case("limits.h", true)
+      .Case("stdalign.h", true)
+      .Case("stdarg.h", true)
+      .Case("stdbool.h", true)
+      .Case("stddef.h", true)
+      .Case("stdint.h", true)
+      .Case("tgmath.h", true)
+      .Case("unwind.h", true)
+      .Default(false);
+}
+
 /// \brief Parse a header declaration.
 ///
 ///   header-declaration:
@@ -1058,6 +1081,7 @@
 
   // Look for this file.
   const FileEntry *File = 0;
+  const FileEntry *BuiltinFile = 0;
   llvm::SmallString<128> PathName;
   if (llvm::sys::path::is_absolute(FileName)) {
     PathName = FileName;
@@ -1090,6 +1114,24 @@
       // Lookup for normal headers.
       llvm::sys::path::append(PathName, FileName);
       File = SourceMgr.getFileManager().getFile(PathName);
+      
+      // If this is a system module with a top-level header, this header
+      // may have a counterpart (or replacement) in the set of headers
+      // supplied by Clang. Find that builtin header.
+      if (ActiveModule->IsSystem && !Umbrella && BuiltinIncludeDir &&
+          BuiltinIncludeDir != Directory && isBuiltinHeader(FileName)) {
+        llvm::SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
+        llvm::sys::path::append(BuiltinPathName, FileName);
+        BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
+        
+        // If Clang supplies this header but the underlying system does not,
+        // just silently swap in our builtin version. Otherwise, we'll end
+        // up adding both (later).
+        if (!File && BuiltinFile) {
+          File = BuiltinFile;
+          BuiltinFile = 0;
+        }
+      }
     }
   }
   
@@ -1113,6 +1155,10 @@
     } else {
       // Record this header.
       Map.addHeader(ActiveModule, File);
+      
+      // If there is a builtin counterpart to this file, add it now.
+      if (BuiltinFile)
+        Map.addHeader(ActiveModule, BuiltinFile);
     }
   } else {
     Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
@@ -1375,7 +1421,8 @@
   // Parse this module map file.
   Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
   Diags->getClient()->BeginSourceFile(MMapLangOpts);
-  ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir());
+  ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir(),
+                         BuiltinIncludeDir);
   bool Result = Parser.parseModuleMapFile();
   Diags->getClient()->EndSourceFile();
   

Added: cfe/trunk/test/Modules/Inputs/System/usr/include/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/System/usr/include/module.map?rev=149611&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/System/usr/include/module.map (added)
+++ cfe/trunk/test/Modules/Inputs/System/usr/include/module.map Thu Feb  2 12:42:48 2012
@@ -0,0 +1,21 @@
+module cstd [system] {
+  // Only in compiler support directory
+  module float_constants {
+    header "float.h"
+  }
+
+  // Only in system headers directory
+  module stdio {
+    header "stdio.h"
+  }
+
+  // In both directories (compiler support version wins, does not forward)
+  module stdbool {
+    header "stdbool.h"
+  }
+
+  // In both directories (compiler support version wins, forwards)
+  module stdint {
+    header "stdint.h"
+  }
+}

Added: cfe/trunk/test/Modules/Inputs/System/usr/include/stdbool.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/System/usr/include/stdbool.h?rev=149611&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/System/usr/include/stdbool.h (added)
+++ cfe/trunk/test/Modules/Inputs/System/usr/include/stdbool.h Thu Feb  2 12:42:48 2012
@@ -0,0 +1 @@
+// Testing hack: does not define bool/true/false.

Added: cfe/trunk/test/Modules/Inputs/System/usr/include/stdint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/System/usr/include/stdint.h?rev=149611&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/System/usr/include/stdint.h (added)
+++ cfe/trunk/test/Modules/Inputs/System/usr/include/stdint.h Thu Feb  2 12:42:48 2012
@@ -0,0 +1 @@
+typedef int my_awesome_nonstandard_integer_type;

Added: cfe/trunk/test/Modules/Inputs/System/usr/include/stdio.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/System/usr/include/stdio.h?rev=149611&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/System/usr/include/stdio.h (added)
+++ cfe/trunk/test/Modules/Inputs/System/usr/include/stdio.h Thu Feb  2 12:42:48 2012
@@ -0,0 +1,3 @@
+typedef struct { int id; } FILE;
+int fprintf(FILE*restrict, const char* restrict format, ...);
+

Modified: cfe/trunk/test/Modules/compiler_builtins.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/compiler_builtins.m?rev=149611&r1=149610&r2=149611&view=diff
==============================================================================
--- cfe/trunk/test/Modules/compiler_builtins.m (original)
+++ cfe/trunk/test/Modules/compiler_builtins.m Thu Feb  2 12:42:48 2012
@@ -1,22 +1,6 @@
 // RUN: rm -rf %t
 // RUN: %clang -fsyntax-only -fmodules -fmodule-cache-path %t -D__need_wint_t %s -Xclang -verify
 
- at import _Builtin_stdlib.float_constants;
-
-float getFltMax() { return FLT_MAX; }
-
- at import _Builtin_stdlib.limits;
-
-char getCharMax() { return CHAR_MAX; }
-
-// MS limits.h provides size_t.
-// XFAIL: win32
-size_t size; // expected-error{{unknown type name 'size_t'}}
-
- at import _Builtin_stdlib.stdint;
-
-intmax_t value;
-
 #ifdef __SSE__
 @import _Builtin_intrinsics.intel.sse;
 #endif

Added: cfe/trunk/test/Modules/cstd.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cstd.m?rev=149611&view=auto
==============================================================================
--- cfe/trunk/test/Modules/cstd.m (added)
+++ cfe/trunk/test/Modules/cstd.m Thu Feb  2 12:42:48 2012
@@ -0,0 +1,29 @@
+// RUN: rm -rf %t
+// RUN: %clang -fsyntax-only -isysroot %S/Inputs/System -fmodules -fmodule-cache-path %t -D__need_wint_t %s -Xclang -verify
+
+// Supplied by compiler, but referenced from the "/usr/include" module map.
+ at import cstd.float_constants;
+
+float getFltMax() { return FLT_MAX; }
+
+// Supplied by the "/usr/include" module map.
+ at import cstd.stdio;
+
+void test_fprintf(FILE *file) {
+  fprintf(file, "Hello, modules\n");
+}
+
+// Supplied by compiler, which forwards to the the "/usr/include" version.
+ at import cstd.stdint;
+
+my_awesome_nonstandard_integer_type value;
+
+// Supplied by the compiler; that version wins.
+ at import cstd.stdbool;
+
+#ifndef bool
+#  error "bool was not defined!"
+#endif
+
+
+





More information about the cfe-commits mailing list