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; 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: 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: 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_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