/// know anything about preprocessor-level issues like the \#include stack,
/// token expansion, etc.
class Preprocessor {
+ friend class VariadicMacroScopeGuard;
std::shared_ptr<PreprocessorOptions> PPOpts;
DiagnosticsEngine *Diags;
LangOptions &LangOpts;
--- /dev/null
+//===- VariadicMacroSupport.h - scope-guards etc. -*- C++ -*---------------===//\r
+//\r
+// The LLVM Compiler Infrastructure\r
+//\r
+// This file is distributed under the University of Illinois Open Source\r
+// License. See LICENSE.TXT for details.\r
+//\r
+//===----------------------------------------------------------------------===//\r
+//\r
+// This file defines support types to help with preprocessing variadic macro \r
+// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and \r
+// expansions.\r
+//\r
+//===----------------------------------------------------------------------===//\r
+\r
+#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H\r
+#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H\r
+\r
+#include "clang/Lex/Preprocessor.h"\r
+\r
+namespace clang {\r
+\r
+/// An RAII class that tracks when the Preprocessor starts and stops lexing the\r
+/// definition of a (ISO C/C++) variadic macro. As an example, this is useful\r
+/// for unpoisoning and repoisoning certain identifiers (such as __VA_ARGS__)\r
+/// that are only allowed in this context. Also, being a friend of the\r
+/// Preprocessor class allows it to access PP's cached identifiers directly (as\r
+/// opposed to performing a lookup each time).\r
+class VariadicMacroScopeGuard {\r
+ const Preprocessor &PP;\r
+ IdentifierInfo &Ident__VA_ARGS__;\r
+\r
+public:\r
+ VariadicMacroScopeGuard(const Preprocessor &P)\r
+ : PP(P), Ident__VA_ARGS__(*PP.Ident__VA_ARGS__) {\r
+ assert(Ident__VA_ARGS__.isPoisoned() && "__VA_ARGS__ should be poisoned "\r
+ "outside an ISO C/C++ variadic "\r
+ "macro definition!");\r
+ }\r
+\r
+ /// Client code should call this function just before the Preprocessor is\r
+ /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.\r
+ void enterScope() { Ident__VA_ARGS__.setIsPoisoned(false); }\r
+\r
+ /// Client code should call this function as soon as the Preprocessor has\r
+ /// either completed lexing the macro's definition tokens, or an error occured\r
+ /// and the context is being exited. This function is idempotent (might be\r
+ /// explicitly called, and then reinvoked via the destructor).\r
+ void exitScope() { Ident__VA_ARGS__.setIsPoisoned(true); }\r
+ \r
+ ~VariadicMacroScopeGuard() { exitScope(); }\r
+};\r
+\r
+} // end namespace clang\r
+\r
+#endif\r
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/PTHLexer.h"
#include "clang/Lex/Token.h"
+#include "clang/Lex/VariadicMacroSupport.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
Token Tok;
LexUnexpandedToken(Tok);
+ // Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk
+ // within their appropriate context.
+ VariadicMacroScopeGuard VariadicMacroScopeGuard(*this);
+
// If this is a function-like macro definition, parse the argument list,
// marking each of the identifiers as being used as macro arguments. Also,
// check other constraints on the first token of the macro body.
return nullptr;
}
- // If this is a definition of a variadic C99 function-like macro, not using
- // the GNU named varargs extension, enabled __VA_ARGS__.
+ // If this is a definition of an ISO C/C++ variadic function-like macro (not
+ // using the GNU named varargs extension) inform our variadic scope guard
+ // which un-poisons and re-poisons certain identifiers (e.g. __VA_ARGS__)
+ // allowed only within the definition of a variadic macro.
- // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
- // This gets unpoisoned where it is allowed.
- assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!");
- if (MI->isC99Varargs())
- Ident__VA_ARGS__->setIsPoisoned(false);
+ if (MI->isC99Varargs()) {
+ VariadicMacroScopeGuard.enterScope();
+ }
// Read the first token after the arg list for down below.
LexUnexpandedToken(Tok);
} else {
Diag(Tok, diag::err_pp_stringize_not_parameter)
<< LastTok.is(tok::hashat);
-
- // Disable __VA_ARGS__ again.
- Ident__VA_ARGS__->setIsPoisoned(true);
return nullptr;
}
}
}
}
MI->setDefinitionEndLoc(LastTok.getLocation());
- // Disable __VA_ARGS__ again.
- Ident__VA_ARGS__->setIsPoisoned(true);
-
return MI;
}
/// HandleDefineDirective - Implements \#define. This consumes the entire macro