[cfe-commits] r153959 - in /cfe/trunk: include/clang/Lex/Preprocessor.h lib/Lex/MacroArgs.cpp lib/Lex/Pragma.cpp lib/Lex/Preprocessor.cpp test/Preprocessor/_Pragma-in-macro-arg.c

Argyrios Kyrtzidis akyrtzi at gmail.com
Tue Apr 3 09:47:41 PDT 2012


Author: akirtzidis
Date: Tue Apr  3 11:47:40 2012
New Revision: 153959

URL: http://llvm.org/viewvc/llvm-project?rev=153959&view=rev
Log:
Correct handling of _Pragma macro inside a macro argument.

If we are pre-expanding a macro argument don't actually "activate"
the pragma at that point, activate the pragma whenever we encounter
it again in the token stream.
This ensures that we will activate it in the correct location
or that we will ignore it if it never enters the token stream, e.g:

     \#define EMPTY(x)
     \#define INACTIVE(x) EMPTY(x)
     INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\""))

This also fixes the crash in rdar://11168596.

Added:
    cfe/trunk/test/Preprocessor/_Pragma-in-macro-arg.c
Modified:
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/MacroArgs.cpp
    cfe/trunk/lib/Lex/Pragma.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=153959&r1=153958&r2=153959&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Tue Apr  3 11:47:40 2012
@@ -124,6 +124,9 @@
   /// \brief Whether we have already loaded macros from the external source.
   mutable bool ReadMacrosFromExternalSource : 1;
 
+  /// \brief True if we are pre-expanding macro arguments.
+  bool InMacroArgPreExpansion;
+
   /// Identifiers - This is mapping/lookup information for all identifiers in
   /// the program, including program keywords.
   mutable IdentifierTable Identifiers;

Modified: cfe/trunk/lib/Lex/MacroArgs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/MacroArgs.cpp?rev=153959&r1=153958&r2=153959&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/MacroArgs.cpp (original)
+++ cfe/trunk/lib/Lex/MacroArgs.cpp Tue Apr  3 11:47:40 2012
@@ -16,6 +16,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/LexDiagnostic.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/Support/SaveAndRestore.h"
 #include <algorithm>
 
 using namespace clang;
@@ -155,6 +156,8 @@
   std::vector<Token> &Result = PreExpArgTokens[Arg];
   if (!Result.empty()) return Result;
 
+  SaveAndRestore<bool> PreExpandingMacroArgs(PP.InMacroArgPreExpansion, true);
+
   const Token *AT = getUnexpArgument(Arg);
   unsigned NumToks = getArgLength(AT)+1;  // Include the EOF.
 
@@ -177,6 +180,8 @@
   // will not otherwise be popped until the next token is lexed.  The problem is
   // that the token may be lexed sometime after the vector of tokens itself is
   // destroyed, which would be badness.
+  if (PP.InCachingLexMode())
+    PP.ExitCachingLexMode();
   PP.RemoveTopOfLexerStack();
   return Result;
 }

Modified: cfe/trunk/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=153959&r1=153958&r2=153959&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Pragma.cpp (original)
+++ cfe/trunk/lib/Lex/Pragma.cpp Tue Apr  3 11:47:40 2012
@@ -115,10 +115,61 @@
     DiscardUntilEndOfDirective();
 }
 
+namespace {
+/// \brief Helper class for \see Preprocessor::Handle_Pragma.
+class LexingFor_PragmaRAII {
+  Preprocessor &PP;
+  bool InMacroArgPreExpansion;
+  bool Failed;
+  Token &OutTok;
+  Token PragmaTok;
+
+public:
+  LexingFor_PragmaRAII(Preprocessor &PP, bool InMacroArgPreExpansion,
+                       Token &Tok)
+    : PP(PP), InMacroArgPreExpansion(InMacroArgPreExpansion),
+      Failed(false), OutTok(Tok) {
+    if (InMacroArgPreExpansion) {
+      PragmaTok = OutTok;
+      PP.EnableBacktrackAtThisPos();
+    }
+  }
+
+  ~LexingFor_PragmaRAII() {
+    if (InMacroArgPreExpansion) {
+      if (Failed) {
+        PP.CommitBacktrackedTokens();
+      } else {
+        PP.Backtrack();
+        OutTok = PragmaTok;
+      }
+    }
+  }
+
+  void failed() {
+    Failed = true;
+  }
+};
+}
+
 /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then
 /// return the first token after the directive.  The _Pragma token has just
 /// been read into 'Tok'.
 void Preprocessor::Handle_Pragma(Token &Tok) {
+
+  // This works differently if we are pre-expanding a macro argument.
+  // In that case we don't actually "activate" the pragma now, we only lex it
+  // until we are sure it is lexically correct and then we backtrack so that
+  // we activate the pragma whenever we encounter the tokens again in the token
+  // stream. This ensures that we will activate it in the correct location
+  // or that we will ignore it if it never enters the token stream, e.g:
+  //
+  //     #define EMPTY(x)
+  //     #define INACTIVE(x) EMPTY(x)
+  //     INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\""))
+
+  LexingFor_PragmaRAII _PragmaLexing(*this, InMacroArgPreExpansion, Tok);
+
   // Remember the pragma token location.
   SourceLocation PragmaLoc = Tok.getLocation();
 
@@ -126,7 +177,7 @@
   Lex(Tok);
   if (Tok.isNot(tok::l_paren)) {
     Diag(PragmaLoc, diag::err__Pragma_malformed);
-    return;
+    return _PragmaLexing.failed();
   }
 
   // Read the '"..."'.
@@ -138,7 +189,7 @@
       Lex(Tok);
     if (Tok.is(tok::r_paren))
       Lex(Tok);
-    return;
+    return _PragmaLexing.failed();
   }
 
   if (Tok.hasUDSuffix()) {
@@ -147,20 +198,24 @@
     Lex(Tok);
     if (Tok.is(tok::r_paren))
       Lex(Tok);
-    return;
+    return _PragmaLexing.failed();
   }
 
   // Remember the string.
-  std::string StrVal = getSpelling(Tok);
+  Token StrTok = Tok;
 
   // Read the ')'.
   Lex(Tok);
   if (Tok.isNot(tok::r_paren)) {
     Diag(PragmaLoc, diag::err__Pragma_malformed);
-    return;
+    return _PragmaLexing.failed();
   }
 
+  if (InMacroArgPreExpansion)
+    return;
+
   SourceLocation RParenLoc = Tok.getLocation();
+  std::string StrVal = getSpelling(StrTok);
 
   // The _Pragma is lexically sound.  Destringize according to C99 6.10.9.1:
   // "The string literal is destringized by deleting the L prefix, if present,

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=153959&r1=153958&r2=153959&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Tue Apr  3 11:47:40 2012
@@ -135,6 +135,7 @@
   // Macro expansion is enabled.
   DisableMacroExpansion = false;
   InMacroArgs = false;
+  InMacroArgPreExpansion = false;
   NumCachedTokenLexers = 0;
   
   CachedLexPos = 0;

Added: cfe/trunk/test/Preprocessor/_Pragma-in-macro-arg.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/_Pragma-in-macro-arg.c?rev=153959&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/_Pragma-in-macro-arg.c (added)
+++ cfe/trunk/test/Preprocessor/_Pragma-in-macro-arg.c Tue Apr  3 11:47:40 2012
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -verify -Wconversion
+
+// Don't crash (rdar://11168596)
+#define A(desc) _Pragma("clang diagnostic push")  _Pragma("clang diagnostic ignored \"-Wparentheses\"") _Pragma("clang diagnostic pop")
+#define B(desc) A(desc)
+B(_Pragma("clang diagnostic ignored \"-Wparentheses\""))
+
+
+#define EMPTY(x)
+#define INACTIVE(x) EMPTY(x)
+
+#define ID(x) x
+#define ACTIVE(x) ID(x)
+
+// This should be ignored..
+INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\""))
+
+#define IGNORE_CONV _Pragma("clang diagnostic ignored \"-Wconversion\"")
+
+// ..as should this.
+INACTIVE(IGNORE_CONV)
+
+#define IGNORE_POPPUSH(Pop, Push, W, D) Push W D Pop
+IGNORE_POPPUSH(_Pragma("clang diagnostic pop"), _Pragma("clang diagnostic push"),
+               _Pragma("clang diagnostic ignored \"-Wconversion\""), int q = (double)1.0);
+
+int x1 = (double)1.0; // expected-warning {{implicit conversion}}
+
+ACTIVE(_Pragma) ("clang diagnostic ignored \"-Wconversion\"")) // expected-error {{_Pragma takes a parenthesized string literal}} \
+                                      expected-error {{expected identifier or '('}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+// This should disable the warning.
+ACTIVE(IGNORE_CONV)
+
+int x2 = (double)1.0;





More information about the cfe-commits mailing list