#include "clang/Basic/SourceLocation.h"
#include <string>
+#include <vector>
#include <cassert>
namespace llvm {
/// 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;
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
/// 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;
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>;
ErrorOccurred = false;
FatalErrorOccurred = false;
NumDiagnostics = 0;
+
NumErrors = 0;
CustomDiagInfo = 0;
CurDiagID = ~0U;
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.
};
/// 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();
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;
}
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());
AddPragmaHandler("GCC", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
AddPragmaHandler("GCC", new PragmaDiagnosticHandler(
- getIdentifierInfo("diagnostic")));
+ getIdentifierInfo("diagnostic"),
+ false));
// #pragma clang ...
AddPragmaHandler("clang", new PragmaPoisonHandler(
getIdentifierInfo("poison")));
AddPragmaHandler("clang", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
AddPragmaHandler("clang", new PragmaDiagnosticHandler(
- getIdentifierInfo("diagnostic")));
+ getIdentifierInfo("diagnostic"),
+ true));
AddPragmaHandler("STDC", new PragmaSTDC_FP_CONTRACTHandler(
getIdentifierInfo("FP_CONTRACT")));
--- /dev/null
+// 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}}