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).

llvm-svn: 73289
This commit is contained in:
Chris Lattner 2009-06-13 07:13:28 +00:00
parent a5d5c749b1
commit b6f77af532
5 changed files with 194 additions and 18 deletions

View File

@ -19,6 +19,7 @@ td {
<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,11 +46,72 @@ td {
<!-- ======================================================================= -->
<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 @@ more information on these extensions.</p>
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 @@ href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI
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 @@ caveats to this use of name mangling:</p>
C.</li>
</ul>
<p>Query for this feature with __has_feature(attribute_overloadable).</p>
<!-- ======================================================================= -->
<h2 id="builtins">Builtin Functions</h2>
<!-- ======================================================================= -->
@ -320,7 +390,10 @@ placed at the end of function prototypes:</p>
<pre>
void foo() <b>__attribute__((analyzer_noreturn))</b>;
</p>
</pre>
<p>Query for this feature with __has_feature(attribute_analyzer_noreturn).</p>
</div>
</body>

View File

@ -205,6 +205,10 @@ def err_pp_expr_bad_token_start_expr : Error<
"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<

View File

@ -69,6 +69,8 @@ class Preprocessor {
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 @@ private: // Cached tokens state.
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 @@ private:
/// 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

View File

@ -36,14 +36,14 @@ void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {
/// 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 @@ IdentifierInfo *Preprocessor::RegisterBuiltinMacro(const char *Name) {
/// 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 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
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 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
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!");
}

View File

@ -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