erikjv updated the summary for this revision.
erikjv updated this revision to Diff 62748.
erikjv added a comment.

This version stores/loads the conditional stack in the preprocessor the the 
generated pch file. It suppresses errors about unfinished conditional 
preprocessor blocks, and after restoring, it will check if the block is closed 
in the main file.


http://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
@@ -983,6 +983,7 @@
   RECORD(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS);
   RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES);
   RECORD(DELETE_EXPRS_TO_ANALYZE);
+  RECORD(PP_CONDITIONAL_STACK);
 
   // SourceManager Block.
   BLOCK(SOURCE_MANAGER_BLOCK);
@@ -2140,6 +2141,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
@@ -2803,6 +2803,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
@@ -140,6 +140,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
@@ -130,6 +130,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
@@ -682,9 +682,7 @@
   } 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();
@@ -2528,6 +2526,11 @@
     return true;
   }
   
+  if (PP->IsRecordingPreamble()) {
+    PP->setRecordedPreambleConditionalStack(ConditionalStack);
+    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
@@ -1972,6 +1972,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
@@ -580,7 +580,9 @@
       MSSTRUCT_PRAGMA_OPTIONS = 55,
 
       /// \brief Record code for \#pragma ms_struct options.
-      POINTERS_TO_MEMBERS_PRAGMA_OPTIONS = 56
+      POINTERS_TO_MEMBERS_PRAGMA_OPTIONS = 56,
+
+      PP_CONDITIONAL_STACK = 57,
     };
 
     /// \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
@@ -81,6 +81,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
@@ -277,6 +277,58 @@
   /// This is used when loading a precompiled preamble.
   std::pair<int, bool> SkipMainFilePreamble;
 
+  class PreambleConditionalStackStore {
+  public:
+    enum State {
+      Off = 0,
+      Recording = 1,
+      Replaying = 2,
+      Done = 3
+    };
+    typedef SmallVector<PPConditionalInfo, 4> Stack;
+
+    PreambleConditionalStackStore()
+      : ConditionalStack(nullptr, Off)
+    {}
+    ~PreambleConditionalStackStore()
+    { delete ConditionalStack.getPointer(); }
+
+    void setState(State s) {
+      ConditionalStack.setInt(s);
+    }
+
+    void startRecording() { ConditionalStack.setInt(Recording); }
+    bool isRecording() const { return ConditionalStack.getInt() == Recording; }
+    bool isReplaying() const { return ConditionalStack.getInt() == Replaying; }
+
+    const Stack &getStack() const {
+      assert(ConditionalStack.getPointer());
+      return *ConditionalStack.getPointer();
+    }
+
+    void doneReplaying() {
+      assert(ConditionalStack.getPointer());
+      delete ConditionalStack.getPointer();
+      ConditionalStack.setPointer(nullptr);
+      setState(Done);
+    }
+
+    void setStack(const Stack &s)
+    {
+      if (!isRecording() && !isReplaying())
+        return;
+      if (auto ptr = ConditionalStack.getPointer())
+        *ptr = s;
+      else
+        ConditionalStack.setPointer(new Stack(s));
+    }
+
+    bool HasRecordedPreamble() const { return ConditionalStack.getPointer(); }
+
+  private:
+    llvm::PointerIntPair<Stack *, 2, State> ConditionalStack;
+  } 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.
   ///
@@ -1904,6 +1956,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.setState(PreambleConditionalStackStore::Replaying);
+    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

Reply via email to