diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -178,6 +178,8 @@ IdentifierInfo *Ident__is_target_vendor; // __is_target_vendor IdentifierInfo *Ident__is_target_os; // __is_target_os IdentifierInfo *Ident__is_target_environment; // __is_target_environment + IdentifierInfo *Ident__is_target_variant_os; + IdentifierInfo *Ident__is_target_variant_environment; IdentifierInfo *Ident__FLT_EVAL_METHOD__; // __FLT_EVAL_METHOD // Weak, only valid (and set) while InMacroArgs is true. diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -387,6 +387,10 @@ Ident__is_target_os = RegisterBuiltinMacro(*this, "__is_target_os"); Ident__is_target_environment = RegisterBuiltinMacro(*this, "__is_target_environment"); + Ident__is_target_variant_os = + RegisterBuiltinMacro(*this, "__is_target_variant_os"); + Ident__is_target_variant_environment = + RegisterBuiltinMacro(*this, "__is_target_variant_environment"); // Modules. Ident__building_module = RegisterBuiltinMacro(*this, "__building_module"); @@ -1431,6 +1435,39 @@ return TI.getTriple().getEnvironment() == Env.getEnvironment(); } +/// Implements the __is_target_variant_os builtin macro. +static bool isTargetVariantOS(const TargetInfo &TI, const IdentifierInfo *II) { + if (TI.getTriple().isOSDarwin()) { + const llvm::Triple *VariantTriple = TI.getDarwinTargetVariantTriple(); + if (!VariantTriple) + return false; + + 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 VariantTriple->isOSDarwin(); + } + return VariantTriple->getOS() == OS.getOS(); + } + return false; +} + +/// Implements the __is_target_variant_environment builtin macro. +static bool isTargetVariantEnvironment(const TargetInfo &TI, + const IdentifierInfo *II) { + if (TI.getTriple().isOSDarwin()) { + const llvm::Triple *VariantTriple = TI.getDarwinTargetVariantTriple(); + if (!VariantTriple) + return false; + std::string EnvName = (llvm::Twine("---") + II->getName().lower()).str(); + llvm::Triple Env(EnvName); + return VariantTriple->getEnvironment() == Env.getEnvironment(); + } + return false; +} + /// 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) { @@ -1678,6 +1715,8 @@ .Case("__is_target_vendor", true) .Case("__is_target_os", true) .Case("__is_target_environment", true) + .Case("__is_target_variant_os", true) + .Case("__is_target_variant_environment", true) .Default(false); } }); @@ -1878,6 +1917,22 @@ Tok, *this, diag::err_feature_check_malformed); return II && isTargetEnvironment(getTargetInfo(), II); }); + } else if (II == Ident__is_target_variant_os) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetVariantOS(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_variant_environment) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetVariantEnvironment(getTargetInfo(), II); + }); } else { llvm_unreachable("Unknown identifier!"); } diff --git a/clang/test/Preprocessor/is_target_unknown.c b/clang/test/Preprocessor/is_target_unknown.c --- a/clang/test/Preprocessor/is_target_unknown.c +++ b/clang/test/Preprocessor/is_target_unknown.c @@ -20,3 +20,13 @@ #if !__is_target_environment(unknown) #error "mismatching environment" #endif + +// Unknown variant OS is not allowed. +#if __is_target_variant_os(unknown) + #error "mismatching OS" +#endif + +// Unknown variant environment is not allowed. +#if __is_target_variant_environment(unknown) + #error "mismatching environment" +#endif diff --git a/clang/test/Preprocessor/is_target_variant.c b/clang/test/Preprocessor/is_target_variant.c new file mode 100644 --- /dev/null +++ b/clang/test/Preprocessor/is_target_variant.c @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-macos -DMAC -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-ios13.1 -DIOS -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-ios13.1-macabi -DCATALYST -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-macos12 -darwin-target-variant-triple arm64-apple-ios-macabi -DZIPPERED -verify %s +// expected-no-diagnostics + +#if !__has_builtin(__is_target_variant_os) || !__has_builtin(__is_target_variant_environment) + #error "has builtin doesn't work" +#endif + +#ifdef ZIPPERED + + // Target variant is a darwin. + #if !__is_target_variant_os(darwin) + #error "mismatching variant os" + #endif + + // Target variant is not macOS... + #if __is_target_variant_os(macos) + #error "mismatching variant os" + #endif + + // ...but iOS. + #if !__is_target_variant_os(ios) + #error "mismatching variant os" + #endif + + // Zippered builds also set the target variant environment to macabi. + // At the moment, only zippered builds set __is_target_variant_os(ios), + // so checking __is_target_variant_environment() is currently redundant + // with checking the former. + #if !__is_target_variant_environment(macabi) + #error "mismatching variant environment" + #endif + +#else + + // In non-zippered builds, even for catalyst, no target variant is set. + // So these are all false. + + #if __is_target_variant_os(darwin) + #error "mismatching variant os" + #endif + + #if __is_target_variant_os(macos) + #error "mismatching variant os" + #endif + + #if __is_target_variant_os(ios) + #error "mismatching variant os" + #endif + + #if __is_target_variant_environment(macabi) + #error "mismatching variant environment" + #endif + +#endif + +// The target environment in zippered builds is _not_ macabi. +// The target environment is macabi only in catalyst builds. +#ifdef CATALYST + #if !__is_target_environment(macabi) + #error "mismatching environment" + #endif + #if !__is_target_os(ios) + #error "mismatching os" + #endif +#else + #if __is_target_environment(macabi) + #error "mismatching environment" + #endif +#endif