diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index fb23ff6647eaf..6dc5ca20cbb99 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -64,7 +64,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 3a24b234263ab..5a9b118bf86bc 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -948,6 +948,9 @@ ASTContext::getFeatureAvailInfo(Decl *D) const { case 2: Kind = FeatureAvailKind::Dynamic; break; + case 3: + Kind = FeatureAvailKind::AlwaysAvailable; + break; default: llvm_unreachable("invalid feature kind"); } @@ -990,10 +993,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 d89b9ef6548b9..bb62373f3f86f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11995,6 +11995,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 7ce82e8b0cd5e..c493f02a98eed 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 __attribute__((availability(domain:feature1, AVAIL))) void func12(void); @@ -31,6 +32,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) { @@ -237,3 +240,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