forked from OSchip/llvm-project
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:
parent
a5d5c749b1
commit
b6f77af532
|
@ -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>
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue