[ObjC] Warn on unguarded use of partial declaration
This commit adds a traversal of the AST after Sema of a function that diagnoses unguarded references to declarations that are partially available (based on availability attributes). This traversal is only done when we would otherwise emit -Wpartial-availability. This commit is part of a feature I proposed here: http://lists.llvm.org/pipermail/cfe-dev/2016-July/049851.html Differential revision: https://reviews.llvm.org/D23003 llvm-svn: 278826
This commit is contained in:
parent
c98ef718ea
commit
5cd57177a5
|
@ -933,6 +933,8 @@ public:
|
||||||
bool isConstexpr() const { return IfStmtBits.IsConstexpr; }
|
bool isConstexpr() const { return IfStmtBits.IsConstexpr; }
|
||||||
void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; }
|
void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; }
|
||||||
|
|
||||||
|
bool isObjCAvailabilityCheck() const;
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; }
|
SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; }
|
||||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||||
if (SubExprs[ELSE])
|
if (SubExprs[ELSE])
|
||||||
|
|
|
@ -95,8 +95,9 @@ def CXX11CompatDeprecatedWritableStr :
|
||||||
def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
|
def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
|
||||||
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
||||||
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
|
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
|
||||||
def PartialAvailability : DiagGroup<"partial-availability">;
|
|
||||||
def UnguardedAvailability : DiagGroup<"unguarded-availability">;
|
def UnguardedAvailability : DiagGroup<"unguarded-availability">;
|
||||||
|
// partial-availability is an alias of unguarded-availability.
|
||||||
|
def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
|
||||||
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
|
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
|
||||||
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
|
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
|
||||||
def DeprecatedRegister : DiagGroup<"deprecated-register">;
|
def DeprecatedRegister : DiagGroup<"deprecated-register">;
|
||||||
|
|
|
@ -2656,8 +2656,20 @@ def note_overridden_method : Note<
|
||||||
def note_protocol_method : Note<
|
def note_protocol_method : Note<
|
||||||
"protocol method is here">;
|
"protocol method is here">;
|
||||||
|
|
||||||
def warn_available_using_star_case : Warning<
|
def warn_unguarded_availability :
|
||||||
"using '*' case here, platform %0 is not accounted for">, InGroup<UnguardedAvailability>;
|
Warning<"%0 is only available on %1 %2 or newer">,
|
||||||
|
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||||
|
def warn_partial_availability : Warning<"%0 is only available conditionally">,
|
||||||
|
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||||
|
def note_partial_availability_silence : Note<
|
||||||
|
"explicitly redeclare %0 to silence this warning">;
|
||||||
|
def note_unguarded_available_silence : Note<
|
||||||
|
"enclose %0 in an @available check to silence this warning">;
|
||||||
|
def warn_partial_message : Warning<"%0 is partial: %1">,
|
||||||
|
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||||
|
def warn_partial_fwdclass_message : Warning<
|
||||||
|
"%0 may be partial because the receiver type is unknown">,
|
||||||
|
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||||
|
|
||||||
// Thread Safety Attributes
|
// Thread Safety Attributes
|
||||||
def warn_invalid_capability_name : Warning<
|
def warn_invalid_capability_name : Warning<
|
||||||
|
@ -4279,15 +4291,6 @@ def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neith
|
||||||
def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the "
|
def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the "
|
||||||
"call site%select{| or in %2| or in an associated namespace of one of its arguments}1">;
|
"call site%select{| or in %2| or in an associated namespace of one of its arguments}1">;
|
||||||
def err_undeclared_use : Error<"use of undeclared %0">;
|
def err_undeclared_use : Error<"use of undeclared %0">;
|
||||||
def warn_partial_availability : Warning<"%0 is only available conditionally">,
|
|
||||||
InGroup<PartialAvailability>, DefaultIgnore;
|
|
||||||
def note_partial_availability_silence : Note<
|
|
||||||
"explicitly redeclare %0 to silence this warning">;
|
|
||||||
def warn_partial_message : Warning<"%0 is partial: %1">,
|
|
||||||
InGroup<PartialAvailability>, DefaultIgnore;
|
|
||||||
def warn_partial_fwdclass_message : Warning<
|
|
||||||
"%0 may be partial because the receiver type is unknown">,
|
|
||||||
InGroup<PartialAvailability>, DefaultIgnore;
|
|
||||||
def warn_deprecated : Warning<"%0 is deprecated">,
|
def warn_deprecated : Warning<"%0 is deprecated">,
|
||||||
InGroup<DeprecatedDeclarations>;
|
InGroup<DeprecatedDeclarations>;
|
||||||
def warn_property_method_deprecated :
|
def warn_property_method_deprecated :
|
||||||
|
@ -4738,6 +4741,8 @@ def note_protected_by_vla_type_alias : Note<
|
||||||
"jump bypasses initialization of VLA type alias">;
|
"jump bypasses initialization of VLA type alias">;
|
||||||
def note_protected_by_constexpr_if : Note<
|
def note_protected_by_constexpr_if : Note<
|
||||||
"jump enters controlled statement of constexpr if">;
|
"jump enters controlled statement of constexpr if">;
|
||||||
|
def note_protected_by_if_available : Note<
|
||||||
|
"jump enters controlled statement of if available">;
|
||||||
def note_protected_by_vla : Note<
|
def note_protected_by_vla : Note<
|
||||||
"jump bypasses initialization of variable length array">;
|
"jump bypasses initialization of variable length array">;
|
||||||
def note_protected_by_objc_try : Note<
|
def note_protected_by_objc_try : Note<
|
||||||
|
|
|
@ -106,11 +106,15 @@ public:
|
||||||
bool HasDroppedStmt : 1;
|
bool HasDroppedStmt : 1;
|
||||||
|
|
||||||
/// \brief True if current scope is for OpenMP declare reduction combiner.
|
/// \brief True if current scope is for OpenMP declare reduction combiner.
|
||||||
bool HasOMPDeclareReductionCombiner;
|
bool HasOMPDeclareReductionCombiner : 1;
|
||||||
|
|
||||||
/// \brief Whether there is a fallthrough statement in this function.
|
/// \brief Whether there is a fallthrough statement in this function.
|
||||||
bool HasFallthroughStmt : 1;
|
bool HasFallthroughStmt : 1;
|
||||||
|
|
||||||
|
/// \brief Whether we make reference to a declaration that could be
|
||||||
|
/// unavailable.
|
||||||
|
bool HasPotentialAvailabilityViolations : 1;
|
||||||
|
|
||||||
/// A flag that is set when parsing a method that must call super's
|
/// A flag that is set when parsing a method that must call super's
|
||||||
/// implementation, such as \c -dealloc, \c -finalize, or any method marked
|
/// implementation, such as \c -dealloc, \c -finalize, or any method marked
|
||||||
/// with \c __attribute__((objc_requires_super)).
|
/// with \c __attribute__((objc_requires_super)).
|
||||||
|
@ -381,6 +385,7 @@ public:
|
||||||
HasDroppedStmt(false),
|
HasDroppedStmt(false),
|
||||||
HasOMPDeclareReductionCombiner(false),
|
HasOMPDeclareReductionCombiner(false),
|
||||||
HasFallthroughStmt(false),
|
HasFallthroughStmt(false),
|
||||||
|
HasPotentialAvailabilityViolations(false),
|
||||||
ObjCShouldCallSuper(false),
|
ObjCShouldCallSuper(false),
|
||||||
ObjCIsDesignatedInit(false),
|
ObjCIsDesignatedInit(false),
|
||||||
ObjCWarnForNoDesignatedInitChain(false),
|
ObjCWarnForNoDesignatedInitChain(false),
|
||||||
|
|
|
@ -3639,6 +3639,9 @@ public:
|
||||||
bool makeUnavailableInSystemHeader(SourceLocation loc,
|
bool makeUnavailableInSystemHeader(SourceLocation loc,
|
||||||
UnavailableAttr::ImplicitReason reason);
|
UnavailableAttr::ImplicitReason reason);
|
||||||
|
|
||||||
|
/// \brief Issue any -Wunguarded-availability warnings in \c FD
|
||||||
|
void DiagnoseUnguardedAvailabilityViolations(Decl *FD);
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Expression Parsing Callbacks: SemaExpr.cpp.
|
// Expression Parsing Callbacks: SemaExpr.cpp.
|
||||||
|
|
||||||
|
|
|
@ -794,6 +794,10 @@ void IfStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
|
||||||
VarRange.getEnd());
|
VarRange.getEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IfStmt::isObjCAvailabilityCheck() const {
|
||||||
|
return isa<ObjCAvailabilityCheckExpr>(SubExprs[COND]);
|
||||||
|
}
|
||||||
|
|
||||||
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
|
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
|
||||||
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
|
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
|
||||||
SourceLocation RP)
|
SourceLocation RP)
|
||||||
|
|
|
@ -325,30 +325,27 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
|
||||||
|
|
||||||
case Stmt::IfStmtClass: {
|
case Stmt::IfStmtClass: {
|
||||||
IfStmt *IS = cast<IfStmt>(S);
|
IfStmt *IS = cast<IfStmt>(S);
|
||||||
if (!IS->isConstexpr())
|
if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
unsigned Diag = IS->isConstexpr() ? diag::note_protected_by_constexpr_if
|
||||||
|
: diag::note_protected_by_if_available;
|
||||||
|
|
||||||
if (VarDecl *Var = IS->getConditionVariable())
|
if (VarDecl *Var = IS->getConditionVariable())
|
||||||
BuildScopeInformation(Var, ParentScope);
|
BuildScopeInformation(Var, ParentScope);
|
||||||
|
|
||||||
// Cannot jump into the middle of the condition.
|
// Cannot jump into the middle of the condition.
|
||||||
unsigned NewParentScope = Scopes.size();
|
unsigned NewParentScope = Scopes.size();
|
||||||
Scopes.push_back(GotoScope(ParentScope,
|
Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getLocStart()));
|
||||||
diag::note_protected_by_constexpr_if, 0,
|
|
||||||
IS->getLocStart()));
|
|
||||||
BuildScopeInformation(IS->getCond(), NewParentScope);
|
BuildScopeInformation(IS->getCond(), NewParentScope);
|
||||||
|
|
||||||
// Jumps into either arm of an 'if constexpr' are not allowed.
|
// Jumps into either arm of an 'if constexpr' are not allowed.
|
||||||
NewParentScope = Scopes.size();
|
NewParentScope = Scopes.size();
|
||||||
Scopes.push_back(GotoScope(ParentScope,
|
Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getLocStart()));
|
||||||
diag::note_protected_by_constexpr_if, 0,
|
|
||||||
IS->getLocStart()));
|
|
||||||
BuildScopeInformation(IS->getThen(), NewParentScope);
|
BuildScopeInformation(IS->getThen(), NewParentScope);
|
||||||
if (Stmt *Else = IS->getElse()) {
|
if (Stmt *Else = IS->getElse()) {
|
||||||
NewParentScope = Scopes.size();
|
NewParentScope = Scopes.size();
|
||||||
Scopes.push_back(GotoScope(ParentScope,
|
Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getLocStart()));
|
||||||
diag::note_protected_by_constexpr_if, 0,
|
|
||||||
IS->getLocStart()));
|
|
||||||
BuildScopeInformation(Else, NewParentScope);
|
BuildScopeInformation(Else, NewParentScope);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -29,6 +29,7 @@ void FunctionScopeInfo::Clear() {
|
||||||
HasIndirectGoto = false;
|
HasIndirectGoto = false;
|
||||||
HasDroppedStmt = false;
|
HasDroppedStmt = false;
|
||||||
HasOMPDeclareReductionCombiner = false;
|
HasOMPDeclareReductionCombiner = false;
|
||||||
|
HasPotentialAvailabilityViolations = false;
|
||||||
ObjCShouldCallSuper = false;
|
ObjCShouldCallSuper = false;
|
||||||
ObjCIsDesignatedInit = false;
|
ObjCIsDesignatedInit = false;
|
||||||
ObjCWarnForNoDesignatedInitChain = false;
|
ObjCWarnForNoDesignatedInitChain = false;
|
||||||
|
|
|
@ -11736,6 +11736,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Body && getCurFunction()->HasPotentialAvailabilityViolations)
|
||||||
|
DiagnoseUnguardedAvailabilityViolations(dcl);
|
||||||
|
|
||||||
assert(!getCurFunction()->ObjCShouldCallSuper &&
|
assert(!getCurFunction()->ObjCShouldCallSuper &&
|
||||||
"This should only be set for ObjC methods, which should have been "
|
"This should only be set for ObjC methods, which should have been "
|
||||||
"handled in the block above.");
|
"handled in the block above.");
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/ExprCXX.h"
|
#include "clang/AST/ExprCXX.h"
|
||||||
#include "clang/AST/Mangle.h"
|
#include "clang/AST/Mangle.h"
|
||||||
|
#include "clang/AST/RecursiveASTVisitor.h"
|
||||||
#include "clang/Basic/CharInfo.h"
|
#include "clang/Basic/CharInfo.h"
|
||||||
#include "clang/Basic/SourceManager.h"
|
#include "clang/Basic/SourceManager.h"
|
||||||
#include "clang/Basic/TargetInfo.h"
|
#include "clang/Basic/TargetInfo.h"
|
||||||
|
@ -6330,6 +6331,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AR_NotYetIntroduced:
|
case AR_NotYetIntroduced:
|
||||||
|
assert(!S.getCurFunctionOrMethodDecl() &&
|
||||||
|
"Function-level partial availablity should not be diagnosed here!");
|
||||||
|
|
||||||
diag = diag::warn_partial_availability;
|
diag = diag::warn_partial_availability;
|
||||||
diag_message = diag::warn_partial_message;
|
diag_message = diag::warn_partial_message;
|
||||||
diag_fwdclass_message = diag::warn_partial_fwdclass_message;
|
diag_fwdclass_message = diag::warn_partial_fwdclass_message;
|
||||||
|
@ -6511,3 +6515,146 @@ VersionTuple Sema::getVersionForDecl(const Decl *D) const {
|
||||||
|
|
||||||
return std::max(DeclVersion, Context.getTargetInfo().getPlatformMinVersion());
|
return std::max(DeclVersion, Context.getTargetInfo().getPlatformMinVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// \brief This class implements -Wunguarded-availability.
|
||||||
|
///
|
||||||
|
/// This is done with a traversal of the AST of a function that makes reference
|
||||||
|
/// to a partially available declaration. Whenever we encounter an \c if of the
|
||||||
|
/// form: \c if(@available(...)), we use the version from the condition to visit
|
||||||
|
/// the then statement.
|
||||||
|
class DiagnoseUnguardedAvailability
|
||||||
|
: public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
|
||||||
|
typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
|
||||||
|
|
||||||
|
Sema &SemaRef;
|
||||||
|
|
||||||
|
/// Stack of potentially nested 'if (@available(...))'s.
|
||||||
|
SmallVector<VersionTuple, 8> AvailabilityStack;
|
||||||
|
|
||||||
|
void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range);
|
||||||
|
|
||||||
|
public:
|
||||||
|
DiagnoseUnguardedAvailability(Sema &SemaRef, VersionTuple BaseVersion)
|
||||||
|
: SemaRef(SemaRef) {
|
||||||
|
AvailabilityStack.push_back(BaseVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
|
||||||
|
|
||||||
|
bool TraverseIfStmt(IfStmt *If);
|
||||||
|
|
||||||
|
bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
|
||||||
|
if (ObjCMethodDecl *D = Msg->getMethodDecl())
|
||||||
|
DiagnoseDeclAvailability(
|
||||||
|
D, SourceRange(Msg->getSelectorStartLoc(), Msg->getLocEnd()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VisitDeclRefExpr(DeclRefExpr *DRE) {
|
||||||
|
DiagnoseDeclAvailability(DRE->getDecl(),
|
||||||
|
SourceRange(DRE->getLocStart(), DRE->getLocEnd()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VisitMemberExpr(MemberExpr *ME) {
|
||||||
|
DiagnoseDeclAvailability(ME->getMemberDecl(),
|
||||||
|
SourceRange(ME->getLocStart(), ME->getLocEnd()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VisitTypeLoc(TypeLoc Ty);
|
||||||
|
};
|
||||||
|
|
||||||
|
void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
|
||||||
|
NamedDecl *D, SourceRange Range) {
|
||||||
|
|
||||||
|
VersionTuple ContextVersion = AvailabilityStack.back();
|
||||||
|
if (AvailabilityResult Result = SemaRef.ShouldDiagnoseAvailabilityOfDecl(
|
||||||
|
D, ContextVersion, nullptr)) {
|
||||||
|
// All other diagnostic kinds have already been handled in
|
||||||
|
// DiagnoseAvailabilityOfDecl.
|
||||||
|
if (Result != AR_NotYetIntroduced)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D);
|
||||||
|
VersionTuple Introduced = AA->getIntroduced();
|
||||||
|
|
||||||
|
SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability)
|
||||||
|
<< Range << D
|
||||||
|
<< AvailabilityAttr::getPrettyPlatformName(
|
||||||
|
SemaRef.getASTContext().getTargetInfo().getPlatformName())
|
||||||
|
<< Introduced.getAsString();
|
||||||
|
|
||||||
|
SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here)
|
||||||
|
<< D << /* partial */ 3;
|
||||||
|
|
||||||
|
// FIXME: Replace this with a fixit diagnostic.
|
||||||
|
SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
|
||||||
|
<< Range << D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
|
||||||
|
const Type *TyPtr = Ty.getTypePtr();
|
||||||
|
SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
|
||||||
|
|
||||||
|
if (const TagType *TT = dyn_cast<TagType>(TyPtr)) {
|
||||||
|
TagDecl *TD = TT->getDecl();
|
||||||
|
DiagnoseDeclAvailability(TD, Range);
|
||||||
|
|
||||||
|
} else if (const TypedefType *TD = dyn_cast<TypedefType>(TyPtr)) {
|
||||||
|
TypedefNameDecl *D = TD->getDecl();
|
||||||
|
DiagnoseDeclAvailability(D, Range);
|
||||||
|
|
||||||
|
} else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
|
||||||
|
if (NamedDecl *D = ObjCO->getInterface())
|
||||||
|
DiagnoseDeclAvailability(D, Range);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
|
||||||
|
VersionTuple CondVersion;
|
||||||
|
if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
|
||||||
|
CondVersion = E->getVersion();
|
||||||
|
|
||||||
|
// If we're using the '*' case here or if this check is redundant, then we
|
||||||
|
// use the enclosing version to check both branches.
|
||||||
|
if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
|
||||||
|
return Base::TraverseStmt(If->getThen()) &&
|
||||||
|
Base::TraverseStmt(If->getElse());
|
||||||
|
} else {
|
||||||
|
// This isn't an availability checking 'if', we can just continue.
|
||||||
|
return Base::TraverseIfStmt(If);
|
||||||
|
}
|
||||||
|
|
||||||
|
AvailabilityStack.push_back(CondVersion);
|
||||||
|
bool ShouldContinue = TraverseStmt(If->getThen());
|
||||||
|
AvailabilityStack.pop_back();
|
||||||
|
|
||||||
|
return ShouldContinue && TraverseStmt(If->getElse());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
|
||||||
|
Stmt *Body = nullptr;
|
||||||
|
|
||||||
|
if (auto *FD = D->getAsFunction()) {
|
||||||
|
// FIXME: We only examine the pattern decl for availability violations now,
|
||||||
|
// but we should also examine instantiated templates.
|
||||||
|
if (FD->isTemplateInstantiation())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Body = FD->getBody();
|
||||||
|
} else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
|
||||||
|
Body = MD->getBody();
|
||||||
|
|
||||||
|
assert(Body && "Need a body here!");
|
||||||
|
|
||||||
|
VersionTuple BaseVersion = getVersionForDecl(D);
|
||||||
|
DiagnoseUnguardedAvailability(*this, BaseVersion).IssueDiagnostics(Body);
|
||||||
|
}
|
||||||
|
|
|
@ -184,6 +184,11 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
||||||
if (AvailabilityResult Result =
|
if (AvailabilityResult Result =
|
||||||
S.ShouldDiagnoseAvailabilityOfDecl(D, ContextVersion, &Message)) {
|
S.ShouldDiagnoseAvailabilityOfDecl(D, ContextVersion, &Message)) {
|
||||||
|
|
||||||
|
if (Result == AR_NotYetIntroduced && S.getCurFunctionOrMethodDecl()) {
|
||||||
|
S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const ObjCPropertyDecl *ObjCPDecl = nullptr;
|
const ObjCPropertyDecl *ObjCPDecl = nullptr;
|
||||||
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||||
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
|
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
|
||||||
|
@ -15198,11 +15203,6 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
|
||||||
VersionTuple Version;
|
VersionTuple Version;
|
||||||
if (Spec != AvailSpecs.end())
|
if (Spec != AvailSpecs.end())
|
||||||
Version = Spec->getVersion();
|
Version = Spec->getVersion();
|
||||||
else
|
|
||||||
// This is the '*' case in @available. We should diagnose this; the
|
|
||||||
// programmer should explicitly account for this case if they target this
|
|
||||||
// platform.
|
|
||||||
Diag(AtLoc, diag::warn_available_using_star_case) << RParen << Platform;
|
|
||||||
|
|
||||||
return new (Context)
|
return new (Context)
|
||||||
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
|
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
|
||||||
|
|
|
@ -536,7 +536,7 @@ StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
|
||||||
if (Cond.isInvalid())
|
if (Cond.isInvalid())
|
||||||
return StmtError();
|
return StmtError();
|
||||||
|
|
||||||
if (IsConstexpr)
|
if (IsConstexpr || isa<ObjCAvailabilityCheckExpr>(Cond.get().second))
|
||||||
getCurFunction()->setHasBranchProtectedScope();
|
getCurFunction()->setHasBranchProtectedScope();
|
||||||
|
|
||||||
DiagnoseUnusedExprResult(thenStmt);
|
DiagnoseUnusedExprResult(thenStmt);
|
||||||
|
|
|
@ -15,8 +15,6 @@ void f() {
|
||||||
|
|
||||||
(void)@available(erik_os 10.10, hat_os 1.0, *); // expected-error 2 {{unrecognized platform name}}
|
(void)@available(erik_os 10.10, hat_os 1.0, *); // expected-error 2 {{unrecognized platform name}}
|
||||||
|
|
||||||
(void)@available(ios 8, *); // expected-warning{{using '*' case here, platform macos is not accounted for}}
|
|
||||||
|
|
||||||
(void)@available(); // expected-error{{expected a platform name here}}
|
(void)@available(); // expected-error{{expected a platform name here}}
|
||||||
(void)@available(macos 10.10,); // expected-error{{expected a platform name here}}
|
(void)@available(macos 10.10,); // expected-error{{expected a platform name here}}
|
||||||
(void)@available(macos); // expected-error{{expected a version}}
|
(void)@available(macos); // expected-error{{expected a version}}
|
||||||
|
|
|
@ -30,7 +30,7 @@ void test_10095131() {
|
||||||
ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in macOS 9.0 - use ATSFontGetFullPostScriptName}}
|
ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in macOS 9.0 - use ATSFontGetFullPostScriptName}}
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'PartiallyAvailable' to silence this warning}}
|
// expected-warning@+2 {{is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'PartiallyAvailable' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
PartiallyAvailable();
|
PartiallyAvailable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,16 +46,16 @@ void f(A *a, B *b) {
|
||||||
[b proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in macOS 10.2}}
|
[b proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in macOS 10.2}}
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'partialMethod' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'partialMethod' to silence this warning}}
|
// expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'partialMethod' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[a partialMethod];
|
[a partialMethod];
|
||||||
[b partialMethod]; // no warning
|
[b partialMethod]; // no warning
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'partial_proto_method' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'partial_proto_method' to silence this warning}}
|
// expected-warning@+2 {{'partial_proto_method' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'partial_proto_method' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[a partial_proto_method];
|
[a partial_proto_method];
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'partial_proto_method' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'partial_proto_method' to silence this warning}}
|
// expected-warning@+2 {{'partial_proto_method' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'partial_proto_method' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[b partial_proto_method];
|
[b partial_proto_method];
|
||||||
}
|
}
|
||||||
|
@ -163,14 +163,14 @@ void partialfun(PartialI* a) {
|
||||||
[a partialMethod]; // no warning
|
[a partialMethod]; // no warning
|
||||||
[a ipartialMethod1]; // no warning
|
[a ipartialMethod1]; // no warning
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'ipartialMethod2' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'ipartialMethod2' to silence this warning}}
|
// expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[a ipartialMethod2];
|
[a ipartialMethod2];
|
||||||
[a ppartialMethod]; // no warning
|
[a ppartialMethod]; // no warning
|
||||||
[PartialI partialMethod]; // no warning
|
[PartialI partialMethod]; // no warning
|
||||||
[PartialI ipartialMethod1]; // no warning
|
[PartialI ipartialMethod1]; // no warning
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'ipartialMethod2' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'ipartialMethod2' to silence this warning}}
|
// expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[PartialI ipartialMethod2];
|
[PartialI ipartialMethod2];
|
||||||
[PartialI ppartialMethod]; // no warning
|
[PartialI ppartialMethod]; // no warning
|
||||||
|
@ -309,7 +309,7 @@ __attribute__((objc_root_class))
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation LookupAvailabilityBase
|
@implementation LookupAvailabilityBase
|
||||||
-(void)method1 { fn_10_7(); } // expected-warning{{partial}} expected-note{{explicitly redeclare}}
|
-(void)method1 { fn_10_7(); } // expected-warning{{only available on macOS 10.7}} expected-note{{@available}}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
__attribute__((availability(macosx, introduced=10.7)))
|
__attribute__((availability(macosx, introduced=10.7)))
|
||||||
|
@ -321,7 +321,7 @@ __attribute__((availability(macosx, introduced=10.7)))
|
||||||
|
|
||||||
@implementation LookupAvailability
|
@implementation LookupAvailability
|
||||||
-(void)method2 { fn_10_7(); }
|
-(void)method2 { fn_10_7(); }
|
||||||
-(void)method3 { fn_10_8(); } // expected-warning{{partial}} expected-note{{explicitly redeclare}}
|
-(void)method3 { fn_10_8(); } // expected-warning{{only available on macOS 10.8}} expected-note{{@available}}
|
||||||
-(void)method4 { fn_10_8(); }
|
-(void)method4 { fn_10_8(); }
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ typedef signed char BOOL;
|
||||||
@property(nonatomic,assign) id ptarget __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'ptarget' is declared deprecated here}} expected-note {{'ptarget' has been explicitly marked deprecated here}}
|
@property(nonatomic,assign) id ptarget __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'ptarget' is declared deprecated here}} expected-note {{'ptarget' has been explicitly marked deprecated here}}
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-note@+2 {{property 'partialPtarget' is declared partial here}} expected-note@+2 {{'partialPtarget' has been explicitly marked partial here}}
|
// expected-note@+2 {{'partialPtarget' has been explicitly marked partial here}}
|
||||||
#endif
|
#endif
|
||||||
@property(nonatomic,assign) id partialPtarget __attribute__((availability(ios,introduced=5.0)));
|
@property(nonatomic,assign) id partialPtarget __attribute__((availability(ios,introduced=5.0)));
|
||||||
@end
|
@end
|
||||||
|
@ -24,7 +24,7 @@ typedef signed char BOOL;
|
||||||
@property(nonatomic,assign) id target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'target' is declared deprecated here}} expected-note {{'setTarget:' has been explicitly marked deprecated here}}
|
@property(nonatomic,assign) id target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'target' is declared deprecated here}} expected-note {{'setTarget:' has been explicitly marked deprecated here}}
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-note@+2 {{property 'partialTarget' is declared partial here}} expected-note@+2 {{'setPartialTarget:' has been explicitly marked partial here}}
|
// expected-note@+2 {{'setPartialTarget:' has been explicitly marked partial here}}
|
||||||
#endif
|
#endif
|
||||||
@property(nonatomic,assign) id partialTarget __attribute__((availability(ios,introduced=5.0)));
|
@property(nonatomic,assign) id partialTarget __attribute__((availability(ios,introduced=5.0)));
|
||||||
@end
|
@end
|
||||||
|
@ -40,7 +40,7 @@ typedef signed char BOOL;
|
||||||
// expected-note 2 {{'setDep_target:' has been explicitly marked deprecated here}}
|
// expected-note 2 {{'setDep_target:' has been explicitly marked deprecated here}}
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-note@+2 4 {{property 'partial_dep_target' is declared partial here}} expected-note@+2 2 {{'partial_dep_target' has been explicitly marked partial here}} expected-note@+2 2 {{'setPartial_dep_target:' has been explicitly marked partial here}}
|
// expected-note@+2 2 {{'partial_dep_target' has been explicitly marked partial here}} expected-note@+2 2 {{'setPartial_dep_target:' has been explicitly marked partial here}}
|
||||||
#endif
|
#endif
|
||||||
@property(nonatomic,assign) id partial_dep_target __attribute__((availability(ios,introduced=5.0)));
|
@property(nonatomic,assign) id partial_dep_target __attribute__((availability(ios,introduced=5.0)));
|
||||||
@end
|
@end
|
||||||
|
@ -57,7 +57,7 @@ typedef signed char BOOL;
|
||||||
[self setPtarget: (id)0]; // no-warning
|
[self setPtarget: (id)0]; // no-warning
|
||||||
[self setPartialTarget: (id)0]; // no-warning
|
[self setPartialTarget: (id)0]; // no-warning
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'partial_dep_target' is partial: introduced in iOS 5.0}} expected-warning@+2 {{'setPartial_dep_target:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partial_dep_target' to silence this warning}} expected-note@+2 {{explicitly redeclare 'setPartial_dep_target:' to silence this warning}}
|
// expected-warning@+2 {{'partial_dep_target' is only available on iOS 5.0 or newer}} expected-warning@+2 {{'setPartial_dep_target:' is only available on iOS 5.0 or newer}} expected-note@+2 {{enclose 'partial_dep_target' in an @available check to silence this warning}} expected-note@+2 {{enclose 'setPartial_dep_target:' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[self setPartial_dep_target: [self partial_dep_target]];
|
[self setPartial_dep_target: [self partial_dep_target]];
|
||||||
|
|
||||||
|
@ -82,11 +82,11 @@ typedef signed char BOOL;
|
||||||
[self setPtarget: (id)0]; // no-warning
|
[self setPtarget: (id)0]; // no-warning
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'setPartialTarget:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'setPartialTarget:' to silence this warning}}
|
// expected-warning@+2 {{'setPartialTarget:' is only available on iOS 5.0 or newer}} expected-note@+2 {{enclose 'setPartialTarget:' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[self setPartialTarget: (id)0];
|
[self setPartialTarget: (id)0];
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'partial_dep_target' is partial: introduced in iOS 5.0}} expected-warning@+2 {{'setPartial_dep_target:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partial_dep_target' to silence this warning}} expected-note@+2 {{explicitly redeclare 'setPartial_dep_target:' to silence this warning}}
|
// expected-warning@+2 {{'partial_dep_target' is only available on iOS 5.0 or newer}} expected-warning@+2 {{'setPartial_dep_target:' is only available on iOS 5.0 or newer}} expected-note@+2 {{enclose 'partial_dep_target' in an @available check to silence this warning}} expected-note@+2 {{enclose 'setPartial_dep_target:' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
[self setPartial_dep_target: [self partial_dep_target]];
|
[self setPartial_dep_target: [self partial_dep_target]];
|
||||||
[self setPartialPtarget: (id)0]; // no-warning
|
[self setPartialPtarget: (id)0]; // no-warning
|
||||||
|
@ -100,12 +100,12 @@ typedef signed char BOOL;
|
||||||
@property(setter=setNewDelegate:,assign) id delegate __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{'setNewDelegate:' has been explicitly marked deprecated here}} expected-note {{property 'delegate' is declared deprecated here}}
|
@property(setter=setNewDelegate:,assign) id delegate __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{'setNewDelegate:' has been explicitly marked deprecated here}} expected-note {{property 'delegate' is declared deprecated here}}
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-note@+2 {{property 'partialEnabled' is declared partial here}} expected-note@+2 {{'partialIsEnabled' has been explicitly marked partial here}}
|
// expected-note@+2 {{'partialIsEnabled' has been explicitly marked partial here}}
|
||||||
#endif
|
#endif
|
||||||
@property(getter=partialIsEnabled,assign) BOOL partialEnabled __attribute__((availability(ios,introduced=5.0)));
|
@property(getter=partialIsEnabled,assign) BOOL partialEnabled __attribute__((availability(ios,introduced=5.0)));
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-note@+2 {{property 'partialDelegate' is declared partial here}} expected-note@+2 {{'partialSetNewDelegate:' has been explicitly marked partial here}}
|
// expected-note@+2 {{'partialSetNewDelegate:' has been explicitly marked partial here}}
|
||||||
#endif
|
#endif
|
||||||
@property(setter=partialSetNewDelegate:,assign) id partialDelegate __attribute__((availability(ios,introduced=5.0)));
|
@property(setter=partialSetNewDelegate:,assign) id partialDelegate __attribute__((availability(ios,introduced=5.0)));
|
||||||
@end
|
@end
|
||||||
|
@ -115,7 +115,7 @@ void testCustomAccessorNames(CustomAccessorNames *obj) {
|
||||||
[obj setNewDelegate:0]; // expected-warning {{'setNewDelegate:' is deprecated: first deprecated in iOS 3.0}}
|
[obj setNewDelegate:0]; // expected-warning {{'setNewDelegate:' is deprecated: first deprecated in iOS 3.0}}
|
||||||
|
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'partialIsEnabled' is partial: introduced in iOS 5.0}} expected-warning@+3 {{'partialSetNewDelegate:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partialIsEnabled' to silence this warning}} expected-note@+3 {{explicitly redeclare 'partialSetNewDelegate:' to silence this warning}}
|
// expected-warning@+2 {{'partialIsEnabled' is only available on iOS 5.0 or newer}} expected-warning@+3 {{'partialSetNewDelegate:' is only available on iOS 5.0 or newer}} expected-note@+2 {{enclose 'partialIsEnabled' in an @available check to silence this warning}} expected-note@+3 {{enclose 'partialSetNewDelegate:' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
if ([obj partialIsEnabled])
|
if ([obj partialIsEnabled])
|
||||||
[obj partialSetNewDelegate:0];
|
[obj partialSetNewDelegate:0];
|
||||||
|
@ -138,7 +138,7 @@ id useDeprecatedProperty(ProtocolInCategory *obj, id<P> obj2, int flag) {
|
||||||
if (flag)
|
if (flag)
|
||||||
return [obj partialPtarget]; // no-warning
|
return [obj partialPtarget]; // no-warning
|
||||||
#if defined(WARN_PARTIAL)
|
#if defined(WARN_PARTIAL)
|
||||||
// expected-warning@+2 {{'partialPtarget' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partialPtarget' to silence this warning}}
|
// expected-warning@+2 {{'partialPtarget' is only available on iOS 5.0 or newer}} expected-note@+2 {{enclose 'partialPtarget' in an @available check to silence this warning}}
|
||||||
#endif
|
#endif
|
||||||
return [obj2 partialPtarget];
|
return [obj2 partialPtarget];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-apple-macosx-10.9 -Wunguarded-availability -fblocks -fsyntax-only -verify %s
|
||||||
|
// RUN: %clang_cc1 -xobjective-c++ -DOBJCPP -triple x86_64-apple-macosx-10.9 -Wunguarded-availability -fblocks -fsyntax-only -verify %s
|
||||||
|
|
||||||
|
#define AVAILABLE_10_0 __attribute__((availability(macos, introduced = 10.0)))
|
||||||
|
#define AVAILABLE_10_11 __attribute__((availability(macos, introduced = 10.11)))
|
||||||
|
#define AVAILABLE_10_12 __attribute__((availability(macos, introduced = 10.12)))
|
||||||
|
|
||||||
|
int func_10_11() AVAILABLE_10_11; // expected-note 4 {{'func_10_11' has been explicitly marked partial here}}
|
||||||
|
|
||||||
|
#ifdef OBJCPP
|
||||||
|
// expected-note@+2 {{marked partial here}}
|
||||||
|
#endif
|
||||||
|
int func_10_12() AVAILABLE_10_12; // expected-note 5 {{'func_10_12' has been explicitly marked partial here}}
|
||||||
|
|
||||||
|
int func_10_0() AVAILABLE_10_0;
|
||||||
|
|
||||||
|
void use_func() {
|
||||||
|
func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
|
||||||
|
|
||||||
|
if (@available(macos 10.11, *))
|
||||||
|
func_10_11();
|
||||||
|
else
|
||||||
|
func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void defn_10_11() AVAILABLE_10_11;
|
||||||
|
|
||||||
|
void defn_10_11() {
|
||||||
|
func_10_11();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nested_ifs() {
|
||||||
|
if (@available(macos 10.12, *)) {
|
||||||
|
if (@available(macos 10.10, *)) {
|
||||||
|
func_10_12();
|
||||||
|
} else {
|
||||||
|
func_10_12();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose 'func_10_12' in an @available check to silence this warning}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void star_case() {
|
||||||
|
if (@available(ios 9, *)) {
|
||||||
|
func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
|
||||||
|
func_10_0();
|
||||||
|
} else
|
||||||
|
func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
|
||||||
|
|
||||||
|
if (@available(macos 10.11, *)) {
|
||||||
|
if (@available(ios 8, *)) {
|
||||||
|
func_10_11();
|
||||||
|
func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose}}
|
||||||
|
} else {
|
||||||
|
func_10_11();
|
||||||
|
func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef int int_10_11 AVAILABLE_10_11; // expected-note {{'int_10_11' has been explicitly marked partial here}}
|
||||||
|
#ifdef OBJCPP
|
||||||
|
// expected-note@+2 {{marked partial here}}
|
||||||
|
#endif
|
||||||
|
typedef int int_10_12 AVAILABLE_10_12; // expected-note 3 {{'int_10_12' has been explicitly marked partial here}}
|
||||||
|
|
||||||
|
void use_typedef() {
|
||||||
|
int_10_11 x; // expected-warning{{'int_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'int_10_11' in an @available check to silence this warning}}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((objc_root_class))
|
||||||
|
AVAILABLE_10_11 @interface Class_10_11 {
|
||||||
|
int_10_11 foo;
|
||||||
|
int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
|
||||||
|
}
|
||||||
|
- (void)method1;
|
||||||
|
- (void)method2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation Class_10_11
|
||||||
|
- (void) method1 {
|
||||||
|
func_10_11();
|
||||||
|
func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose 'func_10_12' in an @available check to silence this warning}}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)method2 AVAILABLE_10_12 {
|
||||||
|
func_10_12();
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
int protected_scope() {
|
||||||
|
if (@available(macos 10.20, *)) { // expected-note 2 {{jump enters controlled statement of if available}}
|
||||||
|
label1:
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
label2:
|
||||||
|
goto label1; // expected-error{{cannot jump from this goto statement to its label}}
|
||||||
|
}
|
||||||
|
|
||||||
|
goto label2; // expected-error{{cannot jump from this goto statement to its label}}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
int m1;
|
||||||
|
int m2 __attribute__((availability(macos, introduced = 10.12))); // expected-note{{marked partial here}}
|
||||||
|
|
||||||
|
struct Nested {
|
||||||
|
int nested_member __attribute__((availability(macos, introduced = 10.12))); // expected-note{{marked partial here}}
|
||||||
|
} n;
|
||||||
|
};
|
||||||
|
|
||||||
|
int test_members() {
|
||||||
|
struct S s;
|
||||||
|
(void)s.m1;
|
||||||
|
(void)s.m2; // expected-warning{{'m2' is only available on macOS 10.12 or newer}} expected-note{{@available}}
|
||||||
|
|
||||||
|
(void)s.n.nested_member; // expected-warning{{'nested_member' is only available on macOS 10.12 or newer}} expected-note{{@available}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_blocks() {
|
||||||
|
(void) ^{
|
||||||
|
func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
|
||||||
|
|
||||||
|
// FIXME: This should be fine!
|
||||||
|
void test_params2(int_10_12 x) AVAILABLE_10_12; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
|
||||||
|
|
||||||
|
#ifdef OBJCPP
|
||||||
|
|
||||||
|
int f(char) AVAILABLE_10_12;
|
||||||
|
int f(int);
|
||||||
|
|
||||||
|
template <class T> int use_f() {
|
||||||
|
// FIXME: We should warn here!
|
||||||
|
return f(T());
|
||||||
|
}
|
||||||
|
|
||||||
|
int a = use_f<int>();
|
||||||
|
int b = use_f<char>();
|
||||||
|
|
||||||
|
template <class> int use_at_available() {
|
||||||
|
if (@available(macos 10.12, *))
|
||||||
|
return func_10_12();
|
||||||
|
else
|
||||||
|
return func_10_12(); // expected-warning {{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose}}
|
||||||
|
}
|
||||||
|
|
||||||
|
int instantiate_template() {
|
||||||
|
if (@available(macos 10.12, *)) {
|
||||||
|
use_at_available<char>();
|
||||||
|
} else {
|
||||||
|
use_at_available<float>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class>
|
||||||
|
int with_availability_attr() AVAILABLE_10_11 { // expected-note 2 {{marked partial here}}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int instantiate_with_availability_attr() {
|
||||||
|
if (@available(macos 10.12, *))
|
||||||
|
with_availability_attr<char>();
|
||||||
|
else
|
||||||
|
with_availability_attr<int>(); // expected-warning {{'with_availability_attr<int>' is only available on macOS 10.11 or newer}} expected-note {{enclose}}
|
||||||
|
}
|
||||||
|
|
||||||
|
int instantiate_availability() {
|
||||||
|
if (@available(macos 10.12, *))
|
||||||
|
with_availability_attr<int_10_12>();
|
||||||
|
else
|
||||||
|
with_availability_attr<int_10_12>(); // expected-warning{{'with_availability_attr<int>' is only available on macOS 10.11 or newer}} expected-warning{{'int_10_12' is only available on macOS 10.12 or newer}} expected-note 2 {{enclose}}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue