summaryrefslogtreecommitdiffstats
path: root/include/clang/Lex/Preprocessor.h
diff options
context:
space:
mode:
authorErik Verbruggen <erikjv@me.com>2017-05-30 11:54:55 +0000
committerErik Verbruggen <erikjv@me.com>2017-05-30 11:54:55 +0000
commit0289cea07c4cf50b36f6f9c9e60ac2d35c624946 (patch)
tree777717e284d92304e2db18e5cb00e26c8c999d64 /include/clang/Lex/Preprocessor.h
parentbccb6a479f9f7afe6912c97223cb0489a231c63c (diff)
Allow for unfinished #if blocks in preambles
Previously, a preamble only included #if blocks (and friends like ifdef) if there was a corresponding #endif before any declaration or definition. The problem is that any header file that uses include guards will not have a preamble generated, which can make code-completion very slow. To prevent errors about unbalanced preprocessor conditionals in the preamble, and unbalanced preprocessor conditionals after a preamble containing unfinished conditionals, the conditional stack is stored in the pch file. This fixes PR26045. Differential Revision: http://reviews.llvm.org/D15994 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@304207 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang/Lex/Preprocessor.h')
-rw-r--r--include/clang/Lex/Preprocessor.h64
1 files changed, 64 insertions, 0 deletions
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 9f015eaa23..aeca83a907 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -283,6 +283,44 @@ class Preprocessor {
/// This is used when loading a precompiled preamble.
std::pair<int, bool> SkipMainFilePreamble;
+ class PreambleConditionalStackStore {
+ enum State {
+ Off = 0,
+ Recording = 1,
+ Replaying = 2,
+ };
+
+ public:
+ PreambleConditionalStackStore() : ConditionalStackState(Off) {}
+
+ void startRecording() { ConditionalStackState = Recording; }
+ void startReplaying() { ConditionalStackState = Replaying; }
+ bool isRecording() const { return ConditionalStackState == Recording; }
+ bool isReplaying() const { return ConditionalStackState == Replaying; }
+
+ ArrayRef<PPConditionalInfo> getStack() const {
+ return ConditionalStack;
+ }
+
+ void doneReplaying() {
+ ConditionalStack.clear();
+ ConditionalStackState = Off;
+ }
+
+ void setStack(ArrayRef<PPConditionalInfo> s) {
+ if (!isRecording() && !isReplaying())
+ return;
+ ConditionalStack.clear();
+ ConditionalStack.append(s.begin(), s.end());
+ }
+
+ bool hasRecordedPreamble() const { return !ConditionalStack.empty(); }
+
+ private:
+ SmallVector<PPConditionalInfo, 4> 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.
///
@@ -1695,6 +1733,11 @@ public:
/// \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 main file (specifically, if we are 0
+ /// (zero) levels deep \#include. This is used by the lexer to determine if
+ /// it needs to generate errors about unterminated \#if directives.
+ bool isInMainFile() const;
+
/// \brief Handle cases where the \#include name is expanded
/// from a macro as multiple tokens, which need to be glued together.
///
@@ -1932,6 +1975,27 @@ public:
Module *M,
SourceLocation MLoc);
+ bool isRecordingPreamble() const {
+ return PreambleConditionalStack.isRecording();
+ }
+
+ bool hasRecordedPreamble() const {
+ return PreambleConditionalStack.hasRecordedPreamble();
+ }
+
+ ArrayRef<PPConditionalInfo> getPreambleConditionalStack() const {
+ return PreambleConditionalStack.getStack();
+ }
+
+ void setRecordedPreambleConditionalStack(ArrayRef<PPConditionalInfo> s) {
+ PreambleConditionalStack.setStack(s);
+ }
+
+ void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s) {
+ PreambleConditionalStack.startReplaying();
+ PreambleConditionalStack.setStack(s);
+ }
+
private:
// Macro handling.
void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);