aaron.ballman created this revision.
We have the __has_cpp_attribute builtin macro to determine when an attribute is
supported with C++ [[]] syntax, and this patch adds the analogous
__has_c_attribute builtin macro so that users can test whether a given [[]]
attribute is available in C when -fdouble-square-bracket-attributes is
specified.
https://reviews.llvm.org/D39665
Files:
clang/include/clang/Lex/Preprocessor.h
clang/lib/Lex/PPMacroExpansion.cpp
clang/test/Preprocessor/has_c_attribute.c
Index: clang/test/Preprocessor/has_c_attribute.c
===
--- clang/test/Preprocessor/has_c_attribute.c
+++ clang/test/Preprocessor/has_c_attribute.c
@@ -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
+
Index: clang/lib/Lex/PPMacroExpansion.cpp
===
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -369,6 +369,7 @@
Ident__has_extension= RegisterBuiltinMacro(*this, "__has_extension");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
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_include = RegisterBuiltinMacro(*this, "__has_include");
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
@@ -1775,30 +1776,34 @@
return II ? hasAttribute(AttrSyntax::Declspec, nullptr, II,
getTargetInfo(), getLangOpts()) : 0;
});
- } else if (II == Ident__has_cpp_attribute) {
-EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
- [this](Token , bool ) -> int {
-IdentifierInfo *ScopeII = nullptr;
-IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
- diag::err_feature_check_malformed);
-if (!II)
- return false;
+ } else if (II == Ident__has_cpp_attribute ||
+ II == Ident__has_c_attribute) {
+bool IsCXX = II == Ident__has_cpp_attribute;
+EvaluateFeatureLikeBuiltinMacro(
+OS, Tok, II, *this, [&](Token , bool ) -> int {
+ IdentifierInfo *ScopeII = nullptr;
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+ Tok, *this, diag::err_feature_check_malformed);
+ if (!II)
+return false;
-// It is possible to receive a scope token. Read the "::", if it is
-// available, and the subsequent identifier.
-LexUnexpandedToken(Tok);
-if (Tok.isNot(tok::coloncolon))
- HasLexedNextToken = true;
-else {
- ScopeII = II;
+ // It is possible to receive a scope token. Read the "::", if it is
+ // available, and the subsequent identifier.
LexUnexpandedToken(Tok);
- II = ExpectFeatureIdentifierInfo(Tok, *this,
- diag::err_feature_check_malformed);
-}
+ if (Tok.isNot(tok::coloncolon))
+HasLexedNextToken = true;
+ else {
+ScopeII = II;
+LexUnexpandedToken(Tok);
+II = ExpectFeatureIdentifierInfo(Tok, *this,
+
diag::err_feature_check_malformed);
+ }
-return II ? hasAttribute(AttrSyntax::CXX, ScopeII, II,
- getTargetInfo(), getLangOpts()) : 0;
- });
+ AttrSyntax Syntax = IsCXX ? AttrSyntax::CXX : AttrSyntax::C;
+ return II ? hasAttribute(Syntax, ScopeII, II, getTargetInfo(),
+ getLangOpts())
+: 0;
+});
} else if (II == Ident__has_include ||
II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
Index: clang/include/clang/Lex/Preprocessor.h
===
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -144,6 +144,7 @@
IdentifierInfo *Ident__building_module; // __building_module
IdentifierInfo *Ident__MODULE__; // __MODULE__
IdentifierInfo *Ident__has_cpp_attribute;// __has_cpp_attribute
+ IdentifierInfo *Ident__has_c_attribute; // __has_c_attribute
IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute
SourceLocation DATELoc, TIMELoc;
Index: clang/test/Preprocessor/has_c_attribute.c