forked from OSchip/llvm-project
add push/pop semantics for diagnostics. Patch by Louis Gerbarg!
llvm-svn: 75431
This commit is contained in:
parent
7b9d6ebb9c
commit
fb42a1820f
|
@ -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 ¤tMappings = 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;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")));
|
||||
|
|
|
@ -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}}
|
Loading…
Reference in New Issue