]> granicus.if.org Git - clang/commitdiff
Implement built-in macro '__has_warning', which allows one to query if a warning...
authorTed Kremenek <kremenek@apple.com>
Wed, 12 Oct 2011 19:46:30 +0000 (19:46 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 12 Oct 2011 19:46:30 +0000 (19:46 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141802 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LanguageExtensions.html
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticIDs.h
include/clang/Basic/DiagnosticLexKinds.td
include/clang/Lex/Preprocessor.h
lib/Lex/PPMacroExpansion.cpp

index d8a57df4865a6aa7b5cb4e9c749e49b8fe937714..ef57a659c4de4be8ae8b352d80837a769b01e378 100644 (file)
@@ -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>
 <!-- ======================================================================= -->
index 8020dd163d23904fcd8162fdb1bf2923a0898ce1..55e88312811deaf01564cf6332b705f6e80e7ea0 100644 (file)
@@ -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">;
index e158bf52b5c72fe52b5780408d49f62f797618e0..16d9b39985ed2db41ffd5e61b5c9f6a8cb66e87a 100644 (file)
@@ -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.
index 2d6cbe8fc3c7e4c3264e42632ee3c1f56b188529..6655472057b846521a3deeafe10f04440a303611 100644 (file)
@@ -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<
index 7e64fc4d8adf9ce573b7eaaaee536555f587ae3a..8b7743316f9cd734d8690a80416367bc72deae11 100644 (file)
@@ -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.
index 5bdebf93b36ddf0dc82187d0f887012d18fd6d57..486ffbeb9c958a58183c1e95a141fe0896a30c7a 100644 (file)
@@ -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!");
   }