[cfe-commits] r73289 - in /cfe/trunk: docs/LanguageExtensions.html include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/Preprocessor.h lib/Lex/PPMacroExpansion.cpp test/Preprocessor/feature_tests.c
Chris Lattner
sabre at nondot.org
Sat Jun 13 00:13:28 PDT 2009
Author: lattner
Date: Sat Jun 13 02:13:28 2009
New Revision: 73289
URL: http://llvm.org/viewvc/llvm-project?rev=73289&view=rev
Log:
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/trunk/test/Preprocessor/feature_tests.c
Modified:
cfe/trunk/docs/LanguageExtensions.html
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=73289&r1=73288&r2=73289&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Sat Jun 13 02:13:28 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>
<!-- ======================================================================= -->
@@ -320,7 +390,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/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=73289&r1=73288&r2=73289&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Sat Jun 13 02:13:28 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/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=73289&r1=73288&r2=73289&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Sat Jun 13 02:13:28 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/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=73289&r1=73288&r2=73289&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Sat Jun 13 02:13:28 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
@@ -469,6 +473,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) {
@@ -599,6 +631,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/trunk/test/Preprocessor/feature_tests.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/feature_tests.c?rev=73289&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/feature_tests.c (added)
+++ cfe/trunk/test/Preprocessor/feature_tests.c Sat Jun 13 02:13:28 2009
@@ -0,0 +1,30 @@
+// RUN: clang-cc %s --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 cfe-commits
mailing list