Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -110,6 +110,10 @@ 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: 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"); @@ -1593,6 +1598,57 @@ 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 @@ .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 @@ 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!"); }