Copy diagnostic pragmas to the preprocessed output, from Richard Osborne!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133633 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index fd07a29..a794815 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -16,6 +16,7 @@
 
 #include "clang/Lex/DirectoryLookup.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/DiagnosticIDs.h"
 #include "llvm/ADT/StringRef.h"
 #include <string>
 
@@ -124,6 +125,24 @@
   virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) {
   }
 
+  /// PragmaDiagnosticPush - This callback is invoked when a
+  /// #pragma gcc dianostic push directive is read.
+  virtual void PragmaDiagnosticPush(SourceLocation Loc,
+                                    llvm::StringRef Namespace) {
+  }
+
+  /// PragmaDiagnosticPop - This callback is invoked when a
+  /// #pragma gcc dianostic pop directive is read.
+  virtual void PragmaDiagnosticPop(SourceLocation Loc,
+                                   llvm::StringRef Namespace) {
+  }
+
+  /// PragmaDiagnostic - This callback is invoked when a
+  /// #pragma gcc dianostic directive is read.
+  virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
+                                diag::Mapping mapping, llvm::StringRef Str) {
+  }
+
   /// MacroExpands - This is called by
   /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is
   /// found.
@@ -232,6 +251,24 @@
     Second->PragmaMessage(Loc, Str);
   }
 
+  virtual void PragmaDiagnosticPush(SourceLocation Loc,
+                                    llvm::StringRef Namespace) {
+    First->PragmaDiagnosticPush(Loc, Namespace);
+    Second->PragmaDiagnosticPush(Loc, Namespace);
+  }
+
+  virtual void PragmaDiagnosticPop(SourceLocation Loc,
+                                    llvm::StringRef Namespace) {
+    First->PragmaDiagnosticPop(Loc, Namespace);
+    Second->PragmaDiagnosticPop(Loc, Namespace);
+  }
+
+  virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
+                                diag::Mapping mapping, llvm::StringRef Str) {
+    First->PragmaDiagnostic(Loc, Namespace, mapping, Str);
+    Second->PragmaDiagnostic(Loc, Namespace, mapping, Str);
+  }
+
   virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI) {
     First->MacroExpands(MacroNameTok, MI);
     Second->MacroExpands(MacroNameTok, MI);
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index b46e047..b9c0642 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -26,6 +26,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Config/config.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <cstdio>
 using namespace clang;
 
@@ -122,6 +123,12 @@
   virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
                              const std::string &Str);
   virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str);
+  virtual void PragmaDiagnosticPush(SourceLocation Loc,
+                                    llvm::StringRef Namespace);
+  virtual void PragmaDiagnosticPop(SourceLocation Loc,
+                                   llvm::StringRef Namespace);
+  virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
+                                diag::Mapping Map, llvm::StringRef Str);
 
   bool HandleFirstTokOnLine(Token &Tok);
   bool MoveToLine(SourceLocation Loc) {
@@ -361,6 +368,43 @@
   EmittedTokensOnThisLine = true;
 }
 
+void PrintPPOutputPPCallbacks::
+PragmaDiagnosticPush(SourceLocation Loc, llvm::StringRef Namespace) {
+  MoveToLine(Loc);
+  OS << "#pragma " << Namespace << " diagnostic push";
+  EmittedTokensOnThisLine = true;
+}
+
+void PrintPPOutputPPCallbacks::
+PragmaDiagnosticPop(SourceLocation Loc, llvm::StringRef Namespace) {
+  MoveToLine(Loc);
+  OS << "#pragma " << Namespace << " diagnostic pop";
+  EmittedTokensOnThisLine = true;
+}
+
+void PrintPPOutputPPCallbacks::
+PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace,
+                 diag::Mapping Map, llvm::StringRef Str) {
+  MoveToLine(Loc);
+  OS << "#pragma " << Namespace << " diagnostic ";
+  switch (Map) {
+  default: llvm_unreachable("unexpected diagnostic kind");
+  case diag::MAP_WARNING:
+    OS << "warning";
+    break;
+  case diag::MAP_ERROR:
+    OS << "error";
+    break;
+  case diag::MAP_IGNORE:
+    OS << "ignored";
+    break;
+  case diag::MAP_FATAL:
+    OS << "fatal";
+    break;
+  }
+  OS << " \"" << Str << '"';
+  EmittedTokensOnThisLine = true;
+}
 
 /// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
 /// is called for the first token on each new line.  If this really is the start
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 512b024..bd2ac1b 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -836,8 +836,11 @@
 
 /// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
 struct PragmaDiagnosticHandler : public PragmaHandler {
+private:
+  const char *Namespace;
 public:
-  explicit PragmaDiagnosticHandler() : PragmaHandler("diagnostic") {}
+  explicit PragmaDiagnosticHandler(const char *NS) :
+    PragmaHandler("diagnostic"), Namespace(NS) {}
   virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
                             Token &DiagToken) {
     SourceLocation DiagLoc = DiagToken.getLocation();
@@ -848,6 +851,7 @@
       return;
     }
     IdentifierInfo *II = Tok.getIdentifierInfo();
+    PPCallbacks *Callbacks = PP.getPPCallbacks();
 
     diag::Mapping Map;
     if (II->isStr("warning"))
@@ -861,10 +865,13 @@
     else if (II->isStr("pop")) {
       if (!PP.getDiagnostics().popMappings(DiagLoc))
         PP.Diag(Tok, diag::warn_pragma_diagnostic_cannot_pop);
-
+      else if (Callbacks)
+        Callbacks->PragmaDiagnosticPop(DiagLoc, Namespace);
       return;
     } else if (II->isStr("push")) {
       PP.getDiagnostics().pushMappings(DiagLoc);
+      if (Callbacks)
+        Callbacks->PragmaDiagnosticPush(DiagLoc, Namespace);
       return;
     } else {
       PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
@@ -916,6 +923,8 @@
                                                       Map, DiagLoc))
       PP.Diag(StrToks[0].getLocation(),
               diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
+    else if (Callbacks)
+      Callbacks->PragmaDiagnostic(DiagLoc, Namespace, Map, WarningName);
   }
 };
 
@@ -1010,13 +1019,13 @@
   AddPragmaHandler("GCC", new PragmaPoisonHandler());
   AddPragmaHandler("GCC", new PragmaSystemHeaderHandler());
   AddPragmaHandler("GCC", new PragmaDependencyHandler());
-  AddPragmaHandler("GCC", new PragmaDiagnosticHandler());
+  AddPragmaHandler("GCC", new PragmaDiagnosticHandler("GCC"));
   // #pragma clang ...
   AddPragmaHandler("clang", new PragmaPoisonHandler());
   AddPragmaHandler("clang", new PragmaSystemHeaderHandler());
   AddPragmaHandler("clang", new PragmaDebugHandler());
   AddPragmaHandler("clang", new PragmaDependencyHandler());
-  AddPragmaHandler("clang", new PragmaDiagnosticHandler());
+  AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
 
   AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
   AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
diff --git a/test/Preprocessor/pragma_diagnostic_output.c b/test/Preprocessor/pragma_diagnostic_output.c
new file mode 100644
index 0000000..e847107
--- /dev/null
+++ b/test/Preprocessor/pragma_diagnostic_output.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -E %s | FileCheck %s
+// CHECK: #pragma GCC diagnostic warning "-Wall"
+#pragma GCC diagnostic warning "-Wall"
+// CHECK: #pragma GCC diagnostic ignored "-Wall"
+#pragma GCC diagnostic ignored "-Wall"
+// CHECK: #pragma GCC diagnostic error "-Wall"
+#pragma GCC diagnostic error "-Wall"
+// CHECK: #pragma GCC diagnostic fatal "-Wall"
+#pragma GCC diagnostic fatal "-Wall"
+// CHECK: #pragma GCC diagnostic push
+#pragma GCC diagnostic push
+// CHECK: #pragma GCC diagnostic pop
+#pragma GCC diagnostic pop
+
+// CHECK: #pragma clang diagnostic warning "-Wall"
+#pragma clang diagnostic warning "-Wall"
+// CHECK: #pragma clang diagnostic ignored "-Wall"
+#pragma clang diagnostic ignored "-Wall"
+// CHECK: #pragma clang diagnostic error "-Wall"
+#pragma clang diagnostic error "-Wall"
+// CHECK: #pragma clang diagnostic fatal "-Wall"
+#pragma clang diagnostic fatal "-Wall"
+// CHECK: #pragma clang diagnostic push
+#pragma clang diagnostic push
+// CHECK: #pragma clang diagnostic pop
+#pragma clang diagnostic pop