Move PragmaCommentHandler to lib/Parse in preparation for calling Sema

Summary:
No functionality change.  The existing tests for this pragma only verify
that we can preprocess it.

Reviewers: rsmith

CC: cfe-commits

Differential Revision: http://llvm-reviews.chandlerc.com/D751

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181246 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index ef43c5b..3d1249a 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -16,6 +16,7 @@
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
 #include "clang/Sema/Scope.h"
+#include "llvm/ADT/StringSwitch.h"
 using namespace clang;
 
 /// \brief Handle the annotation token produced for #pragma unused(...)
@@ -792,3 +793,68 @@
   PP.EnterTokenStream(Toks, Pragma.size(),
                       /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
 }
+
+/// \brief Handle the microsoft \#pragma comment extension.
+///
+/// The syntax is:
+/// \code
+///   #pragma comment(linker, "foo")
+/// \endcode
+/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user.
+/// "foo" is a string, which is fully macro expanded, and permits string
+/// concatenation, embedded escape characters etc.  See MSDN for more details.
+void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
+                                        PragmaIntroducerKind Introducer,
+                                        Token &Tok) {
+  SourceLocation CommentLoc = Tok.getLocation();
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::l_paren)) {
+    PP.Diag(CommentLoc, diag::err_pragma_comment_malformed);
+    return;
+  }
+
+  // Read the identifier.
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::identifier)) {
+    PP.Diag(CommentLoc, diag::err_pragma_comment_malformed);
+    return;
+  }
+
+  // Verify that this is one of the 5 whitelisted options.
+  // FIXME: warn that 'exestr' is deprecated.
+  const IdentifierInfo *II = Tok.getIdentifierInfo();
+  if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") &&
+      !II->isStr("linker") && !II->isStr("user")) {
+    PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
+    return;
+  }
+
+  // Read the optional string if present.
+  PP.Lex(Tok);
+  std::string ArgumentString;
+  if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString,
+                                                 "pragma comment",
+                                                 /*MacroExpansion=*/true))
+    return;
+
+  // FIXME: If the kind is "compiler" warn if the string is present (it is
+  // ignored).
+  // FIXME: 'lib' requires a comment string.
+  // FIXME: 'linker' requires a comment string, and has a specific list of
+  // things that are allowable.
+
+  if (Tok.isNot(tok::r_paren)) {
+    PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
+    return;
+  }
+  PP.Lex(Tok);  // eat the r_paren.
+
+  if (Tok.isNot(tok::eod)) {
+    PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
+    return;
+  }
+
+  // If the pragma is lexically sound, notify any interested PPCallbacks.
+  if (PP.getPPCallbacks())
+    PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index 841a60b..d9560f3 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -113,6 +113,14 @@
                             Token &FirstToken);
 };
 
+/// PragmaCommentHandler - "\#pragma comment ...".
+class PragmaCommentHandler : public PragmaHandler {
+public:
+  PragmaCommentHandler() : PragmaHandler("comment") {}
+  virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+                            Token &FirstToken);
+};
+
 }  // end namespace clang
 
 #endif
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index d819644..455139b 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -102,6 +102,11 @@
     OpenMPHandler.reset(new PragmaNoOpenMPHandler());
   PP.AddPragmaHandler(OpenMPHandler.get());
 
+  if (getLangOpts().MicrosoftExt) {
+    MSCommentHandler.reset(new PragmaCommentHandler());
+    PP.AddPragmaHandler(MSCommentHandler.get());
+  }
+
   CommentSemaHandler.reset(new ActionCommentHandler(actions));
   PP.addCommentHandler(CommentSemaHandler.get());
 
@@ -436,6 +441,11 @@
   PP.RemovePragmaHandler(OpenMPHandler.get());
   OpenMPHandler.reset();
 
+  if (getLangOpts().MicrosoftExt) {
+    PP.RemovePragmaHandler(MSCommentHandler.get());
+    MSCommentHandler.reset();
+  }
+
   PP.RemovePragmaHandler("STDC", FPContractHandler.get());
   FPContractHandler.reset();