r179616 - rewrite-includes: Rewrite __has_include(_next) to get rid of a host dependency.

Benjamin Kramer benny.kra at googlemail.com
Tue Apr 16 12:08:41 PDT 2013


Author: d0k
Date: Tue Apr 16 14:08:41 2013
New Revision: 179616

URL: http://llvm.org/viewvc/llvm-project?rev=179616&view=rev
Log:
rewrite-includes: Rewrite __has_include(_next) to get rid of a host dependency.

This broke e.g. compiling a crash report from a glibc system on Darwin. Sadly,
the implementation had to game the lexer a lot as we're not using a real
preprocessor here. It also doesn't handle special cases like arbitrary macros in
__has_include, but since this macro isn't common outside of clang's headers we
can get away with that.

Fixes PR14422.

Differential Revision: http://llvm-reviews.chandlerc.com/D594

Added:
    cfe/trunk/test/Frontend/Inputs/rewrite-includes8.h
    cfe/trunk/test/Frontend/rewrite-includes-invalid-hasinclude.c
Modified:
    cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp
    cfe/trunk/test/Frontend/rewrite-includes.c

Modified: cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp?rev=179616&r1=179615&r2=179616&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp (original)
+++ cfe/trunk/lib/Rewrite/Frontend/InclusionRewriter.cpp Tue Apr 16 14:08:41 2013
@@ -15,7 +15,9 @@
 #include "clang/Rewrite/Frontend/Rewriters.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
@@ -74,6 +76,9 @@ private:
   void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken,
                            const MemoryBuffer &FromFile, StringRef EOL,
                            unsigned &NextToWrite, int &Lines);
+  bool HandleHasInclude(FileID FileId, Lexer &RawLex,
+                        const DirectoryLookup *Lookup, Token &Tok,
+                        bool &FileExists);
   const FileChange *FindFileChangeLocation(SourceLocation Loc) const;
   StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
 };
@@ -254,6 +259,75 @@ StringRef InclusionRewriter::NextIdentif
   return StringRef();
 }
 
+// Expand __has_include and __has_include_next if possible. If there's no
+// definitive answer return false.
+bool InclusionRewriter::HandleHasInclude(
+    FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok,
+    bool &FileExists) {
+  // Lex the opening paren.
+  RawLex.LexFromRawLexer(Tok);
+  if (Tok.isNot(tok::l_paren))
+    return false;
+
+  RawLex.LexFromRawLexer(Tok);
+
+  SmallString<128> FilenameBuffer;
+  StringRef Filename;
+  // Since the raw lexer doesn't give us angle_literals we have to parse them
+  // ourselves.
+  // FIXME: What to do if the file name is a macro?
+  if (Tok.is(tok::less)) {
+    RawLex.LexFromRawLexer(Tok);
+
+    FilenameBuffer += '<';
+    do {
+      if (Tok.is(tok::eod)) // Sanity check.
+        return false;
+
+      if (Tok.is(tok::raw_identifier))
+        PP.LookUpIdentifierInfo(Tok);
+
+      // Get the string piece.
+      SmallVector<char, 128> TmpBuffer;
+      bool Invalid = false;
+      StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid);
+      if (Invalid)
+        return false;
+
+      FilenameBuffer += TmpName;
+
+      RawLex.LexFromRawLexer(Tok);
+    } while (Tok.isNot(tok::greater));
+
+    FilenameBuffer += '>';
+    Filename = FilenameBuffer;
+  } else {
+    if (Tok.isNot(tok::string_literal))
+      return false;
+
+    bool Invalid = false;
+    Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid);
+    if (Invalid)
+      return false;
+  }
+
+  // Lex the closing paren.
+  RawLex.LexFromRawLexer(Tok);
+  if (Tok.isNot(tok::r_paren))
+    return false;
+
+  // Now ask HeaderInfo if it knows about the header.
+  // FIXME: Subframeworks aren't handled here. Do we care?
+  bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
+  const DirectoryLookup *CurDir;
+  const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
+      Filename, isAngled, 0, CurDir,
+      PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false);
+
+  FileExists = File != 0;
+  return true;
+}
+
 /// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it
 /// and including content of included files recursively.
 bool InclusionRewriter::Process(FileID FileId,
@@ -291,7 +365,7 @@ bool InclusionRewriter::Process(FileID F
       RawLex.LexFromRawLexer(RawToken);
       if (RawToken.is(tok::raw_identifier))
         PP.LookUpIdentifierInfo(RawToken);
-      if (RawToken.is(tok::identifier)) {
+      if (RawToken.is(tok::identifier) || RawToken.is(tok::kw_if)) {
         switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
           case tok::pp_include:
           case tok::pp_include_next:
@@ -337,6 +411,50 @@ bool InclusionRewriter::Process(FileID F
             }
             break;
           }
+          case tok::pp_if:
+          case tok::pp_elif:
+            // Rewrite special builtin macros to avoid pulling in host details.
+            do {
+              // Walk over the directive.
+              RawLex.LexFromRawLexer(RawToken);
+              if (RawToken.is(tok::raw_identifier))
+                PP.LookUpIdentifierInfo(RawToken);
+
+              if (RawToken.is(tok::identifier)) {
+                bool HasFile;
+                SourceLocation Loc = RawToken.getLocation();
+
+                // Rewrite __has_include(x)
+                if (RawToken.getIdentifierInfo()->isStr("__has_include")) {
+                  if (!HandleHasInclude(FileId, RawLex, 0, RawToken, HasFile))
+                    continue;
+                  // Rewrite __has_include_next(x)
+                } else if (RawToken.getIdentifierInfo()->isStr(
+                               "__has_include_next")) {
+                  const DirectoryLookup *Lookup = PP.GetCurDirLookup();
+                  if (Lookup)
+                    ++Lookup;
+
+                  if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken,
+                                        HasFile))
+                    continue;
+                } else {
+                  continue;
+                }
+                // Replace the macro with (0) or (1), followed by the commented
+                // out macro for reference.
+                OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc),
+                                  EOL, Line);
+                OS << '(' << (int) HasFile << ")/*";
+                OutputContentUpTo(FromFile, NextToWrite,
+                                  SM.getFileOffset(RawToken.getLocation()) +
+                                  RawToken.getLength(),
+                                  EOL, Line);
+                OS << "*/";
+              }
+            } while (RawToken.isNot(tok::eod));
+
+            break;
           default:
             break;
         }

Added: cfe/trunk/test/Frontend/Inputs/rewrite-includes8.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/Inputs/rewrite-includes8.h?rev=179616&view=auto
==============================================================================
--- cfe/trunk/test/Frontend/Inputs/rewrite-includes8.h (added)
+++ cfe/trunk/test/Frontend/Inputs/rewrite-includes8.h Tue Apr 16 14:08:41 2013
@@ -0,0 +1,5 @@
+#if __has_include_next(<rewrite-includes8.h>)
+#elif __has_include(<rewrite-includes8.hfail>)
+#endif
+#if !__has_include("rewrite-includes8.h")
+#endif

Added: cfe/trunk/test/Frontend/rewrite-includes-invalid-hasinclude.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/rewrite-includes-invalid-hasinclude.c?rev=179616&view=auto
==============================================================================
--- cfe/trunk/test/Frontend/rewrite-includes-invalid-hasinclude.c (added)
+++ cfe/trunk/test/Frontend/rewrite-includes-invalid-hasinclude.c Tue Apr 16 14:08:41 2013
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -E -frewrite-includes -DFIRST -I %S/Inputs %s -o - | FileCheck -strict-whitespace %s
+
+#if __has_include bar.h
+#endif
+
+#if __has_include(bar.h)
+#endif
+
+#if __has_include(<bar.h)
+#endif
+
+// CHECK: #if __has_include bar.h
+// CHECK: #endif
+// CHECK: #if __has_include(bar.h)
+// CHECK: #endif
+// CHECK: #if __has_include(<bar.h)
+// CHECK: #endif

Modified: cfe/trunk/test/Frontend/rewrite-includes.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/rewrite-includes.c?rev=179616&r1=179615&r2=179616&view=diff
==============================================================================
--- cfe/trunk/test/Frontend/rewrite-includes.c (original)
+++ cfe/trunk/test/Frontend/rewrite-includes.c Tue Apr 16 14:08:41 2013
@@ -18,6 +18,7 @@ A(1,2)
                                   continues */
 #include "rewrite-includes7.h"
 #include "rewrite-includes7.h"
+#include "rewrite-includes8.h"
 // ENDCOMPARE
 // CHECK: {{^}}// STARTCOMPARE{{$}}
 // CHECK-NEXT: {{^}}#define A(a,b) a ## b{{$}}
@@ -88,6 +89,16 @@ A(1,2)
 // CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
 // CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
 // CHECK-NEXT: {{^}}# 21 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes8.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*[/\\]Inputs[/\\]}}rewrite-includes8.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if (1)/*__has_include_next(<rewrite-includes8.h>)*/{{$}}
+// CHECK-NEXT: {{^}}#elif (0)/*__has_include(<rewrite-includes8.hfail>)*/{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}#if !(1)/*__has_include("rewrite-includes8.h")*/{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}# 22 "{{.*}}rewrite-includes.c" 2{{$}}
 // CHECK-NEXT: {{^}}// ENDCOMPARE{{$}}
 
 // CHECKNL: {{^}}// STARTCOMPARE{{$}}
@@ -142,4 +153,12 @@ A(1,2)
 // CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
 // CHECKNL-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
 // CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECKNL-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECKNL-NEXT: {{^}}#include "rewrite-includes8.h"{{$}}
+// CHECKNL-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECKNL-NEXT: {{^}}#if (1)/*__has_include_next(<rewrite-includes8.h>)*/{{$}}
+// CHECKNL-NEXT: {{^}}#elif (0)/*__has_include(<rewrite-includes8.hfail>)*/{{$}}
+// CHECKNL-NEXT: {{^}}#endif{{$}}
+// CHECKNL-NEXT: {{^}}#if !(1)/*__has_include("rewrite-includes8.h")*/{{$}}
+// CHECKNL-NEXT: {{^}}#endif{{$}}
 // CHECKNL-NEXT: {{^}}// ENDCOMPARE{{$}}





More information about the cfe-commits mailing list