r198082 - Implement MSVC header search algorithm in MicrosoftMode.

Will Wilson will at indefiant.com
Fri Dec 27 11:46:16 PST 2013


Author: lantictac
Date: Fri Dec 27 13:46:16 2013
New Revision: 198082

URL: http://llvm.org/viewvc/llvm-project?rev=198082&view=rev
Log:
Implement MSVC header search algorithm in MicrosoftMode.
Follows algorithm described here: http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx

Added:
    cfe/trunk/test/Preprocessor/microsoft-header-search/
    cfe/trunk/test/Preprocessor/microsoft-header-search.c
    cfe/trunk/test/Preprocessor/microsoft-header-search/a/
    cfe/trunk/test/Preprocessor/microsoft-header-search/a/b/
    cfe/trunk/test/Preprocessor/microsoft-header-search/a/b/include3.h
    cfe/trunk/test/Preprocessor/microsoft-header-search/a/findme.h
    cfe/trunk/test/Preprocessor/microsoft-header-search/a/include2.h
    cfe/trunk/test/Preprocessor/microsoft-header-search/findme.h
    cfe/trunk/test/Preprocessor/microsoft-header-search/include1.h
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Lex/HeaderSearch.h
    cfe/trunk/lib/Lex/HeaderSearch.cpp
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=198082&r1=198081&r2=198082&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Fri Dec 27 13:46:16 2013
@@ -300,6 +300,9 @@ def ext_pp_import_directive : Extension<
   InGroup<DiagGroup<"import-preprocessor-directive-pedantic">>;
 def err_pp_import_directive_ms : Error<
   "#import of type library is an unsupported Microsoft feature">;
+def ext_pp_include_search_ms : ExtWarn<
+  "#include resolved using non-portable MSVC search rules as: %0">,
+  InGroup<DiagGroup<"msvc-include">>;
 
 def ext_pp_ident_directive : Extension<"#ident is a language extension">;
 def ext_pp_include_next_directive : Extension<

Modified: cfe/trunk/include/clang/Lex/HeaderSearch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/HeaderSearch.h?rev=198082&r1=198081&r2=198082&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/HeaderSearch.h (original)
+++ cfe/trunk/include/clang/Lex/HeaderSearch.h Fri Dec 27 13:46:16 2013
@@ -158,6 +158,8 @@ class HeaderSearch {
   /// \brief Header-search options used to initialize this header search.
   IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
 
+  DiagnosticsEngine &Diags;
+  SourceManager &SourceMgr;
   FileManager &FileMgr;
   /// \#include search path information.  Requests for \#include "x" search the
   /// directory of the \#including file first, then each directory in SearchDirs
@@ -349,13 +351,15 @@ public:
   /// \returns If successful, this returns 'UsedDir', the DirectoryLookup member
   /// the file was found in, or null if not applicable.
   ///
+  /// \param IncludeLoc Used for diagnostics if valid.
+  ///
   /// \param isAngled indicates whether the file reference is a <> reference.
   ///
   /// \param CurDir If non-null, the file was found in the specified directory
   /// search location.  This is used to implement \#include_next.
   ///
-  /// \param CurFileEnt If non-null, indicates where the \#including file is, in
-  /// case a relative search is needed.
+  /// \param Includers Indicates where the \#including file(s) are, in case
+  /// relative searches are needed. In reverse order of inclusion.
   ///
   /// \param SearchPath If non-null, will be set to the search path relative
   /// to which the file was found. If the include path is absolute, SearchPath
@@ -368,10 +372,10 @@ public:
   /// \param SuggestedModule If non-null, and the file found is semantically
   /// part of a known module, this will be set to the module that should
   /// be imported instead of preprocessing/parsing the file found.
-  const FileEntry *LookupFile(StringRef Filename, bool isAngled,
-                              const DirectoryLookup *FromDir,
+  const FileEntry *LookupFile(StringRef Filename, SourceLocation IncludeLoc,
+                              bool isAngled, const DirectoryLookup *FromDir,
                               const DirectoryLookup *&CurDir,
-                              const FileEntry *CurFileEnt,
+                              ArrayRef<const FileEntry *> Includers,
                               SmallVectorImpl<char> *SearchPath,
                               SmallVectorImpl<char> *RelativePath,
                               ModuleMap::KnownHeader *SuggestedModule,

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=198082&r1=198081&r2=198082&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Fri Dec 27 13:46:16 2013
@@ -12,12 +12,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Lex/HeaderSearch.h"
-#include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Lex/HeaderMap.h"
 #include "clang/Lex/HeaderSearchOptions.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Lex/LexDiagnostic.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Capacity.h"
 #include "llvm/Support/FileSystem.h"
@@ -45,11 +45,11 @@ ExternalHeaderFileInfoSource::~ExternalH
 
 HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
                            SourceManager &SourceMgr, DiagnosticsEngine &Diags,
-                           const LangOptions &LangOpts, 
+                           const LangOptions &LangOpts,
                            const TargetInfo *Target)
-  : HSOpts(HSOpts), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
-    ModMap(SourceMgr, Diags, LangOpts, Target, *this)
-{
+    : HSOpts(HSOpts), Diags(Diags), SourceMgr(SourceMgr),
+      FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
+      ModMap(SourceMgr, Diags, LangOpts, Target, *this) {
   AngledDirIdx = 0;
   SystemDirIdx = 0;
   NoCurDirSearch = false;
@@ -493,20 +493,15 @@ void HeaderSearch::setTarget(const Targe
 
 /// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file,
 /// return null on failure.  isAngled indicates whether the file reference is
-/// for system \#include's or not (i.e. using <> instead of "").  CurFileEnt, if
-/// non-null, indicates where the \#including file is, in case a relative search
-/// is needed.
+/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
+/// non-empty, indicates where the \#including file(s) are, in case a relative
+/// search is needed. Microsoft mode will pass all \#including files.
 const FileEntry *HeaderSearch::LookupFile(
-    StringRef Filename,
-    bool isAngled,
-    const DirectoryLookup *FromDir,
-    const DirectoryLookup *&CurDir,
-    const FileEntry *CurFileEnt,
-    SmallVectorImpl<char> *SearchPath,
+    StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
+    const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
+    ArrayRef<const FileEntry *> Includers, SmallVectorImpl<char> *SearchPath,
     SmallVectorImpl<char> *RelativePath,
-    ModuleMap::KnownHeader *SuggestedModule,
-    bool SkipCache)
-{
+    ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) {
   if (!HSOpts->ModuleMapFiles.empty()) {
     // Preload all explicitly specified module map files. This enables modules
     // map files lying in a directory structure separate from the header files
@@ -546,44 +541,53 @@ const FileEntry *HeaderSearch::LookupFil
   }
 
   // Unless disabled, check to see if the file is in the #includer's
-  // directory.  This has to be based on CurFileEnt, not CurDir, because
-  // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
-  // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
+  // directory.  This cannot be based on CurDir, because each includer could be
+  // a #include of a subdirectory (#include "foo/bar.h") and a subsequent
+  // include of "baz.h" should resolve to "whatever/foo/baz.h".
   // This search is not done for <> headers.
-  if (CurFileEnt && !isAngled && !NoCurDirSearch) {
+  if (!Includers.empty() && !isAngled && !NoCurDirSearch) {
     SmallString<1024> TmpDir;
-    // Concatenate the requested file onto the directory.
-    // FIXME: Portability.  Filename concatenation should be in sys::Path.
-    TmpDir += CurFileEnt->getDir()->getName();
-    TmpDir.push_back('/');
-    TmpDir.append(Filename.begin(), Filename.end());
-    if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(),/*openFile=*/true)) {
-      // Leave CurDir unset.
-      // This file is a system header or C++ unfriendly if the old file is.
-      //
-      // Note that we only use one of FromHFI/ToHFI at once, due to potential
-      // reallocation of the underlying vector potentially making the first
-      // reference binding dangling.
-      HeaderFileInfo &FromHFI = getFileInfo(CurFileEnt);
-      unsigned DirInfo = FromHFI.DirInfo;
-      bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
-      StringRef Framework = FromHFI.Framework;
-
-      HeaderFileInfo &ToHFI = getFileInfo(FE);
-      ToHFI.DirInfo = DirInfo;
-      ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
-      ToHFI.Framework = Framework;
-
-      if (SearchPath != NULL) {
-        StringRef SearchPathRef(CurFileEnt->getDir()->getName());
-        SearchPath->clear();
-        SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
-      }
-      if (RelativePath != NULL) {
-        RelativePath->clear();
-        RelativePath->append(Filename.begin(), Filename.end());
+    for (ArrayRef<const FileEntry *>::iterator I(Includers.begin()),
+         E(Includers.end());
+         I != E; ++I) {
+      const FileEntry *Includer = *I;
+      // Concatenate the requested file onto the directory.
+      // FIXME: Portability.  Filename concatenation should be in sys::Path.
+      TmpDir = Includer->getDir()->getName();
+      TmpDir.push_back('/');
+      TmpDir.append(Filename.begin(), Filename.end());
+      if (const FileEntry *FE =
+              FileMgr.getFile(TmpDir.str(), /*openFile=*/true)) {
+        // Leave CurDir unset.
+        // This file is a system header or C++ unfriendly if the old file is.
+        //
+        // Note that we only use one of FromHFI/ToHFI at once, due to potential
+        // reallocation of the underlying vector potentially making the first
+        // reference binding dangling.
+        HeaderFileInfo &FromHFI = getFileInfo(Includer);
+        unsigned DirInfo = FromHFI.DirInfo;
+        bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
+        StringRef Framework = FromHFI.Framework;
+
+        HeaderFileInfo &ToHFI = getFileInfo(FE);
+        ToHFI.DirInfo = DirInfo;
+        ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
+        ToHFI.Framework = Framework;
+
+        if (SearchPath != NULL) {
+          StringRef SearchPathRef(Includer->getDir()->getName());
+          SearchPath->clear();
+          SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+        }
+        if (RelativePath != NULL) {
+          RelativePath->clear();
+          RelativePath->append(Filename.begin(), Filename.end());
+        }
+        if (I != Includers.begin())
+          Diags.Report(IncludeLoc, diag::ext_pp_include_search_ms)
+              << FE->getName();
+        return FE;
       }
-      return FE;
     }
   }
 
@@ -667,18 +671,18 @@ const FileEntry *HeaderSearch::LookupFil
   // a header in a framework that is currently being built, and we couldn't
   // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
   // "Foo" is the name of the framework in which the including header was found.
-  if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) {
-    HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt);
+  if (!Includers.empty() && !isAngled &&
+      Filename.find('/') == StringRef::npos) {
+    HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front());
     if (IncludingHFI.IndexHeaderMapHeader) {
       SmallString<128> ScratchFilename;
       ScratchFilename += IncludingHFI.Framework;
       ScratchFilename += '/';
       ScratchFilename += Filename;
-      
-      const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true,
-                                           FromDir, CurDir, CurFileEnt, 
-                                           SearchPath, RelativePath,
-                                           SuggestedModule);
+
+      const FileEntry *Result = LookupFile(
+          ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
+          Includers.front(), SearchPath, RelativePath, SuggestedModule);
       std::pair<unsigned, unsigned> &CacheLookup 
         = LookupFileCache.GetOrCreateValue(Filename).getValue();
       CacheLookup.second

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=198082&r1=198081&r2=198082&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Fri Dec 27 13:46:16 2013
@@ -560,12 +560,12 @@ const FileEntry *Preprocessor::LookupFil
     SmallVectorImpl<char> *RelativePath,
     ModuleMap::KnownHeader *SuggestedModule,
     bool SkipCache) {
-  // If the header lookup mechanism may be relative to the current file, pass in
-  // info about where the current file is.
-  const FileEntry *CurFileEnt = 0;
+  // If the header lookup mechanism may be relative to the current inclusion
+  // stack, record the parent #includes.
+  SmallVector<const FileEntry *, 16> Includers;
   if (!FromDir) {
     FileID FID = getCurrentFileLexer()->getFileID();
-    CurFileEnt = SourceMgr.getFileEntryForID(FID);
+    const FileEntry *FileEnt = SourceMgr.getFileEntryForID(FID);
 
     // If there is no file entry associated with this file, it must be the
     // predefines buffer.  Any other file is not lexed with a normal lexer, so
@@ -573,17 +573,31 @@ const FileEntry *Preprocessor::LookupFil
     // predefines buffer, resolve #include references (which come from the
     // -include command line argument) as if they came from the main file, this
     // affects file lookup etc.
-    if (CurFileEnt == 0) {
-      FID = SourceMgr.getMainFileID();
-      CurFileEnt = SourceMgr.getFileEntryForID(FID);
+    if (!FileEnt)
+      FileEnt = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+
+    if (FileEnt)
+      Includers.push_back(FileEnt);
+
+    // MSVC searches the current include stack from top to bottom for
+    // headers included by quoted include directives.
+    // See: http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx
+    if (LangOpts.MicrosoftMode && !isAngled) {
+      for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
+        IncludeStackInfo &ISEntry = IncludeMacroStack[e - i - 1];
+        if (IsFileLexer(ISEntry))
+          if ((FileEnt = SourceMgr.getFileEntryForID(
+                   ISEntry.ThePPLexer->getFileID())))
+            Includers.push_back(FileEnt);
+      }
     }
   }
 
   // Do a standard file entry lookup.
   CurDir = CurDirLookup;
   const FileEntry *FE = HeaderInfo.LookupFile(
-      Filename, isAngled, FromDir, CurDir, CurFileEnt,
-      SearchPath, RelativePath, SuggestedModule, SkipCache);
+      Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
+      RelativePath, SuggestedModule, SkipCache);
   if (FE) {
     if (SuggestedModule)
       HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
@@ -591,6 +605,7 @@ const FileEntry *Preprocessor::LookupFil
     return FE;
   }
 
+  const FileEntry *CurFileEnt;
   // Otherwise, see if this is a subframework header.  If so, this is relative
   // to one of the headers on the #include stack.  Walk the list of the current
   // headers on the #include stack and pass them to HeaderInfo.

Modified: cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp?rev=198082&r1=198081&r2=198082&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp (original)
+++ cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp Fri Dec 27 13:46:16 2013
@@ -335,7 +335,7 @@ bool InclusionRewriter::HandleHasInclude
   bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
   const DirectoryLookup *CurDir;
   const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
-      Filename, isAngled, 0, CurDir,
+      Filename, SourceLocation(), isAngled, 0, CurDir,
       PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false);
 
   FileExists = File != 0;

Added: cfe/trunk/test/Preprocessor/microsoft-header-search.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/microsoft-header-search.c?rev=198082&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/microsoft-header-search.c (added)
+++ cfe/trunk/test/Preprocessor/microsoft-header-search.c Fri Dec 27 13:46:16 2013
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -I%S/microsoft-header-search %s -fms-compatibility -verify
+
+// expected-warning at microsoft-header-search/a/findme.h:3 {{findme.h successfully included using MS search rules}}
+// expected-warning at microsoft-header-search/a/b/include3.h:3 {{#include resolved using non-portable MSVC search rules as}}
+
+#include "microsoft-header-search/include1.h"
\ No newline at end of file

Added: cfe/trunk/test/Preprocessor/microsoft-header-search/a/b/include3.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/microsoft-header-search/a/b/include3.h?rev=198082&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/microsoft-header-search/a/b/include3.h (added)
+++ cfe/trunk/test/Preprocessor/microsoft-header-search/a/b/include3.h Fri Dec 27 13:46:16 2013
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "findme.h"
\ No newline at end of file

Added: cfe/trunk/test/Preprocessor/microsoft-header-search/a/findme.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/microsoft-header-search/a/findme.h?rev=198082&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/microsoft-header-search/a/findme.h (added)
+++ cfe/trunk/test/Preprocessor/microsoft-header-search/a/findme.h Fri Dec 27 13:46:16 2013
@@ -0,0 +1,3 @@
+#pragma once
+
+#warning findme.h successfully included using MS search rules
\ No newline at end of file

Added: cfe/trunk/test/Preprocessor/microsoft-header-search/a/include2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/microsoft-header-search/a/include2.h?rev=198082&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/microsoft-header-search/a/include2.h (added)
+++ cfe/trunk/test/Preprocessor/microsoft-header-search/a/include2.h Fri Dec 27 13:46:16 2013
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "b/include3.h"
+#pragma once
+
+#include "b/include3.h"
\ No newline at end of file

Added: cfe/trunk/test/Preprocessor/microsoft-header-search/findme.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/microsoft-header-search/findme.h?rev=198082&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/microsoft-header-search/findme.h (added)
+++ cfe/trunk/test/Preprocessor/microsoft-header-search/findme.h Fri Dec 27 13:46:16 2013
@@ -0,0 +1,3 @@
+#pragma once
+
+#error Wrong findme.h included, MSVC header search incorrect
\ No newline at end of file

Added: cfe/trunk/test/Preprocessor/microsoft-header-search/include1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/microsoft-header-search/include1.h?rev=198082&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/microsoft-header-search/include1.h (added)
+++ cfe/trunk/test/Preprocessor/microsoft-header-search/include1.h Fri Dec 27 13:46:16 2013
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "a/include2.h"
+#pragma once
+
+#include "a/include2.h"
\ No newline at end of file





More information about the cfe-commits mailing list