From: Chris Lattner Date: Sun, 19 Apr 2009 23:16:58 +0000 (+0000) Subject: implement "#pragma GCC diagnostic". Besides being a nice feature, this X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=edaf877d2469147ba818187a3e57a00b3f73b123;p=clang 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 bd10642534..32890c7cb8 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -217,6 +217,19 @@ def ext_stdc_pragma_syntax_eom : def warn_stdc_fenv_access_not_supported : ExtWarn<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, InGroup; +def warn_pragma_diagnostic_invalid : + ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or" + " 'fatal'">, + InGroup; +def warn_pragma_diagnostic_invalid_option : + ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">, + InGroup; +def warn_pragma_diagnostic_invalid_token : + ExtWarn<"unexpected token in pragma diagnostic">, + InGroup; +def warn_pragma_diagnostic_unknown_warning : + ExtWarn<"unknown warning group '%0', ignored">, + InGroup; 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 0dc093fd74..bde3fbc0e8 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -348,7 +348,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { 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 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { // macro expansion. // "foo " "bar" "Baz" llvm::SmallVector StrToks; - while (Tok.getKind() == tok::string_literal) { + while (Tok.is(tok::string_literal)) { StrToks.push_back(Tok); Lex(Tok); } @@ -502,6 +502,81 @@ struct PragmaDependencyHandler : public PragmaHandler { } }; +/// 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 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 @@ void Preprocessor::RegisterBuiltinPragmas() { getIdentifierInfo("system_header"))); AddPragmaHandler("GCC", new PragmaDependencyHandler( getIdentifierInfo("dependency"))); + AddPragmaHandler("GCC", new PragmaDiagnosticHandler( + getIdentifierInfo("diagnostic"))); AddPragmaHandler("STDC", new PragmaSTDC_FP_CONTRACTHandler( getIdentifierInfo("FP_CONTRACT")));