Add support for the __has_c_attribute builtin preprocessor macro.

This behaves similar to the __has_cpp_attribute builtin macro in that it allows users to detect whether an attribute is supported with the [[]] spelling syntax, which can be enabled in C with -fdouble-square-bracket-attributes.

llvm-svn: 320088
This commit is contained in:
Aaron Ballman 2017-12-07 21:37:49 +00:00
parent 095d4ea4bf
commit 48f5f4d895
5 changed files with 1965 additions and 1913 deletions

View File

@ -139,6 +139,35 @@ and following ``__`` (double underscore) to avoid interference from a macro with
the same name. For instance, ``gnu::__const__`` can be used instead of the same name. For instance, ``gnu::__const__`` can be used instead of
``gnu::const``. ``gnu::const``.
``__has_c_attribute``
---------------------
This function-like macro takes a single argument that is the name of an
attribute exposed with the double square-bracket syntax in C mode. The argument
can either be a single identifier or a scoped identifier. If the attribute is
supported, a nonzero value is returned. If the attribute is not supported by the
current compilation target, this macro evaluates to 0. It can be used like this:
.. code-block:: c
#ifndef __has_c_attribute // Optional of course.
#define __has_c_attribute(x) 0 // Compatibility with non-clang compilers.
#endif
...
#if __has_c_attribute(fallthrough)
#define FALLTHROUGH [[fallthrough]]
#else
#define FALLTHROUGH
#endif
...
The attribute identifier (but not scope) can also be specified with a preceding
and following ``__`` (double underscore) to avoid interference from a macro with
the same name. For instance, ``gnu::__const__`` can be used instead of
``gnu::const``.
``__has_attribute`` ``__has_attribute``
------------------- -------------------

View File

@ -139,6 +139,11 @@ Clang now supports the ...
Attribute Changes in Clang Attribute Changes in Clang
-------------------------- --------------------------
- Added the ``__has_c_attribute()`` builtin preprocessor macro which allows
users to dynamically detect whether a double square-bracket attribute is
supported in C mode. This attribute syntax can be enabled with the
``-fdouble-square-bracket-attributes`` flag.
- The presence of __attribute__((availability(...))) on a declaration no longer - The presence of __attribute__((availability(...))) on a declaration no longer
implies default visibility for that declaration on macOS. implies default visibility for that declaration on macOS.

View File

@ -173,6 +173,7 @@ class Preprocessor {
IdentifierInfo *Ident__building_module; // __building_module IdentifierInfo *Ident__building_module; // __building_module
IdentifierInfo *Ident__MODULE__; // __MODULE__ IdentifierInfo *Ident__MODULE__; // __MODULE__
IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute
IdentifierInfo *Ident__has_c_attribute; // __has_c_attribute
IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute
SourceLocation DATELoc, TIMELoc; SourceLocation DATELoc, TIMELoc;

View File

@ -369,6 +369,7 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension"); Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute");
Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute");
Ident__has_declspec = RegisterBuiltinMacro(*this, "__has_declspec_attribute"); Ident__has_declspec = RegisterBuiltinMacro(*this, "__has_declspec_attribute");
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
@ -1775,12 +1776,14 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
return II ? hasAttribute(AttrSyntax::Declspec, nullptr, II, return II ? hasAttribute(AttrSyntax::Declspec, nullptr, II,
getTargetInfo(), getLangOpts()) : 0; getTargetInfo(), getLangOpts()) : 0;
}); });
} else if (II == Ident__has_cpp_attribute) { } else if (II == Ident__has_cpp_attribute ||
EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, II == Ident__has_c_attribute) {
[this](Token &Tok, bool &HasLexedNextToken) -> int { bool IsCXX = II == Ident__has_cpp_attribute;
EvaluateFeatureLikeBuiltinMacro(
OS, Tok, II, *this, [&](Token &Tok, bool &HasLexedNextToken) -> int {
IdentifierInfo *ScopeII = nullptr; IdentifierInfo *ScopeII = nullptr;
IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, IdentifierInfo *II = ExpectFeatureIdentifierInfo(
diag::err_feature_check_malformed); Tok, *this, diag::err_feature_check_malformed);
if (!II) if (!II)
return false; return false;
@ -1796,8 +1799,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
diag::err_feature_check_malformed); diag::err_feature_check_malformed);
} }
return II ? hasAttribute(AttrSyntax::CXX, ScopeII, II, AttrSyntax Syntax = IsCXX ? AttrSyntax::CXX : AttrSyntax::C;
getTargetInfo(), getLangOpts()) : 0; return II ? hasAttribute(Syntax, ScopeII, II, getTargetInfo(),
getLangOpts())
: 0;
}); });
} else if (II == Ident__has_include || } else if (II == Ident__has_include ||
II == Ident__has_include_next) { II == Ident__has_include_next) {

View File

@ -0,0 +1,12 @@
// RUN: %clang_cc1 -fdouble-square-bracket-attributes -std=c11 -E %s -o - | FileCheck %s
// CHECK: has_fallthrough
#if __has_c_attribute(fallthrough)
int has_fallthrough();
#endif
// CHECK: does_not_have_selectany
#if !__has_c_attribute(selectany)
int does_not_have_selectany();
#endif