diff options
author | Chris Lattner <sabre@nondot.org> | 2009-07-12 21:18:45 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-07-12 21:18:45 +0000 |
commit | fb42a1820f35c6f53f7fc33016bd45e0f21fcb4c (patch) | |
tree | 3d92ca11a48947b9fe17d8972aebae1736c22434 /clang | |
parent | 7b9d6ebb9cadc1cf21629266051083cc6d322102 (diff) | |
download | bcm5719-llvm-fb42a1820f35c6f53f7fc33016bd45e0f21fcb4c.tar.gz bcm5719-llvm-fb42a1820f35c6f53f7fc33016bd45e0f21fcb4c.zip |
add push/pop semantics for diagnostics. Patch by Louis Gerbarg!
llvm-svn: 75431
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/Diagnostic.h | 23 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticLexKinds.td | 9 | ||||
-rw-r--r-- | clang/lib/Basic/Diagnostic.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Lex/Pragma.cpp | 44 | ||||
-rw-r--r-- | clang/test/Preprocessor/pushable-diagnostics.c | 17 |
5 files changed, 96 insertions, 14 deletions
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 207710bdff3..cdfa7e1157e 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -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; diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 6ca50db50a8..9eda7bd2f31 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -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>; diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index 78b8b0a8559..6ba5907a34c 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -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. diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index bb0b71e2268..fbdbd0b6e76 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -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"))); diff --git a/clang/test/Preprocessor/pushable-diagnostics.c b/clang/test/Preprocessor/pushable-diagnostics.c new file mode 100644 index 00000000000..fe55122d66c --- /dev/null +++ b/clang/test/Preprocessor/pushable-diagnostics.c @@ -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}} |