diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 0fd138b0ebed..21c93e7e8fa2 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -225,6 +225,9 @@ def err__Pragma_malformed : Error< "_Pragma takes a parenthesized string literal">; def err_pragma_comment_malformed : Error< "pragma comment requires parenthesized identifier and optional string">; +def err_pragma_message_malformed : Error< + "pragma message requires parenthesized string">; +def warn_pragma_message : Warning<"%0">; def warn_pragma_ignored : Warning<"unknown pragma ignored">, InGroup, DefaultIgnore; def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h index d74124e9c79b..99fe29b22dc2 100644 --- a/clang/include/clang/Lex/PPCallbacks.h +++ b/clang/include/clang/Lex/PPCallbacks.h @@ -16,6 +16,7 @@ #include "clang/Lex/DirectoryLookup.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" #include namespace clang { @@ -70,6 +71,12 @@ public: const std::string &Str) { } + /// PragmaMessage - This callback is invoked when a #pragma message directive + /// is read. + /// + virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) { + } + /// MacroExpands - This is called by /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is /// found. @@ -127,6 +134,11 @@ public: Second->PragmaComment(Loc, Kind, Str); } + virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) { + First->PragmaMessage(Loc, Str); + Second->PragmaMessage(Loc, Str); + } + virtual void MacroExpands(const Token &Id, const MacroInfo* MI) { First->MacroExpands(Id, MI); Second->MacroExpands(Id, MI); diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index f01b3afc45f5..f90cb0a68799 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -918,6 +918,7 @@ public: void HandlePragmaSystemHeader(Token &SysHeaderTok); void HandlePragmaDependency(Token &DependencyTok); void HandlePragmaComment(Token &CommentTok); + void HandlePragmaMessage(Token &MessageTok); // 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); diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 74552dda25fb..7385ca6cfd4d 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -23,6 +23,7 @@ #include "clang/Lex/TokenConcatenation.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/raw_ostream.h" #include @@ -117,7 +118,7 @@ public: virtual void Ident(SourceLocation Loc, const std::string &str); virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str); - + virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str); bool HandleFirstTokOnLine(Token &Tok); bool MoveToLine(SourceLocation Loc) { @@ -306,6 +307,29 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, EmittedTokensOnThisLine = true; } +void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, + llvm::StringRef Str) { + MoveToLine(Loc); + OS << "#pragma message("; + + OS << '"'; + + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + unsigned char Char = Str[i]; + if (isprint(Char) && Char != '\\' && Char != '"') + OS << (char)Char; + else // Output anything hard as an octal escape. + OS << '\\' + << (char)('0'+ ((Char >> 6) & 7)) + << (char)('0'+ ((Char >> 3) & 7)) + << (char)('0'+ ((Char >> 0) & 7)); + } + OS << '"'; + + OS << ')'; + 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/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 58a632618fd3..18b46ad6116b 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -419,7 +419,68 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { Callbacks->PragmaComment(CommentLoc, II, ArgumentString); } +/// HandlePragmaMessage - Handle the microsoft #pragma message extension. The +/// syntax is: +/// #pragma message(messagestring) +/// messagestring is a string, which is fully macro expanded, and permits string +/// concatenation, embedded escape characters etc. See MSDN for more details. +void Preprocessor::HandlePragmaMessage(Token &Tok) { + SourceLocation MessageLoc = Tok.getLocation(); + Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(MessageLoc, diag::err_pragma_message_malformed); + return; + } + // Read the string. + Lex(Tok); + + + // We need at least one string. + if (Tok.isNot(tok::string_literal)) { + Diag(Tok.getLocation(), diag::err_pragma_message_malformed); + return; + } + + // String concatenation allows multiple strings, which can even come from + // macro expansion. + // "foo " "bar" "Baz" + llvm::SmallVector StrToks; + while (Tok.is(tok::string_literal)) { + StrToks.push_back(Tok); + Lex(Tok); + } + + // Concatenate and parse the strings. + StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); + assert(!Literal.AnyWide && "Didn't allow wide strings in"); + if (Literal.hadError) + return; + if (Literal.Pascal) { + Diag(StrToks[0].getLocation(), diag::err_pragma_message_malformed); + return; + } + + llvm::StringRef MessageString(Literal.GetString(), Literal.GetStringLength()); + + if (Tok.isNot(tok::r_paren)) { + Diag(Tok.getLocation(), diag::err_pragma_message_malformed); + return; + } + Lex(Tok); // eat the r_paren. + + if (Tok.isNot(tok::eom)) { + Diag(Tok.getLocation(), diag::err_pragma_message_malformed); + return; + } + + // Output the message. + Diag(MessageLoc, diag::warn_pragma_message) << MessageString; + + // If the pragma is lexically sound, notify any interested PPCallbacks. + if (Callbacks) + Callbacks->PragmaMessage(MessageLoc, MessageString); +} /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. @@ -632,6 +693,14 @@ struct PragmaCommentHandler : public PragmaHandler { } }; +/// PragmaMessageHandler - "#pragma message("...")". +struct PragmaMessageHandler : public PragmaHandler { + PragmaMessageHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} + virtual void HandlePragma(Preprocessor &PP, Token &CommentTok) { + PP.HandlePragmaMessage(CommentTok); + } +}; + // Pragma STDC implementations. enum STDCSetting { @@ -743,6 +812,8 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler()); // MS extensions. - if (Features.Microsoft) + if (Features.Microsoft) { AddPragmaHandler(0, new PragmaCommentHandler(getIdentifierInfo("comment"))); + AddPragmaHandler(0, new PragmaMessageHandler(getIdentifierInfo("message"))); + } }