implement "#pragma GCC diagnostic". Besides being a nice feature, this
will let us test for multiple different warning modes in the same
file in regression tests.
This implements rdar://2362963, a 10-year old feature request :)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69560 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index bd10642..32890c7 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -217,6 +217,19 @@
def warn_stdc_fenv_access_not_supported :
ExtWarn<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_invalid :
+ ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or"
+ " 'fatal'">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_invalid_option :
+ ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_invalid_token :
+ ExtWarn<"unexpected token in pragma diagnostic">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_unknown_warning :
+ ExtWarn<"unknown warning group '%0', ignored">,
+ InGroup<UnknownPragmas>;
def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">;
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 0dc093f..bde3fbc 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -348,7 +348,7 @@
Lex(Tok); // eat the comma.
// We need at least one string.
- if (Tok.getKind() != tok::string_literal) {
+ if (Tok.isNot(tok::string_literal)) {
Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
return;
}
@@ -357,7 +357,7 @@
// macro expansion.
// "foo " "bar" "Baz"
llvm::SmallVector<Token, 4> StrToks;
- while (Tok.getKind() == tok::string_literal) {
+ while (Tok.is(tok::string_literal)) {
StrToks.push_back(Tok);
Lex(Tok);
}
@@ -502,6 +502,81 @@
}
};
+/// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
+struct PragmaDiagnosticHandler : public PragmaHandler {
+ PragmaDiagnosticHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ 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);
+ return;
+ }
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ diag::Mapping Map;
+ if (II->isStr("warning"))
+ Map = diag::MAP_WARNING;
+ else if (II->isStr("error"))
+ Map = diag::MAP_ERROR;
+ else if (II->isStr("ignored"))
+ Map = diag::MAP_IGNORE;
+ else if (II->isStr("fatal"))
+ Map = diag::MAP_FATAL;
+ else {
+ PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
+ return;
+ }
+
+ PP.LexUnexpandedToken(Tok);
+
+ // We need at least one string.
+ if (Tok.isNot(tok::string_literal)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
+ return;
+ }
+
+ // String concatenation allows multiple strings, which can even come from
+ // macro expansion.
+ // "foo " "bar" "Baz"
+ llvm::SmallVector<Token, 4> StrToks;
+ while (Tok.is(tok::string_literal)) {
+ StrToks.push_back(Tok);
+ PP.LexUnexpandedToken(Tok);
+ }
+
+ if (Tok.isNot(tok::eom)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
+ return;
+ }
+
+ // Concatenate and parse the strings.
+ StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP);
+ assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ if (Literal.hadError)
+ return;
+ if (Literal.Pascal) {
+ PP.Diag(StrToks[0].getLocation(), diag::warn_pragma_diagnostic_invalid);
+ return;
+ }
+
+ std::string WarningName(Literal.GetString(),
+ Literal.GetString()+Literal.GetStringLength());
+
+ if (WarningName.size() < 3 || WarningName[0] != '-' ||
+ WarningName[1] != 'W') {
+ PP.Diag(StrToks[0].getLocation(),
+ diag::warn_pragma_diagnostic_invalid_option);
+ return;
+ }
+
+ if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.c_str()+2,
+ Map))
+ PP.Diag(StrToks[0].getLocation(),
+ diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
+ }
+};
+
/// PragmaCommentHandler - "#pragma comment ...".
struct PragmaCommentHandler : public PragmaHandler {
PragmaCommentHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
@@ -596,6 +671,8 @@
getIdentifierInfo("system_header")));
AddPragmaHandler("GCC", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
+ AddPragmaHandler("GCC", new PragmaDiagnosticHandler(
+ getIdentifierInfo("diagnostic")));
AddPragmaHandler("STDC", new PragmaSTDC_FP_CONTRACTHandler(
getIdentifierInfo("FP_CONTRACT")));