[llvm-branch-commits] [cfe-branch] r73496 - in /cfe/branches/Apple/Dib: docs/LanguageExtensions.html include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/Preprocessor.h lib/Lex/PPMacroExpansion.cpp test/Preprocessor/feature_tests.c

Daniel Dunbar daniel at zuster.org
Tue Jun 16 09:28:39 PDT 2009


Author: ddunbar
Date: Tue Jun 16 11:28:39 2009
New Revision: 73496

URL: http://llvm.org/viewvc/llvm-project?rev=73496&view=rev
Log:
Merge in 73289 (<rdar://problem/6954018>):

------------------------------------------------------------------------
r73289 | lattner | 2009-06-13 00:13:28 -0700 (Sat, 13 Jun 2009) | 7 lines

implement and document a new __has_feature and __has_builtin magic 
builtin preprocessor macro.  This appears to work with two caveats:
1) builtins are registered in -E mode, and 2) target-specific builtins
are unconditionally registered even if they aren't supported by the
target (e.g. SSE4 builtin when only SSE1 is enabled).


------------------------------------------------------------------------

Added:
    cfe/branches/Apple/Dib/test/Preprocessor/feature_tests.c
Modified:
    cfe/branches/Apple/Dib/docs/LanguageExtensions.html
    cfe/branches/Apple/Dib/include/clang/Basic/DiagnosticLexKinds.td
    cfe/branches/Apple/Dib/include/clang/Lex/Preprocessor.h
    cfe/branches/Apple/Dib/lib/Lex/PPMacroExpansion.cpp

Modified: cfe/branches/Apple/Dib/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/docs/LanguageExtensions.html?rev=73496&r1=73495&r2=73496&view=diff

==============================================================================
--- cfe/branches/Apple/Dib/docs/LanguageExtensions.html (original)
+++ cfe/branches/Apple/Dib/docs/LanguageExtensions.html Tue Jun 16 11:28:39 2009
@@ -19,6 +19,7 @@
 
 <ul>
 <li><a href="#intro">Introduction</a></li>
+<li><a href="#feature_check">Feature Checking Macros</a></li>
 <li><a href="#builtinmacros">Builtin Macros</a></li>
 <li><a href="#vectors">Vectors and Extended Vectors</a></li>
 <li><a href="#blocks">Blocks</a></li>
@@ -45,12 +46,73 @@
 <!-- ======================================================================= -->
 
 <p>This document describes the language extensions provided by Clang.  In
-addition to the langauge extensions listed here, Clang aims to support a broad
+addition to the language extensions listed here, Clang aims to support a broad
 range of GCC extensions.  Please see the <a 
 href="http://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html">GCC manual</a> for
 more information on these extensions.</p>
 
 <!-- ======================================================================= -->
+<h2 id="feature_check">Feature Checking Macros</h2>
+<!-- ======================================================================= -->
+
+<p>Language extensions can be very useful, but only if you know you can depend
+on them.  In order to allow fine-grain features checks, we support two builtin
+function-like macros.  This allows you to directly test for a feature in your
+code without having to resort to something like autoconf or fragile "compiler
+version checks".</p>
+
+<!-- ======================================================================= -->
+<h3 id="__has_builtin">__has_builtin</h3>
+<!-- ======================================================================= -->
+
+<p>This function-like macro takes a single identifier argument that is the name
+of a builtin function.  It evaluates to 1 if the builtin is supported or 0 if
+not.  It can be used like this:</p>
+
+<blockquote>
+<pre>
+#ifndef __has_builtin         // Optional of course.
+  #define __has_builtin(x) 0  // Compatibility with non-clang compilers.
+#endif
+
+...
+#if __has_builtin(__builtin_trap)
+  __builtin_trap();
+#else
+  abort();
+#endif
+...
+</pre>
+</blockquote>
+
+
+<!-- ======================================================================= -->
+<h3 id="__has_feature">__has_feature</h3>
+<!-- ======================================================================= -->
+
+<p>This function-like macro takes a single identifier argument that is the name
+of a feature.  It evaluates to 1 if the feature is supported or 0 if not.  It
+can be used like this:</p>
+
+<blockquote>
+<pre>
+#ifndef __has_feature         // Optional of course.
+  #define __has_feature(x) 0  // Compatibility with non-clang compilers.
+#endif
+
+...
+#if __has_feature(attribute_overloadable) || \
+    __has_feature(blocks)
+...
+#endif
+...
+</pre>
+</blockquote>
+
+<p>The feature tag is described along with the language feature below.</p>
+
+
+<!-- ======================================================================= -->
 <h2 id="builtinmacros">Builtin Macros</h2>
 <!-- ======================================================================= -->
 
@@ -64,6 +126,8 @@
 with V.xyzw syntax and other tidbits.  See also <a 
 href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
 
+<p>Query for this feature with __has_feature(attribute_ext_vector_type).</p>
+
 <!-- ======================================================================= -->
 <h2 id="blocks">Blocks</h2>
 <!-- ======================================================================= -->
@@ -73,6 +137,9 @@
 details for the clang implementation are in <a 
 href="BlockImplementation.txt">BlockImplementation.txt</a>.</p>
 
+
+<p>Query for this feature with __has_feature(blocks).</p>
+
 <!-- ======================================================================= -->
 <h2 id="overloading-in-c">Function Overloading in C</h2>
 <!-- ======================================================================= -->
@@ -171,6 +238,9 @@
   C.</li>
 </ul>
 
+<p>Query for this feature with __has_feature(attribute_overloadable).</p>
+
+
 <!-- ======================================================================= -->
 <h2 id="builtins">Builtin Functions</h2>
 <!-- ======================================================================= -->
@@ -319,7 +389,10 @@
 
 <pre>
   void foo() <b>__attribute__((analyzer_noreturn))</b>;
-</p>
+</pre>
+
+<p>Query for this feature with __has_feature(attribute_analyzer_noreturn).</p>
+
 
 </div>
 </body>

Modified: cfe/branches/Apple/Dib/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/include/clang/Basic/DiagnosticLexKinds.td?rev=73496&r1=73495&r2=73496&view=diff

==============================================================================
--- cfe/branches/Apple/Dib/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/branches/Apple/Dib/include/clang/Basic/DiagnosticLexKinds.td Tue Jun 16 11:28:39 2009
@@ -205,6 +205,10 @@
   "invalid token at start of a preprocessor expression">;
 def err_pp_invalid_poison : Error<"can only poison identifier tokens">;
 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__Pragma_malformed : Error<
   "_Pragma takes a parenthesized string literal">;
 def err_pragma_comment_malformed : Error<

Modified: cfe/branches/Apple/Dib/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/include/clang/Lex/Preprocessor.h?rev=73496&r1=73495&r2=73496&view=diff

==============================================================================
--- cfe/branches/Apple/Dib/include/clang/Lex/Preprocessor.h (original)
+++ cfe/branches/Apple/Dib/include/clang/Lex/Preprocessor.h Tue Jun 16 11:28:39 2009
@@ -69,6 +69,8 @@
   IdentifierInfo *Ident__TIMESTAMP__;              // __TIMESTAMP__
   IdentifierInfo *Ident__COUNTER__;                // __COUNTER__
   IdentifierInfo *Ident_Pragma, *Ident__VA_ARGS__; // _Pragma, __VA_ARGS__
+  IdentifierInfo *Ident__has_feature;              // __has_feature
+  IdentifierInfo *Ident__has_builtin;              // __has_builtin
   
   SourceLocation DATELoc, TIMELoc;
   unsigned CounterValue;  // Next __COUNTER__ value.
@@ -194,14 +196,13 @@
 public:
   Preprocessor(Diagnostic &diags, const LangOptions &opts, TargetInfo &target,
                SourceManager &SM, HeaderSearch &Headers,
-               IdentifierInfoLookup* IILookup = 0);
+               IdentifierInfoLookup *IILookup = 0);
 
   ~Preprocessor();
 
   Diagnostic &getDiagnostics() const { return *Diags; }
   void setDiagnostics(Diagnostic &D) { Diags = &D; }
 
-  
   const LangOptions &getLangOptions() const { return Features; }
   TargetInfo &getTargetInfo() const { return Target; }
   FileManager &getFileManager() const { return FileMgr; }
@@ -667,7 +668,6 @@
   /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the
   /// identifier table.
   void RegisterBuiltinMacros();
-  IdentifierInfo *RegisterBuiltinMacro(const char *Name);
   
   /// HandleMacroExpandedIdentifier - If an identifier token is read that is to
   /// be expanded as a macro, handle it and return the next token as 'Tok'.  If

Modified: cfe/branches/Apple/Dib/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/lib/Lex/PPMacroExpansion.cpp?rev=73496&r1=73495&r2=73496&view=diff

==============================================================================
--- cfe/branches/Apple/Dib/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/branches/Apple/Dib/lib/Lex/PPMacroExpansion.cpp Tue Jun 16 11:28:39 2009
@@ -36,14 +36,14 @@
 
 /// RegisterBuiltinMacro - Register the specified identifier in the identifier
 /// table and mark it as a builtin macro to be expanded.
-IdentifierInfo *Preprocessor::RegisterBuiltinMacro(const char *Name) {
+static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){
   // Get the identifier.
-  IdentifierInfo *Id = getIdentifierInfo(Name);
+  IdentifierInfo *Id = PP.getIdentifierInfo(Name);
   
   // Mark it as being a macro that is builtin.
-  MacroInfo *MI = AllocateMacroInfo(SourceLocation());
+  MacroInfo *MI = PP.AllocateMacroInfo(SourceLocation());
   MI->setIsBuiltinMacro();
-  setMacroInfo(Id, MI);
+  PP.setMacroInfo(Id, MI);
   return Id;
 }
 
@@ -51,17 +51,21 @@
 /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the
 /// identifier table.
 void Preprocessor::RegisterBuiltinMacros() {
-  Ident__LINE__ = RegisterBuiltinMacro("__LINE__");
-  Ident__FILE__ = RegisterBuiltinMacro("__FILE__");
-  Ident__DATE__ = RegisterBuiltinMacro("__DATE__");
-  Ident__TIME__ = RegisterBuiltinMacro("__TIME__");
-  Ident__COUNTER__ = RegisterBuiltinMacro("__COUNTER__");
-  Ident_Pragma  = RegisterBuiltinMacro("_Pragma");
+  Ident__LINE__ = RegisterBuiltinMacro(*this, "__LINE__");
+  Ident__FILE__ = RegisterBuiltinMacro(*this, "__FILE__");
+  Ident__DATE__ = RegisterBuiltinMacro(*this, "__DATE__");
+  Ident__TIME__ = RegisterBuiltinMacro(*this, "__TIME__");
+  Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__");
+  Ident_Pragma  = RegisterBuiltinMacro(*this, "_Pragma");
   
   // GCC Extensions.
-  Ident__BASE_FILE__     = RegisterBuiltinMacro("__BASE_FILE__");
-  Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro("__INCLUDE_LEVEL__");
-  Ident__TIMESTAMP__     = RegisterBuiltinMacro("__TIMESTAMP__");
+  Ident__BASE_FILE__     = RegisterBuiltinMacro(*this, "__BASE_FILE__");
+  Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__");
+  Ident__TIMESTAMP__     = RegisterBuiltinMacro(*this, "__TIMESTAMP__");
+  
+  // Clang Extensions.
+  Ident__has_feature     = RegisterBuiltinMacro(*this, "__has_feature");
+  Ident__has_builtin     = RegisterBuiltinMacro(*this, "__has_builtin");
 }
 
 /// isTrivialSingleTokenExpansion - Return true if MI, which has a single token
@@ -468,6 +472,34 @@
   TIMELoc = TmpTok.getLocation();
 }
 
+
+/// HasFeature - Return true if we recognize and implement the specified feature
+/// specified by the identifier.
+static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
+  const LangOptions &LangOpts = PP.getLangOptions();
+  
+  switch (II->getLength()) {
+  default: return false;
+  case 6:
+    if (II->isStr("blocks")) return LangOpts.Blocks;
+    return false;
+  case 22:
+    if (II->isStr("attribute_overloadable")) return true;
+    return false;
+  case 25:
+    if (II->isStr("attribute_ext_vector_type")) return true;
+    return false;
+  case 27:
+    if (II->isStr("attribute_analyzer_noreturn")) return true;
+    return false;
+  case 29:
+    if (II->isStr("attribute_ns_returns_retained")) return true;
+    if (II->isStr("attribute_cf_returns_retained")) return true;
+    return false;
+  }
+}
+
+
 /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
 /// as a builtin macro, handle it and return the next token as 'Tok'.
 void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
@@ -598,6 +630,43 @@
     sprintf(TmpBuffer, "%u", CounterValue++);
     Tok.setKind(tok::numeric_constant);
     CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
+  } else if (II == Ident__has_feature ||
+             II == Ident__has_builtin) {
+    // The argument to these two builtins should be a parenthesized identifier.
+    SourceLocation StartLoc = Tok.getLocation();
+    
+    bool IsValid = false;
+    IdentifierInfo *FeatureII = 0;
+    
+    // Read the '('.
+    Lex(Tok);
+    if (Tok.is(tok::l_paren)) {
+      // Read the identifier
+      Lex(Tok);
+      if (Tok.is(tok::identifier)) {
+        FeatureII = Tok.getIdentifierInfo();
+        
+        // Read the ')'.
+        Lex(Tok);
+        if (Tok.is(tok::r_paren))
+          IsValid = true;
+      }
+    }
+    
+    bool Value = false;
+    if (!IsValid)
+      Diag(StartLoc, diag::err_feature_check_malformed);
+    else if (II == Ident__has_builtin) {
+      // Check for a builtin is trivial. 
+      Value = FeatureII->getBuiltinID() != 0;
+    } else {
+      assert(II == Ident__has_feature && "Must be feature check");
+      Value = HasFeature(*this, FeatureII);
+    }
+    
+    sprintf(TmpBuffer, "%d", (int)Value);
+    Tok.setKind(tok::numeric_constant);
+    CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
   } else {
     assert(0 && "Unknown identifier!");
   }

Added: cfe/branches/Apple/Dib/test/Preprocessor/feature_tests.c
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/test/Preprocessor/feature_tests.c?rev=73496&view=auto

==============================================================================
--- cfe/branches/Apple/Dib/test/Preprocessor/feature_tests.c (added)
+++ cfe/branches/Apple/Dib/test/Preprocessor/feature_tests.c Tue Jun 16 11:28:39 2009
@@ -0,0 +1,31 @@
+// RUN: clang-cc %s --triple=i686-apple-darwin9 &&
+// RUN: clang-cc %s -E --triple=i686-apple-darwin9
+#ifndef __has_feature
+#error Should have __has_feature
+#endif
+
+
+#if __has_feature(something_we_dont_have)
+#error Bad
+#endif
+
+#if  !__has_builtin(__builtin_huge_val) || \
+     !__has_builtin(__builtin_shufflevector) || \
+     !__has_builtin(__builtin_trap) || \
+     !__has_feature(attribute_analyzer_noreturn) || \
+     !__has_feature(attribute_overloadable)
+#error Clang should have these
+#endif
+
+#if __has_builtin(__builtin_insanity)
+#error Clang should not have this
+#endif
+
+
+
+// Make sure we have x86 builtins only (forced with target triple).
+
+#if !__has_builtin(__builtin_ia32_emms) || \
+    __has_builtin(__builtin_altivec_abs_v4sf)
+#error Broken handling of target-specific builtins
+#endif





More information about the llvm-branch-commits mailing list