#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;
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.
// 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;
}
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();
Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
- return;
+ return _PragmaLexing.failed();
}
// Read the '"..."'.
Lex(Tok);
if (Tok.is(tok::r_paren))
Lex(Tok);
- return;
+ return _PragmaLexing.failed();
}
if (Tok.hasUDSuffix()) {
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,
--- /dev/null
+// 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;