[cfe-commits] r111234 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/MacroInfo.h include/clang/Lex/Preprocessor.h lib/Lex/MacroInfo.cpp lib/Lex/PPDirectives.cpp lib/Lex/Pragma.cpp test/Preprocessor/pragma-pushpop-macro.c
Chris Lattner
sabre at nondot.org
Tue Aug 17 08:55:45 PDT 2010
Author: lattner
Date: Tue Aug 17 10:55:45 2010
New Revision: 111234
URL: http://llvm.org/viewvc/llvm-project?rev=111234&view=rev
Log:
Implement #pragma push_macro, patch by Francois Pichet!
Added:
cfe/trunk/test/Preprocessor/pragma-pushpop-macro.c
Modified:
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/include/clang/Lex/MacroInfo.h
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Lex/MacroInfo.cpp
cfe/trunk/lib/Lex/PPDirectives.cpp
cfe/trunk/lib/Lex/Pragma.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=111234&r1=111233&r2=111234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Tue Aug 17 10:55:45 2010
@@ -230,6 +230,10 @@
"pragma comment requires parenthesized identifier and optional string">;
def err_pragma_message_malformed : Error<
"pragma message requires parenthesized string">;
+def err_pragma_push_pop_macro_malformed : Error<
+ "pragma %0 requires a parenthesized string">;
+def warn_pragma_pop_macro_no_push : Warning<
+ "pragma pop_macro could not pop '%0', no matching push_macro">;
def warn_pragma_message : Warning<"%0">;
def warn_pragma_ignored : Warning<"unknown pragma ignored">,
InGroup<UnknownPragmas>, DefaultIgnore;
Modified: cfe/trunk/include/clang/Lex/MacroInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/MacroInfo.h?rev=111234&r1=111233&r2=111234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/MacroInfo.h (original)
+++ cfe/trunk/include/clang/Lex/MacroInfo.h Tue Aug 17 10:55:45 2010
@@ -79,13 +79,18 @@
/// emit -Wunused-macros diagnostics.
bool IsUsed : 1;
- ~MacroInfo() {
+ /// AllowRedefinitionsWithoutWarning - True if this macro can be redefined
+ /// without emitting a warning.
+ bool IsAllowRedefinitionsWithoutWarning : 1;
+
+ ~MacroInfo() {
assert(ArgumentList == 0 && "Didn't call destroy before dtor!");
}
public:
MacroInfo(SourceLocation DefLoc);
-
+ MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator);
+
/// FreeArgumentList - Free the argument list of the macro, restoring it to a
/// state where it can be reused for other devious purposes.
void FreeArgumentList(llvm::BumpPtrAllocator &PPAllocator) {
@@ -128,6 +133,12 @@
IsUsed = Val;
}
+ /// setIsAllowRedefinitionsWithoutWarning - Set the value of the
+ /// IsAllowRedefinitionsWithoutWarning flag.
+ void setIsAllowRedefinitionsWithoutWarning(bool Val) {
+ IsAllowRedefinitionsWithoutWarning = Val;
+ }
+
/// setArgumentList - Set the specified list of identifiers as the argument
/// list for this macro.
void setArgumentList(IdentifierInfo* const *List, unsigned NumArgs,
@@ -185,6 +196,12 @@
/// not yet been used.
bool isUsed() const { return IsUsed; }
+ /// isAllowRedefinitionsWithoutWarning - Return true if this macro can be
+ /// redefined without warning.
+ bool isAllowRedefinitionsWithoutWarning() const {
+ return IsAllowRedefinitionsWithoutWarning;
+ }
+
/// getNumTokens - Return the number of tokens that this macro expands to.
///
unsigned getNumTokens() const {
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=111234&r1=111233&r2=111234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Tue Aug 17 10:55:45 2010
@@ -198,6 +198,11 @@
/// reused for quick allocation.
MacroArgs *MacroArgCache;
friend class MacroArgs;
+
+ /// PragmaPushMacroInfo - For each IdentifierInfo used in a #pragma
+ /// push_macro directive, we keep a MacroInfo stack used to restore
+ /// previous macro value.
+ llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > PragmaPushMacroInfo;
// Various statistics we track for performance analysis.
unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma;
@@ -744,7 +749,10 @@
/// AllocateMacroInfo - Allocate a new MacroInfo object with the provide
/// SourceLocation.
- MacroInfo* AllocateMacroInfo(SourceLocation L);
+ MacroInfo *AllocateMacroInfo(SourceLocation L);
+
+ /// CloneMacroInfo - Allocate a new MacroInfo object which is clone of MI.
+ MacroInfo *CloneMacroInfo(const MacroInfo &MI);
/// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully
/// checked and spelled filename, e.g. as an operand of #include. This returns
@@ -802,6 +810,9 @@
IncludeMacroStack.pop_back();
}
+ /// AllocateMacroInfo - Allocate a new MacroInfo object.
+ MacroInfo *AllocateMacroInfo();
+
/// ReleaseMacroInfo - Release the specified MacroInfo. This memory will
/// be reused for allocating new MacroInfo objects.
void ReleaseMacroInfo(MacroInfo* MI);
@@ -948,6 +959,10 @@
void HandlePragmaDependency(Token &DependencyTok);
void HandlePragmaComment(Token &CommentTok);
void HandlePragmaMessage(Token &MessageTok);
+ void HandlePragmaPushMacro(Token &Tok);
+ void HandlePragmaPopMacro(Token &Tok);
+ IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
+
// Return true and store the first token only if any CommentHandler
// has inserted some tokens and getCommentRetentionState() is false.
bool HandleComment(Token &Token, SourceRange Comment);
Modified: cfe/trunk/lib/Lex/MacroInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/MacroInfo.cpp?rev=111234&r1=111233&r2=111234&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/MacroInfo.cpp (original)
+++ cfe/trunk/lib/Lex/MacroInfo.cpp Tue Aug 17 10:55:45 2010
@@ -23,11 +23,29 @@
IsFromPCH = false;
IsDisabled = false;
IsUsed = true;
+ IsAllowRedefinitionsWithoutWarning = false;
ArgumentList = 0;
NumArguments = 0;
}
+MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
+ Location = MI.Location;
+ EndLocation = MI.EndLocation;
+ ReplacementTokens = MI.ReplacementTokens;
+ IsFunctionLike = MI.IsFunctionLike;
+ IsC99Varargs = MI.IsC99Varargs;
+ IsGNUVarargs = MI.IsGNUVarargs;
+ IsBuiltinMacro = MI.IsBuiltinMacro;
+ IsFromPCH = MI.IsFromPCH;
+ IsDisabled = MI.IsDisabled;
+ IsUsed = MI.IsUsed;
+ IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
+ ArgumentList = 0;
+ NumArguments = 0;
+ setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
+}
+
/// isIdenticalTo - Return true if the specified macro definition is equal to
/// this macro in spelling, arguments, and whitespace. This is used to emit
/// duplicate definition warnings. This implements the rules in C99 6.10.3.
Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=111234&r1=111233&r2=111234&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Tue Aug 17 10:55:45 2010
@@ -25,7 +25,7 @@
// Utility Methods for Preprocessor Directive Handling.
//===----------------------------------------------------------------------===//
-MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
+MacroInfo *Preprocessor::AllocateMacroInfo() {
MacroInfo *MI;
if (!MICache.empty()) {
@@ -33,10 +33,21 @@
MICache.pop_back();
} else
MI = (MacroInfo*) BP.Allocate<MacroInfo>();
+ return MI;
+}
+
+MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
+ MacroInfo *MI = AllocateMacroInfo();
new (MI) MacroInfo(L);
return MI;
}
+MacroInfo *Preprocessor::CloneMacroInfo(const MacroInfo &MacroToClone) {
+ MacroInfo *MI = AllocateMacroInfo();
+ new (MI) MacroInfo(MacroToClone, BP);
+ return MI;
+}
+
/// ReleaseMacroInfo - Release the specified MacroInfo. This memory will
/// be reused for allocating new MacroInfo objects.
void Preprocessor::ReleaseMacroInfo(MacroInfo* MI) {
@@ -1446,15 +1457,15 @@
if (!OtherMI->isUsed())
Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used);
- // Macros must be identical. This means all tokes and whitespace
+ // Macros must be identical. This means all tokens and whitespace
// separation must be the same. C99 6.10.3.2.
- if (!MI->isIdenticalTo(*OtherMI, *this)) {
+ if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
+ !MI->isIdenticalTo(*OtherMI, *this)) {
Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef)
<< MacroNameTok.getIdentifierInfo();
Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition);
}
}
-
ReleaseMacroInfo(OtherMI);
}
Modified: cfe/trunk/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=111234&r1=111233&r2=111234&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Pragma.cpp (original)
+++ cfe/trunk/lib/Lex/Pragma.cpp Tue Aug 17 10:55:45 2010
@@ -16,6 +16,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -483,6 +484,109 @@
Callbacks->PragmaMessage(MessageLoc, MessageString);
}
+/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro.
+/// Return the IdentifierInfo* associated with the macro to push or pop.
+IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
+ // Remember the pragma token location.
+ Token PragmaTok = Tok;
+
+ // Read the '('.
+ Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed)
+ << getSpelling(PragmaTok);
+ return 0;
+ }
+
+ // Read the macro name string.
+ Lex(Tok);
+ if (Tok.isNot(tok::string_literal)) {
+ Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed)
+ << getSpelling(PragmaTok);
+ return 0;
+ }
+
+ // Remember the macro string.
+ std::string StrVal = getSpelling(Tok);
+
+ // Read the ')'.
+ Lex(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed)
+ << getSpelling(PragmaTok);
+ return 0;
+ }
+
+ assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
+ "Invalid string token!");
+
+ // Create a Token from the string.
+ Token MacroTok;
+ MacroTok.startToken();
+ MacroTok.setKind(tok::identifier);
+ CreateString(&StrVal[1], StrVal.size() - 2, MacroTok);
+
+ // Get the IdentifierInfo of MacroToPushTok.
+ return LookUpIdentifierInfo(MacroTok);
+}
+
+/// HandlePragmaPushMacro - Handle #pragma push_macro.
+/// The syntax is:
+/// #pragma push_macro("macro")
+void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) {
+ // Parse the pragma directive and get the macro IdentifierInfo*.
+ IdentifierInfo *IdentInfo = ParsePragmaPushOrPopMacro(PushMacroTok);
+ if (!IdentInfo) return;
+
+ // Get the MacroInfo associated with IdentInfo.
+ MacroInfo *MI = getMacroInfo(IdentInfo);
+
+ MacroInfo *MacroCopyToPush = 0;
+ if (MI) {
+ // Make a clone of MI.
+ MacroCopyToPush = CloneMacroInfo(*MI);
+
+ // Allow the original MacroInfo to be redefined later.
+ MI->setIsAllowRedefinitionsWithoutWarning(true);
+ }
+
+ // Push the cloned MacroInfo so we can retrieve it later.
+ PragmaPushMacroInfo[IdentInfo].push_back(MacroCopyToPush);
+}
+
+/// HandlePragmaPopMacro - Handle #pragma push_macro.
+/// The syntax is:
+/// #pragma pop_macro("macro")
+void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
+ SourceLocation MessageLoc = PopMacroTok.getLocation();
+
+ // Parse the pragma directive and get the macro IdentifierInfo*.
+ IdentifierInfo *IdentInfo = ParsePragmaPushOrPopMacro(PopMacroTok);
+ if (!IdentInfo) return;
+
+ // Find the vector<MacroInfo*> associated with the macro.
+ llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> >::iterator iter =
+ PragmaPushMacroInfo.find(IdentInfo);
+ if (iter != PragmaPushMacroInfo.end()) {
+ // Release the MacroInfo currently associated with IdentInfo.
+ MacroInfo *CurrentMI = getMacroInfo(IdentInfo);
+ if (CurrentMI) ReleaseMacroInfo(CurrentMI);
+
+ // Get the MacroInfo we want to reinstall.
+ MacroInfo *MacroToReInstall = iter->second.back();
+
+ // Reinstall the previously pushed macro.
+ setMacroInfo(IdentInfo, MacroToReInstall);
+
+ // Pop PragmaPushMacroInfo stack.
+ iter->second.pop_back();
+ if (iter->second.size() == 0)
+ PragmaPushMacroInfo.erase(iter);
+ } else {
+ Diag(MessageLoc, diag::warn_pragma_pop_macro_no_push)
+ << IdentInfo->getName();
+ }
+}
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
@@ -726,6 +830,25 @@
}
};
+/// PragmaPushMacroHandler - "#pragma push_macro" saves the value of the
+/// macro on the top of the stack.
+struct PragmaPushMacroHandler : public PragmaHandler {
+ PragmaPushMacroHandler() : PragmaHandler("push_macro") {}
+ virtual void HandlePragma(Preprocessor &PP, Token &PushMacroTok) {
+ PP.HandlePragmaPushMacro(PushMacroTok);
+ }
+};
+
+
+/// PragmaPopMacroHandler - "#pragma pop_macro" sets the value of the
+/// macro to the value on the top of the stack.
+struct PragmaPopMacroHandler : public PragmaHandler {
+ PragmaPopMacroHandler() : PragmaHandler("pop_macro") {}
+ virtual void HandlePragma(Preprocessor &PP, Token &PopMacroTok) {
+ PP.HandlePragmaPopMacro(PopMacroTok);
+ }
+};
+
// Pragma STDC implementations.
enum STDCSetting {
@@ -807,6 +930,8 @@
void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler(new PragmaOnceHandler());
AddPragmaHandler(new PragmaMarkHandler());
+ AddPragmaHandler(new PragmaPushMacroHandler());
+ AddPragmaHandler(new PragmaPopMacroHandler());
// #pragma GCC ...
AddPragmaHandler("GCC", new PragmaPoisonHandler());
Added: cfe/trunk/test/Preprocessor/pragma-pushpop-macro.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/pragma-pushpop-macro.c?rev=111234&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/pragma-pushpop-macro.c (added)
+++ cfe/trunk/test/Preprocessor/pragma-pushpop-macro.c Tue Aug 17 10:55:45 2010
@@ -0,0 +1,33 @@
+/* Test pragma pop_macro and push_macro directives from
+ http://msdn.microsoft.com/en-us/library/hsttss76.aspx */
+
+// pop_macro: Sets the value of the macro_name macro to the value on the top of
+// the stack for this macro.
+// #pragma pop_macro("macro_name")
+// push_macro: Saves the value of the macro_name macro on the top of the stack
+// for this macro.
+// #pragma push_macro("macro_name")
+//
+// RUN: %clang_cc1 -fms-extensions -E %s -o - | FileCheck %s
+
+#define X 1
+#define Y 2
+int pmx0 = X;
+int pmy0 = Y;
+#define Y 3
+#pragma push_macro("Y")
+#pragma push_macro("X")
+int pmx1 = X;
+#define X 2
+int pmx2 = X;
+#pragma pop_macro("X")
+int pmx3 = X;
+#pragma pop_macro("Y")
+int pmy1 = Y;
+
+// CHECK: int pmx0 = 1
+// CHECK: int pmy0 = 2
+// CHECK: int pmx1 = 1
+// CHECK: int pmx2 = 2
+// CHECK: int pmx3 = 1
+// CHECK: int pmy1 = 3
More information about the cfe-commits
mailing list