]> granicus.if.org Git - clang/commitdiff
No longer crashing with an assert when __has_include or __has_include_next is used...
authorAaron Ballman <aaron@aaronballman.com>
Wed, 16 Jan 2013 19:32:21 +0000 (19:32 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Wed, 16 Jan 2013 19:32:21 +0000 (19:32 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172639 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticLexKinds.td
include/clang/Lex/Preprocessor.h
lib/Lex/PPDirectives.cpp
lib/Lex/PPMacroExpansion.cpp
lib/Lex/Preprocessor.cpp
test/Preprocessor/has_include.c

index b9dbaf2e9e35595e06e9f311113f2e4b618b143f..59c6ce77fdb4b4027e802eece80f6378f232ac0a 100644 (file)
@@ -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">;
index e7bd0dfeec1ad94aad03606f97d11edfd4f04b3b..faaec3517d8fde59ebf3b0509f24f9ea2d346c75 100644 (file)
@@ -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) {
index bdca03637db08cdb0400fe7369b2c6cb9267ee9b..7e46a9cc28eb8840fc99918a873ea4861984b34b 100644 (file)
@@ -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.
index 7b8871576a67e6d94d7c660c26b6bb2d04dfb3a5..20e5dd986f3e543e2dd66e0f8c614be4c94d0144 100644 (file)
@@ -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);
 
index 9ce4874f63ff1cb7c3395bef7ef5c58277d0489a..ccb2df0602abc3a2734aca001921fdfdc2a4426b 100644 (file)
@@ -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;
   
index 985501a2151f1e97f3bce33f11ad32236ee594d2..4e71a369747581a32402c0b0dd06defcc16291e5 100644 (file)
   #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)
 
 #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 '('}}