erikjv updated this revision to Diff 80589.

https://reviews.llvm.org/D15994

Files:
  include/clang/Lex/Preprocessor.h
  include/clang/Lex/PreprocessorLexer.h
  include/clang/Lex/PreprocessorOptions.h
  include/clang/Serialization/ASTBitCodes.h
  lib/Frontend/ASTUnit.cpp
  lib/Lex/Lexer.cpp
  lib/Lex/PPLexerChange.cpp
  lib/Lex/Preprocessor.cpp
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTWriter.cpp
  test/Lexer/preamble.c
  test/Lexer/preamble2.c

Index: test/Lexer/preamble2.c
===================================================================
--- /dev/null
+++ test/Lexer/preamble2.c
@@ -0,0 +1,19 @@
+// Preamble detection test: header with an include guard.
+#ifndef HEADER_H
+#define HEADER_H
+#include "foo"
+int bar;
+#endif
+
+// This test checks for detection of the preamble of a file, which
+// includes all of the starting comments and #includes.
+
+// RUN: %clang_cc1 -print-preamble %s > %t
+// RUN: echo END. >> %t
+// RUN: FileCheck < %t %s
+
+// CHECK: // Preamble detection test: header with an include guard.
+// CHECK-NEXT: #ifndef HEADER_H
+// CHECK-NEXT: #define HEADER_H
+// CHECK-NEXT: #include "foo"
+// CHECK-NEXT: END.
Index: test/Lexer/preamble.c
===================================================================
--- test/Lexer/preamble.c
+++ test/Lexer/preamble.c
@@ -9,15 +9,12 @@
 #pragma unknown
 #endif
 #ifdef WIBBLE
-#include "honk"
-#else
-int foo();
+#include "foo"
+int bar;
 #endif
 
 // This test checks for detection of the preamble of a file, which
-// includes all of the starting comments and #includes. Note that any
-// changes to the preamble part of this file must be mirrored in
-// Inputs/preamble.txt, since we diff against it.
+// includes all of the starting comments and #includes.
 
 // RUN: %clang_cc1 -print-preamble %s > %t
 // RUN: echo END. >> %t
@@ -33,4 +30,6 @@
 // CHECK-NEXT: #endif
 // CHECK-NEXT: #pragma unknown
 // CHECK-NEXT: #endif
+// CHECK-NEXT: #ifdef WIBBLE
+// CHECK-NEXT: #include "foo"
 // CHECK-NEXT: END.
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -1071,6 +1071,7 @@
   RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES);
   RECORD(DELETE_EXPRS_TO_ANALYZE);
   RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH);
+  RECORD(PP_CONDITIONAL_STACK);
 
   // SourceManager Block.
   BLOCK(SOURCE_MANAGER_BLOCK);
@@ -2233,6 +2234,17 @@
     Stream.EmitRecord(PP_COUNTER_VALUE, Record);
   }
 
+  if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) {
+    for (const auto &Cond : PP.getPreambleConditionalStack()) {
+      AddSourceLocation(Cond.IfLoc, Record);
+      Record.push_back(Cond.WasSkipping);
+      Record.push_back(Cond.FoundNonSkip);
+      Record.push_back(Cond.FoundElse);
+    }
+    Stream.EmitRecord(PP_CONDITIONAL_STACK, Record);
+    Record.clear();
+  }
+
   // Enter the preprocessor block.
   Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
 
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -2870,6 +2870,20 @@
       }
       break;
 
+    case PP_CONDITIONAL_STACK:
+      if (!Record.empty()) {
+        SmallVector<PPConditionalInfo, 4> ConditionalStack;
+        for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
+          auto loc = ReadSourceLocation(F, Record, Idx);
+          bool WasSkipping = Record[Idx++];
+          bool FoundNonSkip = Record[Idx++];
+          bool FoundElse = Record[Idx++];
+          ConditionalStack.push_back({ loc, WasSkipping, FoundNonSkip, FoundElse });
+        }
+        PP.setReplayablePreambleConditionalStack(ConditionalStack);
+      }
+      break;
+
     case PP_COUNTER_VALUE:
       if (!Record.empty() && Listener)
         Listener->ReadCounter(F, Record[0]);
Index: lib/Lex/Preprocessor.cpp
===================================================================
--- lib/Lex/Preprocessor.cpp
+++ lib/Lex/Preprocessor.cpp
@@ -150,6 +150,9 @@
     Ident_GetExceptionInfo = Ident_GetExceptionCode = nullptr;
     Ident_AbnormalTermination = nullptr;
   }
+
+  if (this->PPOpts->PreambleGeneration)
+    PreambleConditionalStack.startRecording();
 }
 
 Preprocessor::~Preprocessor() {
Index: lib/Lex/PPLexerChange.cpp
===================================================================
--- lib/Lex/PPLexerChange.cpp
+++ lib/Lex/PPLexerChange.cpp
@@ -46,6 +46,12 @@
   });
 }
 
+bool Preprocessor::isInPreamble() const {
+  if (IsFileLexer())
+    return IncludeMacroStack.size() == 1;
+  return false;
+}
+
 /// getCurrentLexer - Return the current file lexer being lexed from.  Note
 /// that this ignores any potentially active macro expansions and _Pragma
 /// expansions going on at the time.
@@ -129,6 +135,11 @@
     Callbacks->FileChanged(CurLexer->getFileLoc(),
                            PPCallbacks::EnterFile, FileType);
   }
+
+  if (PreambleConditionalStack.isReplaying()) {
+    CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack());
+    PreambleConditionalStack.doneReplaying();
+  }
 }
 
 /// EnterSourceFileWithPTH - Add a source file to the top of the include stack
Index: lib/Lex/Lexer.cpp
===================================================================
--- lib/Lex/Lexer.cpp
+++ lib/Lex/Lexer.cpp
@@ -535,8 +535,6 @@
 
   enum PreambleDirectiveKind {
     PDK_Skipped,
-    PDK_StartIf,
-    PDK_EndIf,
     PDK_Unknown
   };
 
@@ -559,8 +557,6 @@
 
   bool InPreprocessorDirective = false;
   Token TheTok;
-  Token IfStartTok;
-  unsigned IfCount = 0;
   SourceLocation ActiveCommentLoc;
 
   unsigned MaxLineOffset = 0;
@@ -643,33 +639,18 @@
               .Case("sccs", PDK_Skipped)
               .Case("assert", PDK_Skipped)
               .Case("unassert", PDK_Skipped)
-              .Case("if", PDK_StartIf)
-              .Case("ifdef", PDK_StartIf)
-              .Case("ifndef", PDK_StartIf)
+              .Case("if", PDK_Skipped)
+              .Case("ifdef", PDK_Skipped)
+              .Case("ifndef", PDK_Skipped)
               .Case("elif", PDK_Skipped)
               .Case("else", PDK_Skipped)
-              .Case("endif", PDK_EndIf)
+              .Case("endif", PDK_Skipped)
               .Default(PDK_Unknown);
 
         switch (PDK) {
         case PDK_Skipped:
           continue;
 
-        case PDK_StartIf:
-          if (IfCount == 0)
-            IfStartTok = HashTok;
-            
-          ++IfCount;
-          continue;
-            
-        case PDK_EndIf:
-          // Mismatched #endif. The preamble ends here.
-          if (IfCount == 0)
-            break;
-
-          --IfCount;
-          continue;
-            
         case PDK_Unknown:
           // We don't know what this directive is; stop at the '#'.
           break;
@@ -690,16 +671,13 @@
   } while (true);
   
   SourceLocation End;
-  if (IfCount)
-    End = IfStartTok.getLocation();
-  else if (ActiveCommentLoc.isValid())
+  if (ActiveCommentLoc.isValid())
     End = ActiveCommentLoc; // don't truncate a decl comment.
   else
     End = TheTok.getLocation();
 
   return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(),
-                        IfCount? IfStartTok.isAtStartOfLine()
-                               : TheTok.isAtStartOfLine());
+                        TheTok.isAtStartOfLine());
 }
 
 /// AdvanceToTokenCharacter - Given a location that specifies the start of a
@@ -2540,6 +2518,12 @@
     return true;
   }
   
+  if (PP->isRecordingPreamble()) {
+    PP->setRecordedPreambleConditionalStack(ConditionalStack);
+    if (PP->isInPreamble())
+      ConditionalStack.clear();
+  }
+
   // Issue diagnostics for unterminated #if and missing newline.
 
   // If we are in a #if directive, emit an error.
Index: lib/Frontend/ASTUnit.cpp
===================================================================
--- lib/Frontend/ASTUnit.cpp
+++ lib/Frontend/ASTUnit.cpp
@@ -1973,6 +1973,7 @@
   PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
   PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
   PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
+  PPOpts.PreambleGeneration = PrecompilePreambleAfterNParses != 0;
   
   // Override the resources path.
   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -585,6 +585,9 @@
       /// \brief Number of unmatched #pragma clang cuda_force_host_device begin
       /// directives we've seen.
       CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH = 57,
+
+      /// \brief The stack of open #ifs/#ifdefs recorded in a preamble.
+      PP_CONDITIONAL_STACK = 58,
     };
 
     /// \brief Record types used within a source manager block.
Index: include/clang/Lex/PreprocessorOptions.h
===================================================================
--- include/clang/Lex/PreprocessorOptions.h
+++ include/clang/Lex/PreprocessorOptions.h
@@ -80,6 +80,8 @@
   /// The boolean indicates whether the preamble ends at the start of a new
   /// line.
   std::pair<unsigned, bool> PrecompiledPreambleBytes;
+
+  bool PreambleGeneration = false;
   
   /// The implicit PTH input included at the start of the translation unit, or
   /// empty.
Index: include/clang/Lex/PreprocessorLexer.h
===================================================================
--- include/clang/Lex/PreprocessorLexer.h
+++ include/clang/Lex/PreprocessorLexer.h
@@ -176,6 +176,9 @@
   conditional_iterator conditional_end() const { 
     return ConditionalStack.end(); 
   }
+
+  void setConditionalLevels(const SmallVector<PPConditionalInfo, 4> &CL)
+  { ConditionalStack = CL; }
 };
 
 }  // end namespace clang
Index: include/clang/Lex/Preprocessor.h
===================================================================
--- include/clang/Lex/Preprocessor.h
+++ include/clang/Lex/Preprocessor.h
@@ -281,6 +281,60 @@
   /// This is used when loading a precompiled preamble.
   std::pair<int, bool> SkipMainFilePreamble;
 
+  class PreambleConditionalStackStore {
+    enum State {
+      Off = 0,
+      Recording = 1,
+      Replaying = 2,
+    };
+
+    void setState(State s) {
+      ConditionalStackState = s;
+    }
+
+  public:
+    typedef SmallVector<PPConditionalInfo, 4> Stack;
+
+    PreambleConditionalStackStore()
+      : ConditionalStack(nullptr)
+      , ConditionalStackState(Off)
+    {}
+    ~PreambleConditionalStackStore()
+    { delete ConditionalStack; }
+
+    void startRecording() { ConditionalStackState = Recording; }
+    void startReplaying() { ConditionalStackState = Replaying; }
+    bool isRecording() const { return ConditionalStackState == Recording; }
+    bool isReplaying() const { return ConditionalStackState == Replaying; }
+
+    const Stack &getStack() const {
+      assert(ConditionalStack);
+      return *ConditionalStack;
+    }
+
+    void doneReplaying() {
+      assert(ConditionalStack);
+      delete ConditionalStack;
+      ConditionalStack = nullptr;
+      setState(Off);
+    }
+
+    void setStack(const Stack &s) {
+      if (!isRecording() && !isReplaying())
+        return;
+      if (ConditionalStack)
+        *ConditionalStack = s;
+      else
+        ConditionalStack = new Stack(s);
+    }
+
+    bool hasRecordedPreamble() const { return ConditionalStack; }
+
+  private:
+    Stack *ConditionalStack;
+    State ConditionalStackState;
+  } PreambleConditionalStack;
+
   /// \brief The current top of the stack that we're lexing from if
   /// not expanding a macro and we are lexing directly from source code.
   ///
@@ -1676,6 +1730,11 @@
   /// \brief Return true if we're in the top-level file, not in a \#include.
   bool isInPrimaryFile() const;
 
+  /// \brief Return true if we're in the 1-level deep \#include. This is used
+  /// by the lexer to determine if it needs to generate errors about
+  /// unterminated \#if directives.
+  bool isInPreamble() const;
+
   /// \brief Handle cases where the \#include name is expanded
   /// from a macro as multiple tokens, which need to be glued together. 
   ///
@@ -1918,6 +1977,28 @@
   const FileEntry *getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
                                                           SourceLocation MLoc);
 
+  bool isRecordingPreamble() const {
+    return PreambleConditionalStack.isRecording();
+  }
+
+  bool hasRecordedPreamble() const {
+    return PreambleConditionalStack.hasRecordedPreamble();
+  }
+
+  const SmallVector<PPConditionalInfo, 4> &getPreambleConditionalStack() const
+  { return PreambleConditionalStack.getStack(); }
+
+  void setRecordedPreambleConditionalStack(
+      const SmallVector<PPConditionalInfo, 4> &s) {
+    PreambleConditionalStack.setStack(s);
+  }
+
+  void setReplayablePreambleConditionalStack(
+      const SmallVector<PPConditionalInfo, 4> &s) {
+    PreambleConditionalStack.startReplaying();
+    PreambleConditionalStack.setStack(s);
+  }
+
 private:
   // Macro handling.
   void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D15994: Allow for ... Erik Verbruggen via Phabricator via cfe-commits
    • [PATCH] D15994: Allow... Erik Verbruggen via Phabricator via cfe-commits

Reply via email to