diff options
| -rw-r--r-- | clang/docs/LanguageExtensions.html | 17 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 1 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticIDs.h | 2 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticLexKinds.td | 7 | ||||
| -rw-r--r-- | clang/include/clang/Lex/Preprocessor.h | 1 | ||||
| -rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 69 |
6 files changed, 96 insertions, 1 deletions
diff --git a/clang/docs/LanguageExtensions.html b/clang/docs/LanguageExtensions.html index d8a57df4865..ef57a659c4d 100644 --- a/clang/docs/LanguageExtensions.html +++ b/clang/docs/LanguageExtensions.html @@ -300,6 +300,23 @@ and will issue a warning if used in the top-level compilation file. A warning will also be issued if an absolute path is used in the file argument.</p> + +<!-- ======================================================================= --> +<h3><a name="__has_warning">__has_warning</a></h3> +<!-- ======================================================================= --> + +<p>This function-like macro takes a string literal that represents a command + line option for a warning and returns true if that is a valid warning + option.</p> + +<blockquote> +<pre> +#if __has_warning("-Wformat") +... +#endif +</pre> +</blockquote> + <!-- ======================================================================= --> <h2 id="builtinmacros">Builtin Macros</h2> <!-- ======================================================================= --> diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 8020dd163d2..55e88312811 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -73,6 +73,7 @@ def : DiagGroup<"int-to-pointer-cast">; def : DiagGroup<"invalid-pch">; def LiteralRange : DiagGroup<"literal-range">; def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args">; +def MalformedWarningCheck : DiagGroup<"malformed-warning-check">; def Main : DiagGroup<"main">; def MissingBraces : DiagGroup<"missing-braces">; def MissingDeclarations: DiagGroup<"missing-declarations">; diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index e158bf52b5c..16d9b39985e 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -251,7 +251,6 @@ public: static diag_iterator diags_begin(); static diag_iterator diags_end(); -private: /// \brief Get the set of all diagnostic IDs in the group with the given name. /// /// \param Diags [out] - On return, the diagnostics in the group. @@ -259,6 +258,7 @@ private: bool getDiagnosticsInGroup(StringRef Group, llvm::SmallVectorImpl<diag::kind> &Diags) const; +private: /// \brief Get the set of all diagnostic IDs in the given group. /// /// \param Diags [out] - On return, the diagnostics in the group. diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 2d6cbe8fc3c..6655472057b 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -242,6 +242,13 @@ def err_pp_used_poisoned_id : Error<"attempt to use a poisoned identifier">; def err_feature_check_malformed : Error< "builtin feature check macro requires a parenthesized identifier">; +def err_warning_check_malformed : Error< + "builtin warning check macro requires a parenthesized string">, + InGroup<MalformedWarningCheck>; +def warn_has_warning_invalid_option : + ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">, + InGroup<MalformedWarningCheck>; + def err__Pragma_malformed : Error< "_Pragma takes a parenthesized string literal">; def err_pragma_comment_malformed : Error< diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 7e64fc4d8ad..8b7743316f9 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -93,6 +93,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> { IdentifierInfo *Ident__has_attribute; // __has_attribute IdentifierInfo *Ident__has_include; // __has_include IdentifierInfo *Ident__has_include_next; // __has_include_next + IdentifierInfo *Ident__has_warning; // __has_warning SourceLocation DATELoc, TIMELoc; unsigned CounterValue; // Next __COUNTER__ value. diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 5bdebf93b36..486ffbeb9c9 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -21,6 +21,7 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/LiteralSupport.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" @@ -92,6 +93,7 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); + Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning"); // Microsoft Extensions. if (Features.MicrosoftExt) @@ -1016,6 +1018,73 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Value = EvaluateHasIncludeNext(Tok, II, *this); OS << (int)Value; Tok.setKind(tok::numeric_constant); + } else if (II == Ident__has_warning) { + // The argument should be a parenthesized string literal. + // The argument to these builtins should be a parenthesized identifier. + SourceLocation StartLoc = Tok.getLocation(); + bool IsValid = false; + bool Value = false; + // Read the '('. + Lex(Tok); + do { + if (Tok.is(tok::l_paren)) { + // Read the string. + Lex(Tok); + + // We need at least one string literal. + if (!Tok.is(tok::string_literal)) { + StartLoc = Tok.getLocation(); + IsValid = false; + // Eat tokens until ')'. + do Lex(Tok); while (!(Tok.is(tok::r_paren) || Tok.is(tok::eod))); + break; + } + + // String concatenation allows multiple strings, which can even come + // from macro expansion. + SmallVector<Token, 4> StrToks; + while (Tok.is(tok::string_literal)) { + StrToks.push_back(Tok); + LexUnexpandedToken(Tok); + } + + // Is the end a ')'? + if (!(IsValid = Tok.is(tok::r_paren))) + break; + + // Concatenate and parse the strings. + StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); + assert(Literal.isAscii() && "Didn't allow wide strings in"); + if (Literal.hadError) + break; + if (Literal.Pascal) { + Diag(Tok, diag::warn_pragma_diagnostic_invalid); + break; + } + + StringRef WarningName(Literal.GetString()); + + if (WarningName.size() < 3 || WarningName[0] != '-' || + WarningName[1] != 'W') { + Diag(StrToks[0].getLocation(), diag::warn_has_warning_invalid_option); + break; + } + + // Finally, check if the warning flags maps to a diagnostic group. + // We construct a SmallVector here to talk to getDiagnosticIDs(). + // Although we don't use the result, this isn't a hot path, and not + // worth special casing. + llvm::SmallVector<diag::kind, 10> Diags; + Value = !getDiagnostics().getDiagnosticIDs()-> + getDiagnosticsInGroup(WarningName.substr(2), Diags); + } + } while (false); + + if (!IsValid) + Diag(StartLoc, diag::err_warning_check_malformed); + + OS << (int)Value; + Tok.setKind(tok::numeric_constant); } else { llvm_unreachable("Unknown identifier!"); } |

