diff --git a/clang/lib/Sema/SemaFeatureAvailability.cpp b/clang/lib/Sema/SemaFeatureAvailability.cpp index 781fc9e8e2ff4..e5319941a99a7 100644 --- a/clang/lib/Sema/SemaFeatureAvailability.cpp +++ b/clang/lib/Sema/SemaFeatureAvailability.cpp @@ -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()) + for (auto *Attr : D->specific_attrs()) { + 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 @@ -165,6 +173,12 @@ void DiagnoseUnguardedFeatureAvailability::diagnoseDeclFeatureAvailability( const NamedDecl *D, SourceLocation Loc) { for (auto *Attr : D->specific_attrs()) { std::string FeatureUse = Attr->getDomain().str(); + // Skip checking if the feature is always enabled. + if (!Attr->getUnavailable() && + SemaRef.Context.getFeatureAvailInfo(FeatureUse).Kind == + FeatureAvailKind::AlwaysAvailable) + continue; + if (!isFeatureUseGuarded(Attr)) SemaRef.Diag(Loc, diag::err_unguarded_feature) << D << FeatureUse << Attr->getUnavailable(); diff --git a/clang/test/CodeGen/feature-availability.c b/clang/test/CodeGen/feature-availability.c index 94a72e4f67e34..2956a61b5160f 100644 --- a/clang/test/CodeGen/feature-availability.c +++ b/clang/test/CodeGen/feature-availability.c @@ -1,11 +1,14 @@ // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-llvm -o - -DUSE_DOMAIN %s | FileCheck --check-prefixes=CHECK,DOMAIN %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-llvm -o - -DUSE_DOMAIN -DALWAYS_ENABLED %s | FileCheck --check-prefixes=CHECK,DOMAIN %s // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -emit-pch -o %t %s // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -include-pch %t -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-pch -o %t -DUSE_DOMAIN %s // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -include-pch %t -emit-llvm -o - -DUSE_DOMAIN %s | FileCheck --check-prefixes=CHECK,DOMAIN %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-pch -o %t -DUSE_DOMAIN -DALWAYS_ENABLED %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -include-pch %t -emit-llvm -o - -DUSE_DOMAIN -DALWAYS_ENABLED %s | FileCheck --check-prefixes=CHECK,DOMAIN %s // CHECK: %[[STRUCT_S0:.*]] = type { i32 } // CHECK: @g0 = external global i32, align 4 @@ -22,7 +25,11 @@ #ifdef USE_DOMAIN // DOMAIN: @g3 = extern_weak global i32, align 4 +#ifdef ALWAYS_ENABLED +CLANG_ALWAYS_ENABLED_AVAILABILITY_DOMAIN(feature1); +#else CLANG_ENABLED_AVAILABILITY_DOMAIN(feature1); +#endif CLANG_DISABLED_AVAILABILITY_DOMAIN(feature2); #endif diff --git a/clang/test/CodeGenObjC/feature-availability.m b/clang/test/CodeGenObjC/feature-availability.m index 67ad95dcf260f..13b2a43b9d756 100644 --- a/clang/test/CodeGenObjC/feature-availability.m +++ b/clang/test/CodeGenObjC/feature-availability.m @@ -1,15 +1,21 @@ // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -ffeature-availability=feature3:on -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-llvm -o - -DUSE_DOMAIN %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-llvm -o - -DUSE_DOMAIN -DALWAYS_ENABLED %s | FileCheck %s #include #define AVAIL 0 #ifdef USE_DOMAIN +#ifdef ALWAYS_ENABLED +CLANG_ALWAYS_ENABLED_AVAILABILITY_DOMAIN(feature1); +CLANG_ALWAYS_ENABLED_AVAILABILITY_DOMAIN(feature3); +#else CLANG_ENABLED_AVAILABILITY_DOMAIN(feature1); -CLANG_DISABLED_AVAILABILITY_DOMAIN(feature2); CLANG_ENABLED_AVAILABILITY_DOMAIN(feature3); #endif +CLANG_DISABLED_AVAILABILITY_DOMAIN(feature2); +#endif // CHECK: @"OBJC_CLASS_$_C0" = global %struct._class_t { ptr @"OBJC_METACLASS_$_C0", ptr null, ptr @_objc_empty_cache, ptr @_objc_empty_vtable, ptr @"_OBJC_CLASS_RO_$_C0" }, section "__DATA, __objc_data", align 8 // CHECK-NEXT: @"OBJC_METACLASS_$_C0" = global %struct._class_t { ptr @"OBJC_METACLASS_$_C0", ptr @"OBJC_CLASS_$_C0", ptr @_objc_empty_cache, ptr @_objc_empty_vtable, ptr @"_OBJC_METACLASS_RO_$_C0" }, section "__DATA, __objc_data", align 8 diff --git a/clang/test/Sema/feature-availability.c b/clang/test/Sema/feature-availability.c index 9b2def0eb3760..dbc35cb9e3c48 100644 --- a/clang/test/Sema/feature-availability.c +++ b/clang/test/Sema/feature-availability.c @@ -258,15 +258,14 @@ void test7(void) { #ifdef USE_DOMAIN void test8(void) { - // FIXME: Use of 'func21()' should not be diagnosed because feature5 is always available. - func21(); // expected-error {{cannot use 'func21' because feature 'feature5' is unavailable in this context}} + func21(); func22(); // expected-error {{cannot use 'func22' because feature 'feature5' is available in this context}} if (__builtin_available(domain:feature5)) { func21(); func22(); // expected-error {{cannot use 'func22' because feature 'feature5' is available in this context}} } else { - func21(); // expected-error {{cannot use 'func21' because feature 'feature5' is unavailable in this context}} + func21(); func22(); } } diff --git a/clang/test/SemaObjC/feature-availability.m b/clang/test/SemaObjC/feature-availability.m index c14a8df04e008..d2c9195ca3813 100644 --- a/clang/test/SemaObjC/feature-availability.m +++ b/clang/test/SemaObjC/feature-availability.m @@ -1,5 +1,6 @@ -// 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 @@ -7,7 +8,11 @@ #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 @@ -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; @@ -59,7 +64,7 @@ @interface NSObject @interface Base7 : NSObject @end -@interface Derived3 : Base7 // expected-error {{cannot use 'Base0' because feature 'feature1' is unavailable in this context}} +@interface Derived3 : Base7 // 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)))}} @@ -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))) @@ -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