[cfe-commits] r63926 - in /cfe/trunk: Driver/PrintPreprocessedOutput.cpp include/clang/Lex/MacroInfo.h lib/Lex/Preprocessor.cpp test/Preprocessor/dump_macros.c

Chris Lattner sabre at nondot.org
Thu Feb 5 22:45:26 PST 2009


Author: lattner
Date: Fri Feb  6 00:45:26 2009
New Revision: 63926

URL: http://llvm.org/viewvc/llvm-project?rev=63926&view=rev
Log:
Add an implementation of -dM that follows GCC closely enough to permit
diffing the output of:
  clang -dM -o - -E -x c foo.c | sort

Added:
    cfe/trunk/test/Preprocessor/dump_macros.c
Modified:
    cfe/trunk/Driver/PrintPreprocessedOutput.cpp
    cfe/trunk/include/clang/Lex/MacroInfo.h
    cfe/trunk/lib/Lex/Preprocessor.cpp

Modified: cfe/trunk/Driver/PrintPreprocessedOutput.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/PrintPreprocessedOutput.cpp?rev=63926&r1=63925&r2=63926&view=diff

==============================================================================
--- cfe/trunk/Driver/PrintPreprocessedOutput.cpp (original)
+++ cfe/trunk/Driver/PrintPreprocessedOutput.cpp Fri Feb  6 00:45:26 2009
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang.h"
+#include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/Pragma.h"
@@ -39,6 +40,10 @@
 EnableMacroCommentOutput("CC",
                          llvm::cl::desc("Enable comment output in -E mode, "
                                         "even from macro expansions"));
+static llvm::cl::opt<bool>
+DumpMacros("dM", llvm::cl::desc("Print macro definitions in -E mode instead of"
+                                " normal output"));
+
 
 namespace {
 class PrintPPOutputPPCallbacks : public PPCallbacks {
@@ -543,6 +548,49 @@
   }
 }
 
+/// PrintMacroDefinition - Print a macro definition in a form that will be
+/// properly accepted back as a definition.
+static void PrintMacroDefinition(IdentifierInfo &II, const MacroInfo &MI,
+                                 Preprocessor &PP, llvm::raw_ostream &OS) {
+  // Ignore computed macros like __LINE__ and friends. 
+  if (MI.isBuiltinMacro()) return;
+  OS << "#define " << II.getName();
+
+  if (MI.isFunctionLike()) {
+    OS << '(';
+    if (MI.arg_empty())
+      ;
+    else if (MI.getNumArgs() == 1) 
+      OS << (*MI.arg_begin())->getName();
+    else {
+      MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+      OS << (*AI++)->getName();
+      while (AI != E)
+        OS << ',' << (*AI++)->getName();
+    }
+    
+    if (MI.isVariadic()) {
+      if (!MI.arg_empty())
+        OS << ',';
+      OS << "...";
+    }
+    OS << ')';
+  }
+  
+  // GCC always emits a space, even if the macro body is empty.  However, do not
+  // want to emit two spaces if the first token has a leading space.
+  if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace())
+    OS << ' ';
+  
+  for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
+       I != E; ++I) {
+    if (I->hasLeadingSpace())
+      OS << ' ';
+    OS << PP.getSpelling(*I);
+  }
+  OS << "\n";
+}
+
 
 /// DoPrintPreprocessedInput - This implements -E mode.
 ///
@@ -564,31 +612,45 @@
   
   OS.SetBufferSize(64*1024);
   
-  Token Tok;
-  PrintPPOutputPPCallbacks *Callbacks;
-  Callbacks = new PrintPPOutputPPCallbacks(PP, OS);
-  PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
-  PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks));
-
-  PP.setPPCallbacks(Callbacks);
-
-  // After we have configured the preprocessor, enter the main file.
-  
-  // Start parsing the specified input file.
-  PP.EnterMainSourceFile();
-
-  // Consume all of the tokens that come from the predefines buffer.  Those
-  // should not be emitted into the output and are guaranteed to be at the
-  // start.
-  const SourceManager &SourceMgr = PP.getSourceManager();
-  do PP.Lex(Tok);
-  while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
-         !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
-                 "<predefines>"));
+  if (DumpMacros) {
+    // -dM mode just scans and ignores all tokens in the files, then dumps out
+    // the macro table at the end.
+    PP.EnterMainSourceFile();
+    
+    Token Tok;
+    do PP.Lex(Tok);
+    while (Tok.isNot(tok::eof));
+    
+    for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+         I != E; ++I)
+      PrintMacroDefinition(*I->first, *I->second, PP, OS);
+    
+  } else {
+    PrintPPOutputPPCallbacks *Callbacks;
+    Callbacks = new PrintPPOutputPPCallbacks(PP, OS);
+    PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
+    PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
+                                                        Callbacks));
+
+    PP.setPPCallbacks(Callbacks);
+
+    // After we have configured the preprocessor, enter the main file.
+    PP.EnterMainSourceFile();
+
+    // Consume all of the tokens that come from the predefines buffer.  Those
+    // should not be emitted into the output and are guaranteed to be at the
+    // start.
+    const SourceManager &SourceMgr = PP.getSourceManager();
+    Token Tok;
+    do PP.Lex(Tok);
+    while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
+           !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
+                   "<predefines>"));
 
-  // Read all the preprocessed tokens, printing them out to the stream.
-  PrintPreprocessedTokens(PP, Tok, Callbacks, OS);
-  OS << '\n';
+    // Read all the preprocessed tokens, printing them out to the stream.
+    PrintPreprocessedTokens(PP, Tok, Callbacks, OS);
+    OS << '\n';
+  }
   
   // Flush the ostream.
   OS.flush();

Modified: cfe/trunk/include/clang/Lex/MacroInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/MacroInfo.h?rev=63926&r1=63925&r2=63926&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/MacroInfo.h (original)
+++ cfe/trunk/include/clang/Lex/MacroInfo.h Fri Feb  6 00:45:26 2009
@@ -116,6 +116,7 @@
   /// Arguments - The list of arguments for a function-like macro.  This can be
   /// empty, for, e.g. "#define X()".
   typedef IdentifierInfo* const *arg_iterator;
+  bool arg_empty() const { return NumArguments == 0; }
   arg_iterator arg_begin() const { return ArgumentList; }
   arg_iterator arg_end() const { return ArgumentList+NumArguments; }
   unsigned getNumArgs() const { return NumArguments; }
@@ -163,6 +164,7 @@
   typedef llvm::SmallVector<Token, 8>::const_iterator tokens_iterator;
   tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); }
   tokens_iterator tokens_end() const { return ReplacementTokens.end(); }
+  bool tokens_empty() const { return ReplacementTokens.empty(); }
   
   /// AddTokenToBody - Add the specified token to the replacement text for the
   /// macro.

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=63926&r1=63925&r2=63926&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Fri Feb  6 00:45:26 2009
@@ -13,7 +13,7 @@
 //
 // Options to support:
 //   -H       - Print the name of each header file used.
-//   -d[MDNI] - Dump various things.
+//   -d[DNI] - Dump various things.
 //   -fworking-directory - #line's with preprocessor's working dir.
 //   -fpreprocessed
 //   -dependency-file,-M,-MM,-MF,-MG,-MP,-MT,-MQ,-MD,-MMD

Added: cfe/trunk/test/Preprocessor/dump_macros.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/dump_macros.c?rev=63926&view=auto

==============================================================================
--- cfe/trunk/test/Preprocessor/dump_macros.c (added)
+++ cfe/trunk/test/Preprocessor/dump_macros.c Fri Feb  6 00:45:26 2009
@@ -0,0 +1,31 @@
+// RUN: clang -E -dM %s -o %t &&
+
+// Space even without expansion tokens
+// RUN: grep "#define A(x) " %t &&
+#define A(x)
+
+// Space before expansion list.
+// RUN: grep "#define B(x,y) x y" %t &&
+#define B(x,y)x y
+
+// No space in expansion list.
+// RUN: grep "#define C(x,y) x y" %t &&
+#define C(x, y) x y
+
+// No paste avoidance.
+// RUN: grep "#define X() .." %t &&
+#define X() ..
+
+// Simple test.
+// RUN: grep "#define Y ." %t &&
+// RUN: grep "#define Z X()Y" %t &&
+#define Y .
+#define Z X()Y
+
+// gcc prints macros at end of translation unit, so last one wins.
+// RUN: grep "#define foo 2" %t &&
+// RUN: not grep "#define foo 1" %t
+#define foo 1
+#undef foo
+#define foo 2
+





More information about the cfe-commits mailing list