[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