arphaman created this revision.

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.


Repository:
  rC Clang

https://reviews.llvm.org/D41087

Files:
  include/clang/Lex/Preprocessor.h
  lib/Lex/PPMacroExpansion.cpp
  test/Preprocessor/is_target.c
  test/Preprocessor/is_target_os_darwin.c
  test/Preprocessor/is_target_unknown.c

Index: test/Preprocessor/is_target_unknown.c
===================================================================
--- /dev/null
+++ test/Preprocessor/is_target_unknown.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -triple i686-unknown-unknown -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple i686-- -verify %s
+// expected-no-diagnostics
+
+#if __is_target_arch(unknown)
+  #error "invalid arch"
+#endif
+
+// Unknown vendor is allowed.
+#if !__is_target_vendor(unknown)
+  #error "invalid vendor"
+#endif
+
+// Unknown OS is allowed.
+#if !__is_target_os(unknown)
+  #error "invalid OS"
+#endif
+
+// Unknown environment is allowed.
+#if !__is_target_environment(unknown)
+  #error "invalid environment"
+#endif
Index: test/Preprocessor/is_target_os_darwin.c
===================================================================
--- /dev/null
+++ test/Preprocessor/is_target_os_darwin.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-macos -DMAC -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-ios -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-tvos -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-watchos -verify %s
+// expected-no-diagnostics
+
+#if !__is_target_os(darwin)
+  #error "invalid os"
+#endif
+
+// macOS matches both macOS and macOSX.
+#ifdef MAC
+
+#if !__is_target_os(macos)
+  #error "invalid os"
+#endif
+
+#if !__is_target_os(macosx)
+  #error "invalid os"
+#endif
+
+#if __is_target_os(ios)
+  #error "invalid os"
+#endif
+
+#endif
Index: test/Preprocessor/is_target.c
===================================================================
--- /dev/null
+++ test/Preprocessor/is_target.c
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin-simulator -verify %s
+
+#if !__is_target_arch(x86_64) || !__is_target_arch(X86_64)
+  #error "invalid arch"
+#endif
+
+#if __is_target_arch(arm64)
+  #error "invalid arch"
+#endif
+
+// Silently ignore invalid archs. This will ensure that older compilers will
+// accept headers that support new arches/vendors/os variants.
+#if __is_target_arch(foo)
+  #error "invalid arch"
+#endif
+
+#if !__is_target_vendor(apple) || !__is_target_vendor(APPLE)
+  #error "invalid vendor"
+#endif
+
+#if __is_target_vendor(unknown)
+  #error "invalid vendor"
+#endif
+
+#if __is_target_vendor(foo)
+  #error "invalid vendor"
+#endif
+
+#if !__is_target_os(darwin) || !__is_target_os(DARWIN)
+  #error "invalid os"
+#endif
+
+#if __is_target_os(ios)
+  #error "invalid os"
+#endif
+
+#if __is_target_os(foo)
+  #error "invalid os"
+#endif
+
+#if !__is_target_environment(simulator) || !__is_target_environment(SIMULATOR)
+  #error "invalid environment"
+#endif
+
+#if __is_target_environment(unknown)
+  #error "invalid environment"
+#endif
+
+#if __is_target_environment(foo)
+  #error "invalid environment"
+#endif
+
+#if !__has_builtin(__is_target_arch) || !__has_builtin(__is_target_os) || !__has_builtin(__is_target_vendor) || !__has_builtin(__is_target_environment)
+  #error "has feature doesn't work"
+#endif
+
+#if __is_target_arch(11) // expected-error {{builtin feature check macro requires a parenthesized identifier}}
+  #error "invalid arch"
+#endif
+
+#if __is_target_arch x86 // expected-error{{missing '(' after '__is_target_arch'}}
+  #error "invalid arch"
+#endif
+
+#if __is_target_arch ( x86  // expected-error {{unterminated function-like macro invocation}}
+  #error "invalid arch"
+#endif // expected-error@-2 {{expected value in expression}}
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -375,6 +375,11 @@
   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");
@@ -1755,6 +1760,10 @@
                       .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 +1915,53 @@
       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 ? getTargetInfo().getTriple().getArchName().equals_lower(
+                          II->getName())
+                    : 0;
+        });
+  } 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);
+          StringRef VendorName = getTargetInfo().getTriple().getVendorName();
+          if (VendorName.empty())
+            VendorName = "unknown";
+          return II ? VendorName.equals_lower(II->getName()) : 0;
+        });
+  } 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);
+          if (!II)
+            return 0;
+          std::string OSName =
+              (llvm::Twine("unknown-unknown-") + II->getName().lower()).str();
+          llvm::Triple OS(OSName);
+          switch (OS.getOS()) {
+          case llvm::Triple::Darwin:
+            // Darwin matches macos, ios, etc.
+            return getTargetInfo().getTriple().isOSDarwin();
+          default:
+            return getTargetInfo().getTriple().getOS() == OS.getOS();
+          }
+        });
+  } 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);
+          StringRef EnvName = getTargetInfo().getTriple().getEnvironmentName();
+          if (EnvName.empty())
+            EnvName = "unknown";
+          return II ? EnvName.equals_lower(II->getName()) : 0;
+        });
   } else {
     llvm_unreachable("Unknown identifier!");
   }
Index: include/clang/Lex/Preprocessor.h
===================================================================
--- include/clang/Lex/Preprocessor.h
+++ include/clang/Lex/Preprocessor.h
@@ -175,6 +175,10 @@
   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;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to