From 1afc96bfc824374f443ed623e942a423f7f151cc Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Tue, 9 Sep 2025 18:22:06 -0700 Subject: [PATCH] Introduce FeatureAvailKind::AlwaysAvailable. Represent availability domains that are always available regardless of context by introducing a new `FeatureAvailKind`. The Sema support for these domains will added later; this change is designed to unblock Swift's implementation of support for always available domains. Resolves rdar://160244138. --- clang/include/clang/Basic/LangOptions.h | 8 +++++++- clang/lib/AST/ASTContext.cpp | 21 +++++++++++++++++---- clang/lib/AST/ExprConstant.cpp | 1 + clang/lib/Headers/availability_domain.h | 10 ++++------ clang/test/Sema/feature-availability.c | 19 +++++++++++++++++++ 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 45146416d8ad5..b6637789b7944 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -66,7 +66,13 @@ enum class PointerAuthenticationMode : unsigned { SignAndAuth }; -enum class FeatureAvailKind { None, Available, Unavailable, Dynamic }; +enum class FeatureAvailKind { + None, + Available, + Unavailable, + Dynamic, + AlwaysAvailable, +}; /// Bitfields of LangOptions, split out from LangOptions in order to ensure that /// this large collection of bitfields is a trivial class type. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 5d16cac52b2b8..970172d879348 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1011,6 +1011,9 @@ ASTContext::getFeatureAvailInfo(Decl *D) const { case 2: Kind = FeatureAvailKind::Dynamic; break; + case 3: + Kind = FeatureAvailKind::AlwaysAvailable; + break; default: llvm_unreachable("invalid feature kind"); } @@ -1053,10 +1056,20 @@ bool ASTContext::hasUnavailableFeature(const Decl *D) const { for (auto *AA : D->specific_attrs()) { auto FeatureName = AA->getDomain(); auto FeatureInfo = getFeatureAvailInfo(FeatureName); - if (FeatureInfo.Kind == (AA->getUnavailable() - ? FeatureAvailKind::Available - : FeatureAvailKind::Unavailable)) - return true; + switch (FeatureInfo.Kind) { + case FeatureAvailKind::Available: + case FeatureAvailKind::AlwaysAvailable: + if (AA->getUnavailable()) + return true; + break; + case FeatureAvailKind::Unavailable: + if (!AA->getUnavailable()) + return true; + break; + case FeatureAvailKind::Dynamic: + case FeatureAvailKind::None: + break; + } } return false; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 499524129153f..45866c0f88fce 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12881,6 +12881,7 @@ class IntExprEvaluator switch (FeatureInfo.Kind) { case FeatureAvailKind::Available: + case FeatureAvailKind::AlwaysAvailable: ResultInt = 1; break; case FeatureAvailKind::Unavailable: diff --git a/clang/lib/Headers/availability_domain.h b/clang/lib/Headers/availability_domain.h index ede75841e2b97..2806f58f97821 100644 --- a/clang/lib/Headers/availability_domain.h +++ b/clang/lib/Headers/availability_domain.h @@ -15,6 +15,7 @@ #define __AVAILABILITY_DOMAIN_ENABLED 0 #define __AVAILABILITY_DOMAIN_DISABLED 1 #define __AVAILABILITY_DOMAIN_DYNAMIC 2 +#define __AVAILABILITY_DOMAIN_ALWAYS_ENABLED 3 /// Describes the fields of a Clang availability domain. This struct is an /// implementation detail of the compiler and is subject to change so don't @@ -43,11 +44,8 @@ struct __AvailabilityDomain { availability_domain(domain))) = {__AVAILABILITY_DOMAIN_DISABLED, 0} #define CLANG_ALWAYS_ENABLED_AVAILABILITY_DOMAIN(domain) \ - static struct __AvailabilityDomain domain __attribute__(( \ - availability_domain(domain))) = {__AVAILABILITY_DOMAIN_ENABLED, 0} - -#define CLANG_ALWAYS_DISABLED_AVAILABILITY_DOMAIN(domain) \ - static struct __AvailabilityDomain domain __attribute__(( \ - availability_domain(domain))) = {__AVAILABILITY_DOMAIN_DISABLED, 0} + static struct __AvailabilityDomain domain \ + __attribute__((availability_domain(domain))) = { \ + __AVAILABILITY_DOMAIN_ALWAYS_ENABLED, 0} #endif /* __AVAILABILITY_DOMAIN_H */ diff --git a/clang/test/Sema/feature-availability.c b/clang/test/Sema/feature-availability.c index 173cb6a920677..6385795e80083 100644 --- a/clang/test/Sema/feature-availability.c +++ b/clang/test/Sema/feature-availability.c @@ -13,6 +13,7 @@ CLANG_ENABLED_AVAILABILITY_DOMAIN(feature1); CLANG_DISABLED_AVAILABILITY_DOMAIN(feature2); CLANG_ENABLED_AVAILABILITY_DOMAIN(feature3); CLANG_DYNAMIC_AVAILABILITY_DOMAIN(feature4, pred1); +CLANG_ALWAYS_ENABLED_AVAILABILITY_DOMAIN(feature5); #endif #pragma clang attribute push (__attribute__((availability(domain:feature1, AVAIL))), apply_to=any(function)) @@ -34,6 +35,8 @@ __attribute__((availability(domain:feature4, AVAIL))) void func10(void); __attribute__((availability(domain:feature4, UNAVAIL))) void func11(void); __attribute__((availability(domain:feature4, AVAIL))) int g4; __attribute__((availability(domain:feature4, UNAVAIL))) int g5; +__attribute__((availability(domain:feature5, AVAIL))) void func21(void); +__attribute__((availability(domain:feature5, UNAVAIL))) void func22(void); #endif void test_unreachable_code(void) { @@ -240,3 +243,19 @@ void test7(void) { e = EB; // expected-error {{use of 'EB' requires feature 'feature1' to be available}} } } + +#ifdef USE_DOMAIN +void test8(void) { + // FIXME: Use of 'func21()' should not be diagnosed because feature5 is always available. + func21(); // expected-error {{use of 'func21' requires feature 'feature5' to be available}} + func22(); // expected-error {{use of 'func22' requires feature 'feature5' to be unavailable}} + + if (__builtin_available(domain:feature5)) { + func21(); + func22(); // expected-error {{use of 'func22' requires feature 'feature5' to be unavailable}} + } else { + func21(); // expected-error {{use of 'func21' requires feature 'feature5' to be available}} + func22(); + } +} +#endif