[PATCH] D53866: [Preamble] Fix preamble for circular #includes

Nikolai Kosjar via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 30 07:12:14 PDT 2018


nik created this revision.
Herald added subscribers: cfe-commits, arphaman.

If a header file was processed for the second time, we could end up with
a wrong conditional stack and skipped ranges:

In the particular example, if the header guard is evaluated the second
time and it is decided to skip the conditional block, the corresponding
"#endif" is never seen since the preamble does not include it and we end
up in the Tok.is(tok::eof) case with a wrong conditional stack.

Fix this by resetting the conditional state in such a case.


Repository:
  rC Clang

https://reviews.llvm.org/D53866

Files:
  lib/Lex/PPDirectives.cpp
  test/Index/preamble-cyclic-include.cpp


Index: test/Index/preamble-cyclic-include.cpp
===================================================================
--- /dev/null
+++ test/Index/preamble-cyclic-include.cpp
@@ -0,0 +1,8 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-annotate-tokens=%s:4:1:8:1 %s 2>&1 | FileCheck %s
+// CHECK-NOT: error: unterminated conditional directive
+// CHECK-NOT: Skipping: [4:1 - 8:7]
+#ifndef A_H
+#define A_H
+#  include "preamble-cyclic-include.cpp"
+int bar();
+#endif
Index: lib/Lex/PPDirectives.cpp
===================================================================
--- lib/Lex/PPDirectives.cpp
+++ lib/Lex/PPDirectives.cpp
@@ -361,6 +361,14 @@
   }
 }
 
+static bool isMainFileIncludedAgain(const SourceManager &sourceManager,
+                                    HeaderSearch &headerSearch,
+                                    const FileEntry *fileEntry) {
+  return sourceManager.translateFile(fileEntry) ==
+             sourceManager.getMainFileID() &&
+         headerSearch.getFileInfo(fileEntry).NumIncludes > 1;
+}
+
 /// SkipExcludedConditionalBlock - We just read a \#if or related directive and
 /// decided that the subsequent tokens are in the \#if'd out portion of the
 /// file.  Lex the rest of the file, until we see an \#endif.  If
@@ -377,6 +385,8 @@
   ++NumSkipped;
   assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?");
 
+  const auto InitialConditionalStack = CurPPLexer->ConditionalStack;
+
   if (PreambleConditionalStack.reachedEOFWhileSkipping())
     PreambleConditionalStack.clearSkipInfo();
   else
@@ -407,9 +417,16 @@
       // We don't emit errors for unterminated conditionals here,
       // Lexer::LexEndOfFile can do that propertly.
       // Just return and let the caller lex after this #include.
-      if (PreambleConditionalStack.isRecording())
-        PreambleConditionalStack.SkipInfo.emplace(
-            HashTokenLoc, IfTokenLoc, FoundNonSkipPortion, FoundElse, ElseLoc);
+      if (PreambleConditionalStack.isRecording()) {
+        if (isMainFileIncludedAgain(getSourceManager(), HeaderInfo,
+                                    CurLexer->getFileEntry())) {
+          CurPPLexer->ConditionalStack = InitialConditionalStack;
+        } else {
+          PreambleConditionalStack.SkipInfo.emplace(HashTokenLoc, IfTokenLoc,
+                                                    FoundNonSkipPortion,
+                                                    FoundElse, ElseLoc);
+        }
+      }
       break;
     }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D53866.171689.patch
Type: text/x-patch
Size: 2491 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20181030/fdecebc2/attachment.bin>


More information about the cfe-commits mailing list