From aa8caaeedba138d49222e6baae4deaa1a3dfc78e Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Wed, 24 May 2017 15:15:29 +0000 Subject: [PATCH] Warn about uses of `@available` that can't suppress the -Wunguarded-availability warnings rdar://32306520 Differential Revision: https://reviews.llvm.org/D33450 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303761 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ lib/Sema/SemaDeclAttr.cpp | 6 ++++++ lib/Sema/SemaExpr.cpp | 7 +++++++ test/Parser/objc-available.m | 2 +- test/SemaObjC/unguarded-availability.m | 12 +++++++++++- 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7644a08264..56dd52db4c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2886,6 +2886,10 @@ def warn_partial_message : Warning<"%0 is partial: %1">, def warn_partial_fwdclass_message : Warning< "%0 may be partial because the receiver type is unknown">, InGroup, DefaultIgnore; +def warn_at_available_unchecked_use : Warning< + "%select{@available|__builtin_available}0 does not guard availability here; " + "use if (%select{@available|__builtin_available}0) instead">, + InGroup>; // Thread Safety Attributes def warn_invalid_capability_name : Warning< diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index d484dee1d7..8c4b8c3584 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -7284,6 +7284,12 @@ public: return true; } + bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { + SemaRef.Diag(E->getLocStart(), diag::warn_at_available_unchecked_use) + << (!SemaRef.getLangOpts().ObjC1); + return true; + } + bool VisitTypeLoc(TypeLoc Ty); }; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b83f42dd19..d2443d2f03 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -15762,6 +15762,13 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( if (Spec != AvailSpecs.end()) Version = Spec->getVersion(); + // The use of `@available` in the enclosing function should be analyzed to + // warn when it's used inappropriately (i.e. not if(@available)). + if (getCurFunctionOrMethodDecl()) + getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + else if (getCurBlock() || getCurLambda()) + getCurFunction()->HasPotentialAvailabilityViolations = true; + return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } diff --git a/test/Parser/objc-available.m b/test/Parser/objc-available.m index 49bc539306..01d59f8f52 100644 --- a/test/Parser/objc-available.m +++ b/test/Parser/objc-available.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wunguarded-availability -triple x86_64-apple-macosx10.10.0 -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wunguarded-availability -Wno-unsupported-availability-guard -triple x86_64-apple-macosx10.10.0 -verify %s void f() { diff --git a/test/SemaObjC/unguarded-availability.m b/test/SemaObjC/unguarded-availability.m index 82823204ba..5febee038e 100644 --- a/test/SemaObjC/unguarded-availability.m +++ b/test/SemaObjC/unguarded-availability.m @@ -10,7 +10,7 @@ int func_10_11() AVAILABLE_10_11; // expected-note 4 {{'func_10_11' has been exp #ifdef OBJCPP // expected-note@+2 6 {{marked partial here}} #endif -int func_10_12() AVAILABLE_10_12; // expected-note 6 {{'func_10_12' has been explicitly marked partial here}} +int func_10_12() AVAILABLE_10_12; // expected-note 7 {{'func_10_12' has been explicitly marked partial here}} int func_10_0() AVAILABLE_10_0; @@ -155,6 +155,16 @@ void test_at(Subscriptable *x) { id y = x[42]; // expected-warning{{'objectAtIndexedSubscript:' is only available on macOS 10.12 or newer}} expected-note{{@available}} } +void uncheckAtAvailable() { + if (@available(macOS 10.12, *) || 0) // expected-warning {{@available does not guard availability here; use if (@available) instead}} + func_10_12(); // expected-warning {{'func_10_12' is only available on macOS 10.12 or newer}} + // expected-note@-1 {{enclose 'func_10_12' in an @available check to silence this warning}} +} + +void justAtAvailable() { + int availability = @available(macOS 10.12, *); // expected-warning {{@available does not guard availability here; use if (@available) instead}} +} + #ifdef OBJCPP int f(char) AVAILABLE_10_12; -- 2.50.1