Implemented #pragma GCC warning/error in the same mould as #pragma message.
llvm-svn: 179687
This commit is contained in:
parent
2d5c341cee
commit
9c2ccd622f
|
@ -652,6 +652,31 @@ supports the GCC pragma, Clang and GCC do not support the exact same set
|
|||
of warnings, so even when using GCC compatible #pragmas there is no
|
||||
guarantee that they will have identical behaviour on both compilers.
|
||||
|
||||
In addition to controlling warnings and errors generated by the compiler, it is
|
||||
possible to generate custom warning and error messages through the following
|
||||
pragmas:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// The following will produce warning messages
|
||||
#pragma message "some diagnostic message"
|
||||
#pragma GCC warning "TODO: replace deprecated feature"
|
||||
|
||||
// The following will produce an error message
|
||||
#pragma GCC error "Not supported"
|
||||
|
||||
These pragmas operate similarly to the ``#warning`` and ``#error`` preprocessor
|
||||
directives, except that they may also be embedded into preprocessor macros via
|
||||
the C99 ``_Pragma`` operator, for example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define STR(X) #X
|
||||
#define DEFER(M,...) M(__VA_ARGS__)
|
||||
#define CUSTOM_ERROR(X) _Pragma(STR(GCC error(X " at line " DEFER(STR,__LINE__))))
|
||||
|
||||
CUSTOM_ERROR("Feature not available");
|
||||
|
||||
Controlling Diagnostics in System Headers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -406,13 +406,14 @@ def err__Pragma_malformed : Error<
|
|||
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">;
|
||||
"pragma %select{message|warning|error}0 requires parenthesized string">;
|
||||
def err_pragma_push_pop_macro_malformed : Error<
|
||||
"pragma %0 requires a parenthesized string">;
|
||||
def warn_pragma_pop_macro_no_push : Warning<
|
||||
"pragma pop_macro could not pop '%0', no matching push_macro">;
|
||||
def warn_pragma_message : Warning<"%0">,
|
||||
InGroup<PoundPragmaMessage>, DefaultWarnNoWerror;
|
||||
def err_pragma_message : Error<"%0">;
|
||||
def warn_pragma_ignored : Warning<"unknown pragma ignored">,
|
||||
InGroup<UnknownPragmas>, DefaultIgnore;
|
||||
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
|
||||
|
|
|
@ -165,10 +165,25 @@ public:
|
|||
virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType) {
|
||||
}
|
||||
|
||||
/// \brief Determines the kind of \#pragma invoking a call to PragmaMessage.
|
||||
enum PragmaMessageKind {
|
||||
/// \brief \#pragma message has been invoked.
|
||||
PMK_Message,
|
||||
|
||||
/// \brief \#pragma GCC warning has been invoked.
|
||||
PMK_Warning,
|
||||
|
||||
/// \brief \#pragma GCC error has been invoked.
|
||||
PMK_Error
|
||||
};
|
||||
|
||||
/// \brief Callback invoked when a \#pragma message directive is read.
|
||||
/// \param Loc The location of the message directive.
|
||||
/// \param Namespace The namespace of the message directive.
|
||||
/// \param Kind The type of the message directive.
|
||||
/// \param Str The text of the message directive.
|
||||
virtual void PragmaMessage(SourceLocation Loc, StringRef Str) {
|
||||
virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
|
||||
PragmaMessageKind Kind, StringRef Str) {
|
||||
}
|
||||
|
||||
/// \brief Callback invoked when a \#pragma gcc dianostic push directive
|
||||
|
@ -336,9 +351,10 @@ public:
|
|||
Second->PragmaComment(Loc, Kind, Str);
|
||||
}
|
||||
|
||||
virtual void PragmaMessage(SourceLocation Loc, StringRef Str) {
|
||||
First->PragmaMessage(Loc, Str);
|
||||
Second->PragmaMessage(Loc, Str);
|
||||
virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
|
||||
PragmaMessageKind Kind, StringRef Str) {
|
||||
First->PragmaMessage(Loc, Namespace, Kind, Str);
|
||||
Second->PragmaMessage(Loc, Namespace, Kind, Str);
|
||||
}
|
||||
|
||||
virtual void PragmaDiagnosticPush(SourceLocation Loc,
|
||||
|
|
|
@ -1445,7 +1445,6 @@ public:
|
|||
void HandlePragmaSystemHeader(Token &SysHeaderTok);
|
||||
void HandlePragmaDependency(Token &DependencyTok);
|
||||
void HandlePragmaComment(Token &CommentTok);
|
||||
void HandlePragmaMessage(Token &MessageTok);
|
||||
void HandlePragmaPushMacro(Token &Tok);
|
||||
void HandlePragmaPopMacro(Token &Tok);
|
||||
void HandlePragmaIncludeAlias(Token &Tok);
|
||||
|
|
|
@ -140,7 +140,8 @@ public:
|
|||
virtual void PragmaCaptured(SourceLocation Loc, StringRef Str);
|
||||
virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
|
||||
const std::string &Str);
|
||||
virtual void PragmaMessage(SourceLocation Loc, StringRef Str);
|
||||
virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
|
||||
PragmaMessageKind Kind, StringRef Str);
|
||||
virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType);
|
||||
virtual void PragmaDiagnosticPush(SourceLocation Loc,
|
||||
StringRef Namespace);
|
||||
|
@ -407,12 +408,25 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
|
|||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
|
||||
StringRef Namespace,
|
||||
PragmaMessageKind Kind,
|
||||
StringRef Str) {
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma message(";
|
||||
|
||||
OS << '"';
|
||||
OS << "#pragma ";
|
||||
if (!Namespace.empty())
|
||||
OS << Namespace << ' ';
|
||||
switch (Kind) {
|
||||
case PMK_Message:
|
||||
OS << "message(\"";
|
||||
break;
|
||||
case PMK_Warning:
|
||||
OS << "warning(\"";
|
||||
break;
|
||||
case PMK_Error:
|
||||
OS << "error(\"";
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
|
||||
unsigned char Char = Str[i];
|
||||
|
|
|
@ -554,62 +554,6 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
|
|||
Callbacks->PragmaComment(CommentLoc, II, ArgumentString);
|
||||
}
|
||||
|
||||
/// HandlePragmaMessage - Handle the microsoft and gcc \#pragma message
|
||||
/// extension. The syntax is:
|
||||
/// \code
|
||||
/// #pragma message(string)
|
||||
/// \endcode
|
||||
/// OR, in GCC mode:
|
||||
/// \code
|
||||
/// #pragma message string
|
||||
/// \endcode
|
||||
/// string 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);
|
||||
bool ExpectClosingParen = false;
|
||||
switch (Tok.getKind()) {
|
||||
case tok::l_paren:
|
||||
// We have a MSVC style pragma message.
|
||||
ExpectClosingParen = true;
|
||||
// Read the string.
|
||||
Lex(Tok);
|
||||
break;
|
||||
case tok::string_literal:
|
||||
// We have a GCC style pragma message, and we just read the string.
|
||||
break;
|
||||
default:
|
||||
Diag(MessageLoc, diag::err_pragma_message_malformed);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string MessageString;
|
||||
if (!FinishLexStringLiteral(Tok, MessageString, "pragma message",
|
||||
/*MacroExpansion=*/true))
|
||||
return;
|
||||
|
||||
if (ExpectClosingParen) {
|
||||
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::eod)) {
|
||||
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);
|
||||
}
|
||||
|
||||
/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro.
|
||||
/// Return the IdentifierInfo* associated with the macro to push or pop.
|
||||
IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
|
||||
|
@ -1134,12 +1078,88 @@ struct PragmaIncludeAliasHandler : public PragmaHandler {
|
|||
}
|
||||
};
|
||||
|
||||
/// PragmaMessageHandler - "\#pragma message("...")".
|
||||
/// PragmaMessageHandler - Handle the microsoft and gcc \#pragma message
|
||||
/// extension. The syntax is:
|
||||
/// \code
|
||||
/// #pragma message(string)
|
||||
/// \endcode
|
||||
/// OR, in GCC mode:
|
||||
/// \code
|
||||
/// #pragma message string
|
||||
/// \endcode
|
||||
/// string is a string, which is fully macro expanded, and permits string
|
||||
/// concatenation, embedded escape characters, etc... See MSDN for more details.
|
||||
/// Also handles \#pragma GCC warning and \#pragma GCC error which take the same
|
||||
/// form as \#pragma message.
|
||||
struct PragmaMessageHandler : public PragmaHandler {
|
||||
PragmaMessageHandler() : PragmaHandler("message") {}
|
||||
private:
|
||||
const PPCallbacks::PragmaMessageKind Kind;
|
||||
const StringRef Namespace;
|
||||
|
||||
static const char* PragmaKind(PPCallbacks::PragmaMessageKind Kind,
|
||||
bool PragmaNameOnly = false) {
|
||||
switch (Kind) {
|
||||
case PPCallbacks::PMK_Message:
|
||||
return PragmaNameOnly ? "message" : "pragma message";
|
||||
case PPCallbacks::PMK_Warning:
|
||||
return PragmaNameOnly ? "warning" : "pragma warning";
|
||||
case PPCallbacks::PMK_Error:
|
||||
return PragmaNameOnly ? "error" : "pragma error";
|
||||
}
|
||||
llvm_unreachable("Unknown PragmaMessageKind!");
|
||||
}
|
||||
|
||||
public:
|
||||
PragmaMessageHandler(PPCallbacks::PragmaMessageKind Kind,
|
||||
StringRef Namespace = StringRef())
|
||||
: PragmaHandler(PragmaKind(Kind, true)), Kind(Kind), Namespace(Namespace) {}
|
||||
|
||||
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
|
||||
Token &CommentTok) {
|
||||
PP.HandlePragmaMessage(CommentTok);
|
||||
Token &Tok) {
|
||||
SourceLocation MessageLoc = Tok.getLocation();
|
||||
PP.Lex(Tok);
|
||||
bool ExpectClosingParen = false;
|
||||
switch (Tok.getKind()) {
|
||||
case tok::l_paren:
|
||||
// We have a MSVC style pragma message.
|
||||
ExpectClosingParen = true;
|
||||
// Read the string.
|
||||
PP.Lex(Tok);
|
||||
break;
|
||||
case tok::string_literal:
|
||||
// We have a GCC style pragma message, and we just read the string.
|
||||
break;
|
||||
default:
|
||||
PP.Diag(MessageLoc, diag::err_pragma_message_malformed) << Kind;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string MessageString;
|
||||
if (!PP.FinishLexStringLiteral(Tok, MessageString, PragmaKind(Kind),
|
||||
/*MacroExpansion=*/true))
|
||||
return;
|
||||
|
||||
if (ExpectClosingParen) {
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind;
|
||||
return;
|
||||
}
|
||||
PP.Lex(Tok); // eat the r_paren.
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind;
|
||||
return;
|
||||
}
|
||||
|
||||
// Output the message.
|
||||
PP.Diag(MessageLoc, (Kind == PPCallbacks::PMK_Error)
|
||||
? diag::err_pragma_message
|
||||
: diag::warn_pragma_message) << MessageString;
|
||||
|
||||
// If the pragma is lexically sound, notify any interested PPCallbacks.
|
||||
if (PPCallbacks *Callbacks = PP.getPPCallbacks())
|
||||
Callbacks->PragmaMessage(MessageLoc, Namespace, Kind, MessageString);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1287,13 +1307,17 @@ void Preprocessor::RegisterBuiltinPragmas() {
|
|||
AddPragmaHandler(new PragmaMarkHandler());
|
||||
AddPragmaHandler(new PragmaPushMacroHandler());
|
||||
AddPragmaHandler(new PragmaPopMacroHandler());
|
||||
AddPragmaHandler(new PragmaMessageHandler());
|
||||
AddPragmaHandler(new PragmaMessageHandler(PPCallbacks::PMK_Message));
|
||||
|
||||
// #pragma GCC ...
|
||||
AddPragmaHandler("GCC", new PragmaPoisonHandler());
|
||||
AddPragmaHandler("GCC", new PragmaSystemHeaderHandler());
|
||||
AddPragmaHandler("GCC", new PragmaDependencyHandler());
|
||||
AddPragmaHandler("GCC", new PragmaDiagnosticHandler("GCC"));
|
||||
AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Warning,
|
||||
"GCC"));
|
||||
AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Error,
|
||||
"GCC"));
|
||||
// #pragma clang ...
|
||||
AddPragmaHandler("clang", new PragmaPoisonHandler());
|
||||
AddPragmaHandler("clang", new PragmaSystemHeaderHandler());
|
||||
|
|
|
@ -14,3 +14,19 @@
|
|||
#pragma message ":O gcc accepts this! " STRING(__LINE__) // expected-warning {{:O gcc accepts this! 14}}
|
||||
|
||||
#pragma message(invalid) // expected-error {{expected string literal in pragma message}}
|
||||
|
||||
// GCC supports a similar pragma, #pragma GCC warning (which generates a warning
|
||||
// message) and #pragma GCC error (which generates an error message).
|
||||
|
||||
#pragma GCC warning(":O I'm a message! " STRING(__LINE__)) // expected-warning {{:O I'm a message! 21}}
|
||||
#pragma GCC warning ":O gcc accepts this! " STRING(__LINE__) // expected-warning {{:O gcc accepts this! 22}}
|
||||
|
||||
#pragma GCC error(":O I'm a message! " STRING(__LINE__)) // expected-error {{:O I'm a message! 24}}
|
||||
#pragma GCC error ":O gcc accepts this! " STRING(__LINE__) // expected-error {{:O gcc accepts this! 25}}
|
||||
|
||||
#define COMPILE_ERROR(x) _Pragma(STRING2(GCC error(x)))
|
||||
COMPILE_ERROR("Compile error at line " STRING(__LINE__) "!"); // expected-error {{Compile error at line 28!}}
|
||||
|
||||
#pragma message // expected-error {{pragma message requires parenthesized string}}
|
||||
#pragma GCC warning("" // expected-error {{pragma warning requires parenthesized string}}
|
||||
#pragma GCC error(1) // expected-error {{expected string literal in pragma error}}
|
||||
|
|
Loading…
Reference in New Issue