Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
21 changes: 17 additions & 4 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down Expand Up @@ -1053,10 +1056,20 @@ bool ASTContext::hasUnavailableFeature(const Decl *D) const {
for (auto *AA : D->specific_attrs<DomainAvailabilityAttr>()) {
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;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12881,6 +12881,7 @@ class IntExprEvaluator

switch (FeatureInfo.Kind) {
case FeatureAvailKind::Available:
case FeatureAvailKind::AlwaysAvailable:
ResultInt = 1;
break;
case FeatureAvailKind::Unavailable:
Expand Down
10 changes: 4 additions & 6 deletions clang/lib/Headers/availability_domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
19 changes: 19 additions & 0 deletions clang/test/Sema/feature-availability.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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) {
Expand Down Expand Up @@ -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