[PATCH] D39665: Support __has_c_attribute

Aaron Ballman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sun Nov 5 13:57:10 PST 2017


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 &Tok, bool &HasLexedNextToken) -> 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 &Tok, bool &HasLexedNextToken) -> 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;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D39665.121662.patch
Type: text/x-patch
Size: 4511 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20171105/e7eccd7b/attachment-0001.bin>


More information about the cfe-commits mailing list