]> granicus.if.org Git - clang/commitdiff
[Preprocessor] Implement __is_target_{arch|vendor|os|environment} function-like
authorAlex Lorenz <arphaman@gmail.com>
Thu, 14 Dec 2017 19:22:02 +0000 (19:22 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 14 Dec 2017 19:22:02 +0000 (19:22 +0000)
builtin macros

This patch implements the __is_target_arch, __is_target_vendor, __is_target_os,
and __is_target_environment Clang preprocessor extensions that were proposed by
@compnerd in Bob's cfe-dev post:
http://lists.llvm.org/pipermail/cfe-dev/2017-November/056166.html.

These macros can be used to examine the components of the target triple at
compile time. A has_builtin(is_target_???) preprocessor check can be used to
check for their availability.

__is_target_arch allows you to check if an arch is specified without worring
about a specific subarch, e.g.

__is_target_arch(arm) returns 1 for the target arch "armv7"
__is_target_arch(armv7) returns 1 for the target arch "armv7"
__is_target_arch(armv6) returns 0 for the target arch "armv7"

__is_target_vendor and __is_target_environment match the specific vendor
or environment. __is_target_os matches the specific OS, but
__is_target_os(darwin) will match any Darwin-based OS. "Unknown" can be used
to test if the triple's component is specified.

rdar://35753116

Differential Revision: https://reviews.llvm.org/D41087

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@320734 91177308-0d34-0410-b5e6-96231b3b80d8

docs/ReleaseNotes.rst
include/clang/Lex/Preprocessor.h
lib/Lex/PPMacroExpansion.cpp

index 2ff984d7c4c7a2b83654f6654c9276a8710cf13d..2ec1431a831c4d4725c6ecfd76ffb8c4acd43316 100644 (file)
@@ -110,6 +110,10 @@ Non-comprehensive list of changes in this release
   If a gcc installation is found, it still prefers ``.ctors`` if the found
   gcc is older than 4.7.0.
 
+- The new builtin preprocessor macros ``__is_target_arch``,
+  ``__is_target_vendor``, ``__is_target_os``, and ``__is_target_environment``
+  can be used to to examine the individual components of the target triple.
+
 New Compiler Flags
 ------------------
 
index 548c7e3551f9c6a5d9d44e244edcfc44e5732800..485600f122329ec40c6d563009e9e5e5678a8398 100644 (file)
@@ -175,6 +175,10 @@ class Preprocessor {
   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__is_target_arch;           // __is_target_arch
+  IdentifierInfo *Ident__is_target_vendor;         // __is_target_vendor
+  IdentifierInfo *Ident__is_target_os;             // __is_target_os
+  IdentifierInfo *Ident__is_target_environment;    // __is_target_environment
 
   SourceLocation DATELoc, TIMELoc;
 
index 2d83badfee90a61156944aa63953e2b813e46ca7..3d72006bad4e1e2979fc89d9d4f76ee67cf976de 100644 (file)
@@ -375,6 +375,11 @@ void Preprocessor::RegisterBuiltinMacros() {
   Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
   Ident__has_warning      = RegisterBuiltinMacro(*this, "__has_warning");
   Ident__is_identifier    = RegisterBuiltinMacro(*this, "__is_identifier");
+  Ident__is_target_arch   = RegisterBuiltinMacro(*this, "__is_target_arch");
+  Ident__is_target_vendor = RegisterBuiltinMacro(*this, "__is_target_vendor");
+  Ident__is_target_os     = RegisterBuiltinMacro(*this, "__is_target_os");
+  Ident__is_target_environment =
+      RegisterBuiltinMacro(*this, "__is_target_environment");
 
   // Modules.
   Ident__building_module  = RegisterBuiltinMacro(*this, "__building_module");
@@ -1593,6 +1598,57 @@ static IdentifierInfo *ExpectFeatureIdentifierInfo(Token &Tok,
   return nullptr;
 }
 
+/// Implements the __is_target_arch builtin macro.
+static bool isTargetArch(const TargetInfo &TI, const IdentifierInfo *II) {
+  std::string ArchName = II->getName().lower() + "--";
+  llvm::Triple Arch(ArchName);
+  const llvm::Triple &TT = TI.getTriple();
+  if (TT.isThumb()) {
+    // arm matches thumb or thumbv7. armv7 matches thumbv7.
+    if ((Arch.getSubArch() == llvm::Triple::NoSubArch ||
+         Arch.getSubArch() == TT.getSubArch()) &&
+        ((TT.getArch() == llvm::Triple::thumb &&
+          Arch.getArch() == llvm::Triple::arm) ||
+         (TT.getArch() == llvm::Triple::thumbeb &&
+          Arch.getArch() == llvm::Triple::armeb)))
+      return true;
+  }
+  // Check the parsed arch when it has no sub arch to allow Clang to
+  // match thumb to thumbv7 but to prohibit matching thumbv6 to thumbv7.
+  return (Arch.getSubArch() == llvm::Triple::NoSubArch &&
+          Arch.getArch() == TT.getArch()) ||
+         Arch.getArchName() == TT.getArchName();
+}
+
+/// Implements the __is_target_vendor builtin macro.
+static bool isTargetVendor(const TargetInfo &TI, const IdentifierInfo *II) {
+  StringRef VendorName = TI.getTriple().getVendorName();
+  if (VendorName.empty())
+    VendorName = "unknown";
+  return VendorName.equals_lower(II->getName());
+}
+
+/// Implements the __is_target_os builtin macro.
+static bool isTargetOS(const TargetInfo &TI, const IdentifierInfo *II) {
+  std::string OSName =
+      (llvm::Twine("unknown-unknown-") + II->getName().lower()).str();
+  llvm::Triple OS(OSName);
+  if (OS.getOS() == llvm::Triple::Darwin) {
+    // Darwin matches macos, ios, etc.
+    return TI.getTriple().isOSDarwin();
+  }
+  return TI.getTriple().getOS() == OS.getOS();
+}
+
+/// Implements the __is_target_environment builtin macro.
+static bool isTargetEnvironment(const TargetInfo &TI,
+                                const IdentifierInfo *II) {
+  StringRef EnvName = TI.getTriple().getEnvironmentName();
+  if (EnvName.empty())
+    EnvName = "unknown";
+  return EnvName.equals_lower(II->getName());
+}
+
 /// 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) {
@@ -1755,6 +1811,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
                       .Case("__make_integer_seq", LangOpts.CPlusPlus)
                       .Case("__type_pack_element", LangOpts.CPlusPlus)
                       .Case("__builtin_available", true)
+                      .Case("__is_target_arch", true)
+                      .Case("__is_target_vendor", true)
+                      .Case("__is_target_os", true)
+                      .Case("__is_target_environment", true)
                       .Default(false);
         }
       });
@@ -1906,6 +1966,34 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
       Diag(LParenLoc, diag::note_matching) << tok::l_paren;
     }
     return;
+  } else if (II == Ident__is_target_arch) {
+    EvaluateFeatureLikeBuiltinMacro(
+        OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int {
+          IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+              Tok, *this, diag::err_feature_check_malformed);
+          return II && isTargetArch(getTargetInfo(), II);
+        });
+  } else if (II == Ident__is_target_vendor) {
+    EvaluateFeatureLikeBuiltinMacro(
+        OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int {
+          IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+              Tok, *this, diag::err_feature_check_malformed);
+          return II && isTargetVendor(getTargetInfo(), II);
+        });
+  } else if (II == Ident__is_target_os) {
+    EvaluateFeatureLikeBuiltinMacro(
+        OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int {
+          IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+              Tok, *this, diag::err_feature_check_malformed);
+          return II && isTargetOS(getTargetInfo(), II);
+        });
+  } else if (II == Ident__is_target_environment) {
+    EvaluateFeatureLikeBuiltinMacro(
+        OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int {
+          IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+              Tok, *this, diag::err_feature_check_malformed);
+          return II && isTargetEnvironment(getTargetInfo(), II);
+        });
   } else {
     llvm_unreachable("Unknown identifier!");
   }