Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add missing check for always-enabled feature
Also test always-enabled features.
  • Loading branch information
ahatanaka committed Sep 22, 2025
commit a5b238082f5386f03958f0c265fec6f6a6182a0e
12 changes: 10 additions & 2 deletions clang/lib/Sema/SemaFeatureAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,18 @@ static bool isFeatureUseGuarded(const DomainAvailabilityAttr *AA,
static void diagnoseDeclFeatureAvailability(const NamedDecl *D,
SourceLocation Loc,
Decl *ContextDecl, Sema &S) {
for (auto *Attr : D->specific_attrs<DomainAvailabilityAttr>())
for (auto *Attr : D->specific_attrs<DomainAvailabilityAttr>()) {
std::string FeatureUse = Attr->getDomain().str();
// Skip checking if the feature is always enabled.
if (!Attr->getUnavailable() &&
S.Context.getFeatureAvailInfo(FeatureUse).Kind ==
FeatureAvailKind::AlwaysAvailable)
continue;

if (!isFeatureUseGuarded(Attr, ContextDecl, S.Context))
S.Diag(Loc, diag::err_unguarded_feature)
<< D << Attr->getDomain().str() << Attr->getUnavailable();
<< D << FeatureUse << Attr->getUnavailable();
}
}

class DiagnoseUnguardedFeatureAvailability
Expand Down
29 changes: 17 additions & 12 deletions clang/test/SemaObjC/feature-availability.m
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// RUN: %clang_cc1 -fblocks -ffeature-availability=feature1:ON -ffeature-availability=feature2:OFF -fsyntax-only -verify %s
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -DUSE_DOMAIN %s
// RUN: %clang_cc1 -fblocks -ffeature-availability=feature1:ON -ffeature-availability=feature2:OFF -fsyntax-only -verify=expected,enabled %s
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify=expected,enabled -DUSE_DOMAIN %s
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify=expected -DUSE_DOMAIN -DALWAYS_ENABLED %s

#include <availability_domain.h>

#define AVAIL 0
#define UNAVAIL 1

#ifdef USE_DOMAIN
#ifdef ALWAYS_ENABLED
CLANG_ALWAYS_ENABLED_AVAILABILITY_DOMAIN(feature1);
#else
CLANG_ENABLED_AVAILABILITY_DOMAIN(feature1);
#endif
CLANG_DISABLED_AVAILABILITY_DOMAIN(feature2);
#endif

Expand All @@ -19,18 +24,18 @@

@interface C0 {
struct S0 ivar0; // expected-error {{cannot use 'S0' because feature 'feature1' is available in this context}}
struct S1 ivar1; // expected-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
struct S1 ivar1; // enabled-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
struct S1 ivar2 __attribute__((availability(domain:feature1, AVAIL)));
struct S1 ivar3 __attribute__((availability(domain:feature1, UNAVAIL))); // expected-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
struct S1 ivar3 __attribute__((availability(domain:feature1, UNAVAIL))); // enabled-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
}
@property struct S0 prop0; // expected-error {{cannot use 'S0' because feature 'feature1' is available in this context}}
@property struct S1 prop1; // expected-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
@property struct S1 prop1; // enabled-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
@property struct S1 prop2 __attribute__((availability(domain:feature1, AVAIL)));
@property struct S1 prop3 __attribute__((availability(domain:feature1, UNAVAIL))); // expected-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
@property struct S1 prop3 __attribute__((availability(domain:feature1, UNAVAIL))); // enabled-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
-(struct S0)m0; // expected-error {{cannot use 'S0' because feature 'feature1' is available in this context}}
-(struct S1)m1; // expected-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
-(struct S1)m1; // enabled-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
-(struct S1)m2 __attribute__((availability(domain:feature1, AVAIL)));
-(struct S1)m3 __attribute__((availability(domain:feature1, UNAVAIL))); // expected-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
-(struct S1)m3 __attribute__((availability(domain:feature1, UNAVAIL))); // enabled-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
@end

@class Base0;
Expand Down Expand Up @@ -59,7 +64,7 @@ @interface NSObject
@interface Base7<T> : NSObject
@end

@interface Derived3 : Base7<Base0 *> // expected-error {{cannot use 'Base0' because feature 'feature1' is unavailable in this context}}
@interface Derived3 : Base7<Base0 *> // enabled-error {{cannot use 'Base0' because feature 'feature1' is unavailable in this context}}
@end

__attribute__((availability(domain:feature1, AVAIL))) // expected-note {{is incompatible with __attribute__((availability(domain:feature1, 0)))}} expected-note 2 {{feature attribute __attribute__((availability(domain:feature1, 0)))}}
Expand Down Expand Up @@ -116,7 +121,7 @@ @interface Derived1(C1) // expected-error {{cannot merge incompatible feature at
@end

@protocol P0
@property struct S1 *p0; // expected-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
@property struct S1 *p0; // enabled-error {{cannot use 'S1' because feature 'feature1' is unavailable in this context}}
@end

__attribute__((availability(domain:feature1, AVAIL)))
Expand Down Expand Up @@ -198,8 +203,8 @@ @implementation Derived9 : Base9
-(void)m4 {
// Check that this method doesn't inherit the domain availablity attribute
// from the base class method.
func1(); // expected-error {{cannot use 'func1' because feature 'feature1' is unavailable in this context}}
func1(); // enabled-error {{cannot use 'func1' because feature 'feature1' is unavailable in this context}}

[super m4]; // expected-error {{cannot use 'm4' because feature 'feature1' is unavailable in this context}}
[super m4]; // enabled-error {{cannot use 'm4' because feature 'feature1' is unavailable in this context}}
}
@end