aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2013-01-16 19:32:21 +0000
committerAaron Ballman <aaron@aaronballman.com>2013-01-16 19:32:21 +0000
commit31672b1745195d709b641f1c0f44e203742fa73b (patch)
tree12fbebdd3494a696805c698f0b60668fd5038e2c
parentf0e00046711280d494f3ef2d85ae67a442b97406 (diff)
No longer crashing with an assert when __has_include or __has_include_next is used outside of a preprocessor directive. This fixes PR14837.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172639 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td2
-rw-r--r--include/clang/Lex/Preprocessor.h8
-rw-r--r--lib/Lex/PPDirectives.cpp3
-rw-r--r--lib/Lex/PPMacroExpansion.cpp6
-rw-r--r--lib/Lex/Preprocessor.cpp3
-rw-r--r--test/Preprocessor/has_include.c24
6 files changed, 44 insertions, 2 deletions
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index b9dbaf2e9e..59c6ce77fd 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -285,6 +285,8 @@ def warn_cxx98_compat_empty_fnmacro_arg : Warning<
def note_macro_here : Note<"macro %0 defined here">;
def err_pp_invalid_directive : Error<"invalid preprocessing directive">;
+def err_pp_directive_required : Error<
+ "%0 must be used within a preprocessing directive">;
def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
def err_pp_file_not_found_not_fatal : Error<
"'%0' file not found with <angled> include; use \"quotes\" instead">;
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index e7bd0dfeec..faaec3517d 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -160,6 +160,9 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// \brief True if pragmas are enabled.
bool PragmasEnabled : 1;
+ /// \brief True if we are currently preprocessing a #if or #elif directive
+ bool ParsingIfOrElifDirective;
+
/// \brief True if we are pre-expanding macro arguments.
bool InMacroArgPreExpansion;
@@ -446,6 +449,11 @@ public:
/// \brief Retrieve the module loader associated with this preprocessor.
ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
+ /// \brief True if we are currently preprocessing a #if or #elif directive
+ bool isParsingIfOrElifDirective() const {
+ return ParsingIfOrElifDirective;
+ }
+
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index bdca03637d..7e46a9cc28 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -24,6 +24,7 @@
#include "clang/Lex/Pragma.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -2071,6 +2072,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
///
void Preprocessor::HandleIfDirective(Token &IfToken,
bool ReadAnyTokensBeforeDirective) {
+ SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
++NumIf;
// Parse and evaluate the conditional expression.
@@ -2162,6 +2164,7 @@ void Preprocessor::HandleElseDirective(Token &Result) {
/// HandleElifDirective - Implements the \#elif directive.
///
void Preprocessor::HandleElifDirective(Token &ElifToken) {
+ SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
++NumElse;
// #elif directive in a non-skipping conditional... start skipping.
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 7b8871576a..20e5dd986f 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -964,6 +964,12 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// that location. If not, use the end of this location instead.
SourceLocation LParenLoc = Tok.getLocation();
+ // These expressions are only allowed within a preprocessor directive.
+ if (!PP.isParsingIfOrElifDirective()) {
+ PP.Diag(LParenLoc, diag::err_pp_directive_required) << II->getName();
+ return false;
+ }
+
// Get '('.
PP.LexNonComment(Tok);
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 9ce4874f63..ccb2df0602 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -69,7 +69,8 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0),
SkipMainFilePreamble(0, true), CurPPLexer(0),
CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), Listener(0),
- MacroArgCache(0), Record(0), MIChainHead(0), MICache(0)
+ MacroArgCache(0), Record(0), MIChainHead(0), MICache(0),
+ ParsingIfOrElifDirective(false)
{
OwnsHeaderSearch = OwnsHeaders;
diff --git a/test/Preprocessor/has_include.c b/test/Preprocessor/has_include.c
index 985501a215..4e71a36974 100644
--- a/test/Preprocessor/has_include.c
+++ b/test/Preprocessor/has_include.c
@@ -91,6 +91,28 @@
#error "__has_include with macro failed (2)."
#endif
+// Try as non-preprocessor directives
+void foo( void ) {
+ __has_include_next("stdint.h") // expected-warning {{#include_next in primary source file}} expected-error {{__has_include_next must be used within a preprocessing directive}}
+ __has_include("stdint.h") // expected-error {{__has_include must be used within a preprocessing directive}}
+}
+
+MACRO1 // expected-error {{__has_include must be used within a preprocessing directive}}
+
+#if 1
+MACRO1 // expected-error {{__has_include must be used within a preprocessing directive}}
+#endif
+
+#if 0
+#elif 1
+MACRO1 // expected-error {{__has_include must be used within a preprocessing directive}}
+#endif
+
+#if 0
+MACRO1 // This should be fine because it is never actually reached
+#endif
+
+
// Try badly formed expressions.
// FIXME: We can recover better in almost all of these cases. (PR13335)
@@ -126,7 +148,7 @@
#if __has_include(stdint.h>)
#endif
-// expected-error@+1 {{missing '(' after '__has_include'}}
+// expected-error@+1 {{__has_include must be used within a preprocessing directive}}
__has_include
// expected-error@+1 {{missing ')' after '__has_include'}} // expected-error@+1 {{expected value in expression}} // expected-note@+1 {{to match this '('}}