add push/pop semantics for diagnostics. Patch by Louis Gerbarg!

llvm-svn: 75431
This commit is contained in:
Chris Lattner 2009-07-12 21:18:45 +00:00
parent 7b9d6ebb9c
commit fb42a1820f
5 changed files with 96 additions and 14 deletions

View File

@ -16,6 +16,7 @@
#include "clang/Basic/SourceLocation.h"
#include <string>
#include <vector>
#include <cassert>
namespace llvm {
@ -172,8 +173,10 @@ private:
/// when the mapping was established as a user mapping. If the high bit is
/// clear, then the low bits are set to the default value, and should be
/// mapped with -pedantic, -Werror, etc.
mutable unsigned char DiagMappings[diag::DIAG_UPPER_LIMIT/2];
typedef std::vector<unsigned char> DiagMappings;
mutable std::vector<DiagMappings> DiagMappingsStack;
/// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or
/// fatal error is emitted, and is sticky.
bool ErrorOccurred;
@ -212,6 +215,17 @@ public:
DiagnosticClient *getClient() { return Client; };
const DiagnosticClient *getClient() const { return Client; };
/// pushMappings - Copies the current DiagMappings and pushes the new copy
/// onto the top of the stack.
void pushMappings();
/// popMappings - Pops the current DiagMappings off the top of the stack
/// causing the new top of the stack to be the active mappings. Returns
/// true if the pop happens, false if there is only one DiagMapping on the
/// stack.
bool popMappings();
void setClient(DiagnosticClient* client) { Client = client; }
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
@ -343,13 +357,14 @@ private:
/// specified builtin diagnostic. This returns the high bit encoding, or zero
/// if the field is completely uninitialized.
unsigned getDiagnosticMappingInfo(diag::kind Diag) const {
return (diag::Mapping)((DiagMappings[Diag/2] >> (Diag & 1)*4) & 15);
const DiagMappings &currentMappings = DiagMappingsStack.back();
return (diag::Mapping)((currentMappings[Diag/2] >> (Diag & 1)*4) & 15);
}
void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map,
bool isUser) const {
if (isUser) Map |= 8; // Set the high bit for user mappings.
unsigned char &Slot = DiagMappings[DiagId/2];
unsigned char &Slot = DiagMappingsStack.back()[DiagId/2];
unsigned Shift = (DiagId & 1)*4;
Slot &= ~(15 << Shift);
Slot |= Map << Shift;

View File

@ -226,10 +226,17 @@ def ext_stdc_pragma_syntax_eom :
def warn_stdc_fenv_access_not_supported :
Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
InGroup<UnknownPragmas>;
def warn_pragma_diagnostic_invalid :
def warn_pragma_diagnostic_gcc_invalid :
ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or"
" 'fatal'">,
InGroup<UnknownPragmas>;
def warn_pragma_diagnostic_clang_invalid :
ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal'"
" 'push', or 'pop'">,
InGroup<UnknownPragmas>;
def warn_pragma_diagnostic_clang_cannot_ppp :
ExtWarn<"pragma diagnostic pop could not pop, no matching push">,
InGroup<UnknownPragmas>;
def warn_pragma_diagnostic_invalid_option :
ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">,
InGroup<UnknownPragmas>;

View File

@ -201,6 +201,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ErrorOccurred = false;
FatalErrorOccurred = false;
NumDiagnostics = 0;
NumErrors = 0;
CustomDiagInfo = 0;
CurDiagID = ~0U;
@ -210,13 +211,27 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ArgToStringCookie = 0;
// Set all mappings to 'unset'.
memset(DiagMappings, 0, sizeof(DiagMappings));
DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0);
DiagMappingsStack.push_back(BlankDiags);
}
Diagnostic::~Diagnostic() {
delete CustomDiagInfo;
}
void Diagnostic::pushMappings() {
DiagMappingsStack.push_back(DiagMappingsStack.back());
}
bool Diagnostic::popMappings() {
if (DiagMappingsStack.size() == 1)
return false;
DiagMappingsStack.pop_back();
return true;
}
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
/// and level. If this is the first request for this diagnosic, it is
/// registered and created, otherwise the existing ID is returned.

View File

@ -518,13 +518,23 @@ struct PragmaDependencyHandler : public PragmaHandler {
};
/// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
/// Since clang's diagnostic supports extended functionality beyond GCC's
/// the constructor takes a clangMode flag to tell it whether or not to allow
/// clang's extended functionality, or whether to reject it.
struct PragmaDiagnosticHandler : public PragmaHandler {
PragmaDiagnosticHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
private:
const bool ClangMode;
public:
PragmaDiagnosticHandler(const IdentifierInfo *ID,
const bool clangMode) : PragmaHandler(ID),
ClangMode(clangMode) {}
virtual void HandlePragma(Preprocessor &PP, Token &DiagToken) {
Token Tok;
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
unsigned Diag = ClangMode ? diag::warn_pragma_diagnostic_clang_invalid
: diag::warn_pragma_diagnostic_gcc_invalid;
PP.Diag(Tok, Diag);
return;
}
IdentifierInfo *II = Tok.getIdentifierInfo();
@ -538,8 +548,22 @@ struct PragmaDiagnosticHandler : public PragmaHandler {
Map = diag::MAP_IGNORE;
else if (II->isStr("fatal"))
Map = diag::MAP_FATAL;
else {
PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
else if (ClangMode) {
if (II->isStr("pop")) {
if(!PP.getDiagnostics().popMappings())
PP.Diag(Tok, diag::warn_pragma_diagnostic_clang_cannot_ppp);
return;
}
if (II->isStr("push")) {
PP.getDiagnostics().pushMappings();
return;
}
PP.Diag(Tok, diag::warn_pragma_diagnostic_clang_invalid);
return;
} else {
PP.Diag(Tok, diag::warn_pragma_diagnostic_gcc_invalid);
return;
}
@ -571,10 +595,12 @@ struct PragmaDiagnosticHandler : public PragmaHandler {
if (Literal.hadError)
return;
if (Literal.Pascal) {
PP.Diag(StrToks[0].getLocation(), diag::warn_pragma_diagnostic_invalid);
unsigned Diag = ClangMode ? diag::warn_pragma_diagnostic_clang_invalid
: diag::warn_pragma_diagnostic_gcc_invalid;
PP.Diag(Tok, Diag);
return;
}
std::string WarningName(Literal.GetString(),
Literal.GetString()+Literal.GetStringLength());
@ -689,7 +715,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("GCC", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
AddPragmaHandler("GCC", new PragmaDiagnosticHandler(
getIdentifierInfo("diagnostic")));
getIdentifierInfo("diagnostic"),
false));
// #pragma clang ...
AddPragmaHandler("clang", new PragmaPoisonHandler(
getIdentifierInfo("poison")));
@ -698,7 +725,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("clang", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
AddPragmaHandler("clang", new PragmaDiagnosticHandler(
getIdentifierInfo("diagnostic")));
getIdentifierInfo("diagnostic"),
true));
AddPragmaHandler("STDC", new PragmaSTDC_FP_CONTRACTHandler(
getIdentifierInfo("FP_CONTRACT")));

View File

@ -0,0 +1,17 @@
// RUN: clang-cc -fsyntax-only -verify -pedantic %s
#pragma clang diagnostic pop // expected-warning{{pragma diagnostic pop could not pop, no matching push}}
#pragma clang diagnostic puhs // expected-warning{{pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal' 'push', or 'pop'}}
char a = 'df'; // expected-warning{{multi-character character constant}}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmultichar"
char b = 'df'; // no warning.
#pragma clang diagnostic pop
char c = 'df'; // expected-warning{{multi-character character constant}}
#pragma clang diagnostic pop // expected-warning{{pragma diagnostic pop could not pop, no matching push}}