Implement support for #pragma message, patch by Michael Spencer!

llvm-svn: 106950
This commit is contained in:
Chris Lattner 2010-06-26 17:11:39 +00:00
parent 04775f8413
commit 30c924b3e8
5 changed files with 113 additions and 2 deletions

View File

@ -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<UnknownPragmas>, DefaultIgnore;
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,

View File

@ -16,6 +16,7 @@
#include "clang/Lex/DirectoryLookup.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/StringRef.h"
#include <string>
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);

View File

@ -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);

View File

@ -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 <cstdio>
@ -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

View File

@ -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<Token, 4> 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")));
}
}