From 04ae2df026b275aae5dddfc0db5ca55ff4e62179 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 12 Jul 2009 21:18:45 +0000 Subject: [PATCH] add push/pop semantics for diagnostics. Patch by Louis Gerbarg! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75431 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Diagnostic.h | 23 +++++++++--- include/clang/Basic/DiagnosticLexKinds.td | 9 ++++- lib/Basic/Diagnostic.cpp | 17 ++++++++- lib/Lex/Pragma.cpp | 44 ++++++++++++++++++----- test/Preprocessor/pushable-diagnostics.c | 17 +++++++++ 5 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 test/Preprocessor/pushable-diagnostics.c diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 207710bdff..cdfa7e1157 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -16,6 +16,7 @@ #include "clang/Basic/SourceLocation.h" #include +#include #include 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 DiagMappings; + mutable std::vector 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/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 6ca50db50a..9eda7bd2f3 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/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; -def warn_pragma_diagnostic_invalid : +def warn_pragma_diagnostic_gcc_invalid : ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or" " 'fatal'">, InGroup; +def warn_pragma_diagnostic_clang_invalid : + ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal'" + " 'push', or 'pop'">, + InGroup; +def warn_pragma_diagnostic_clang_cannot_ppp : + ExtWarn<"pragma diagnostic pop could not pop, no matching push">, + InGroup; def warn_pragma_diagnostic_invalid_option : ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">, InGroup; diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 78b8b0a855..6ba5907a34 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/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/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index bb0b71e226..fbdbd0b6e7 100644 --- a/lib/Lex/Pragma.cpp +++ b/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/test/Preprocessor/pushable-diagnostics.c b/test/Preprocessor/pushable-diagnostics.c new file mode 100644 index 0000000000..fe55122d66 --- /dev/null +++ b/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}} -- 2.50.1