[Sema] Don't allow -Wunguarded-availability to be silenced with redecls

Differential revision: https://reviews.llvm.org/D33816

llvm-svn: 307175
This commit is contained in:
Erik Pilkington 2017-07-05 17:08:56 +00:00
parent aa5a6a1c30
commit 4042f3cf8e
13 changed files with 222 additions and 150 deletions

View File

@ -2880,7 +2880,7 @@ def warn_partial_availability : Warning<"%0 is only available conditionally">,
def warn_partial_availability_new : Warning<warn_partial_availability.Text>,
InGroup<UnguardedAvailabilityNew>;
def note_partial_availability_silence : Note<
"explicitly redeclare %0 to silence this warning">;
"annotate %select{%1|anonymous %1}0 with an availability attribute to silence">;
def note_unguarded_available_silence : Note<
"enclose %0 in %select{an @available|a __builtin_available}1 check to silence"
" this warning">;

View File

@ -124,7 +124,8 @@ public:
static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
SourceLocation Loc,
const NamedDecl *D,
const NamedDecl *ReferringDecl,
const NamedDecl *OffendingDecl,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
StringRef Msg,
@ -164,9 +165,13 @@ public:
return *reinterpret_cast<const AccessedEntity*>(AccessData);
}
const NamedDecl *getAvailabilityDecl() const {
const NamedDecl *getAvailabilityReferringDecl() const {
assert(Kind == Availability && "Not an availability diagnostic.");
return AvailabilityData.Decl;
return AvailabilityData.ReferringDecl;
}
const NamedDecl *getAvailabilityOffendingDecl() const {
return AvailabilityData.OffendingDecl;
}
StringRef getAvailabilityMessage() const {
@ -213,7 +218,8 @@ public:
private:
struct AD {
const NamedDecl *Decl;
const NamedDecl *ReferringDecl;
const NamedDecl *OffendingDecl;
const ObjCInterfaceDecl *UnknownObjCClass;
const ObjCPropertyDecl *ObjCProperty;
const char *Message;

View File

@ -3881,7 +3881,9 @@ public:
void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D,
void EmitAvailabilityWarning(AvailabilityResult AR,
const NamedDecl *ReferringDecl,
const NamedDecl *OffendingDecl,
StringRef Message, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
@ -10413,16 +10415,14 @@ public:
return OriginalLexicalContext ? OriginalLexicalContext : CurContext;
}
/// \brief The diagnostic we should emit for \c D, or \c AR_Available.
///
/// \param D The declaration to check. Note that this may be altered to point
/// to another declaration that \c D gets it's availability from. i.e., we
/// walk the list of typedefs to find an availability attribute.
/// The diagnostic we should emit for \c D, and the declaration that
/// originated it, or \c AR_Available.
///
/// \param D The declaration to check.
/// \param Message If non-null, this will be populated with the message from
/// the availability attribute that is selected.
AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D,
std::string *Message);
std::pair<AvailabilityResult, const NamedDecl *>
ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message);
const DeclContext *getCurObjCLexicalContext() const {
const DeclContext *DC = getCurLexicalContext();

View File

@ -22,7 +22,8 @@ using namespace sema;
DelayedDiagnostic
DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
SourceLocation Loc,
const NamedDecl *D,
const NamedDecl *ReferringDecl,
const NamedDecl *OffendingDecl,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
StringRef Msg,
@ -31,7 +32,8 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
DD.Kind = Availability;
DD.Triggered = false;
DD.Loc = Loc;
DD.AvailabilityData.Decl = D;
DD.AvailabilityData.ReferringDecl = ReferringDecl;
DD.AvailabilityData.OffendingDecl = OffendingDecl;
DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass;
DD.AvailabilityData.ObjCProperty = ObjCProperty;
char *MessageData = nullptr;

View File

@ -6929,8 +6929,34 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
DeclVersion >= ForceAvailabilityFromVersion;
}
static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
for (Decl *Ctx = OrigCtx; Ctx;
Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
return cast<NamedDecl>(Ctx);
if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
return Imp->getClassInterface();
return CD;
}
}
return dyn_cast<NamedDecl>(OrigCtx);
}
/// Actually emit an availability diagnostic for a reference to an unavailable
/// decl.
///
/// \param Ctx The context that the reference occurred in
/// \param ReferringDecl The exact declaration that was referenced.
/// \param OffendingDecl A related decl to \c ReferringDecl that has an
/// availability attribute corrisponding to \c K attached to it. Note that this
/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
/// and OffendingDecl is the EnumDecl.
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
Decl *Ctx, const NamedDecl *D,
Decl *Ctx, const NamedDecl *ReferringDecl,
const NamedDecl *OffendingDecl,
StringRef Message, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
@ -6938,7 +6964,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// Diagnostics for deprecated or unavailable.
unsigned diag, diag_message, diag_fwdclass_message;
unsigned diag_available_here = diag::note_availability_specified_here;
SourceLocation NoteLocation = D->getLocation();
SourceLocation NoteLocation = OffendingDecl->getLocation();
// Matches 'diag::note_property_attribute' options.
unsigned property_note_select;
@ -6947,7 +6973,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
unsigned available_here_select_kind;
VersionTuple DeclVersion;
if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D))
if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
DeclVersion = AA->getIntroduced();
if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
@ -6961,7 +6987,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
property_note_select = /* deprecated */ 0;
available_here_select_kind = /* deprecated */ 2;
if (const auto *attr = D->getAttr<DeprecatedAttr>())
if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>())
NoteLocation = attr->getLocation();
break;
@ -6973,13 +6999,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
property_note_select = /* unavailable */ 1;
available_here_select_kind = /* unavailable */ 0;
if (auto attr = D->getAttr<UnavailableAttr>()) {
if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) {
if (attr->isImplicit() && attr->getImplicitReason()) {
// Most of these failures are due to extra restrictions in ARC;
// reflect that in the primary diagnostic when applicable.
auto flagARCError = [&] {
if (S.getLangOpts().ObjCAutoRefCount &&
S.getSourceManager().isInSystemHeader(D->getLocation()))
S.getSourceManager().isInSystemHeader(
OffendingDecl->getLocation()))
diag = diag::err_unavailable_in_arc;
};
@ -7022,7 +7049,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// not specified for deployment targets >= to iOS 11 or equivalent or
// for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
// later.
const AvailabilityAttr *AA = getAttrForPlatform(S.getASTContext(), D);
const AvailabilityAttr *AA =
getAttrForPlatform(S.getASTContext(), OffendingDecl);
VersionTuple Introduced = AA->getIntroduced();
bool NewWarning = shouldDiagnoseAvailabilityByDefault(
S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
@ -7045,9 +7073,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
CharSourceRange UseRange;
StringRef Replacement;
if (K == AR_Deprecated) {
if (auto attr = D->getAttr<DeprecatedAttr>())
if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>())
Replacement = attr->getReplacement();
if (auto attr = getAttrForPlatform(S.Context, D))
if (auto attr = getAttrForPlatform(S.Context, OffendingDecl))
Replacement = attr->getReplacement();
if (!Replacement.empty())
@ -7056,21 +7084,21 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
if (!Message.empty()) {
S.Diag(Loc, diag_message) << D << Message
S.Diag(Loc, diag_message) << ReferringDecl << Message
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else if (!UnknownObjCClass) {
S.Diag(Loc, diag) << D
S.Diag(Loc, diag) << ReferringDecl
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else {
S.Diag(Loc, diag_fwdclass_message) << D
S.Diag(Loc, diag_fwdclass_message) << ReferringDecl
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
@ -7078,16 +7106,16 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// The declaration can have multiple availability attributes, we are looking
// at one of them.
const AvailabilityAttr *A = getAttrForPlatform(S.Context, D);
const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
if (A && A->isInherited()) {
for (const Decl *Redecl = D->getMostRecentDecl(); Redecl;
for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
Redecl = Redecl->getPreviousDecl()) {
const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context,
Redecl);
if (AForRedecl && !AForRedecl->isInherited()) {
// If D is a declaration with inherited attributes, the note should
// point to the declaration with actual attributes.
S.Diag(Redecl->getLocation(), diag_available_here) << D
S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl
<< available_here_select_kind;
break;
}
@ -7095,10 +7123,19 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
else
S.Diag(NoteLocation, diag_available_here)
<< D << available_here_select_kind;
<< OffendingDecl << available_here_select_kind;
if (K == AR_NotYetIntroduced)
S.Diag(Loc, diag::note_partial_availability_silence) << D;
if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
if (auto *TD = dyn_cast<TagDecl>(Enclosing))
if (TD->getDeclName().isEmpty()) {
S.Diag(TD->getLocation(), diag::note_partial_availability_silence)
<< /*Anonymous*/1 << TD->getKindName();
return;
}
S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence)
<< /*Named*/0 << Enclosing;
}
}
static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
@ -7108,9 +7145,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
DD.Triggered = true;
DoEmitAvailabilityWarning(
S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(),
DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(),
DD.getObjCProperty(), false);
S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc,
DD.getUnknownObjCClass(), DD.getObjCProperty(), false);
}
void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
@ -7169,22 +7206,25 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
}
void Sema::EmitAvailabilityWarning(AvailabilityResult AR,
NamedDecl *D, StringRef Message,
SourceLocation Loc,
const NamedDecl *ReferringDecl,
const NamedDecl *OffendingDecl,
StringRef Message, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
const ObjCPropertyDecl *ObjCProperty,
bool ObjCPropertyAccess) {
// Delay if we're currently parsing a declaration.
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
AR, Loc, D, UnknownObjCClass, ObjCProperty, Message,
ObjCPropertyAccess));
DelayedDiagnostics.add(
DelayedDiagnostic::makeAvailability(
AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass,
ObjCProperty, Message, ObjCPropertyAccess));
return;
}
Decl *Ctx = cast<Decl>(getCurLexicalContext());
DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass,
ObjCProperty, ObjCPropertyAccess);
DoEmitAvailabilityWarning(*this, AR, Ctx, ReferringDecl, OffendingDecl,
Message, Loc, UnknownObjCClass, ObjCProperty,
ObjCPropertyAccess);
}
namespace {
@ -7336,19 +7376,21 @@ public:
void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
NamedDecl *D, SourceRange Range) {
VersionTuple ContextVersion = AvailabilityStack.back();
if (AvailabilityResult Result =
SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) {
AvailabilityResult Result;
const NamedDecl *OffendingDecl;
std::tie(Result, OffendingDecl) =
SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr);
if (Result != AR_Available) {
// All other diagnostic kinds have already been handled in
// DiagnoseAvailabilityOfDecl.
if (Result != AR_NotYetIntroduced)
return;
const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D);
const AvailabilityAttr *AA =
getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
VersionTuple Introduced = AA->getIntroduced();
if (ContextVersion >= Introduced)
if (AvailabilityStack.back() >= Introduced)
return;
// If the context of this function is less available than D, we should not
@ -7373,8 +7415,9 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
SemaRef.getASTContext().getTargetInfo().getPlatformName())
<< Introduced.getAsString();
SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here)
<< D << /* partial */ 3;
SemaRef.Diag(OffendingDecl->getLocation(),
diag::note_availability_specified_here)
<< OffendingDecl << /* partial */ 3;
auto FixitDiag =
SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)

View File

@ -87,24 +87,9 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
}
}
static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) {
const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
if (!OMD)
return false;
const ObjCInterfaceDecl *OID = OMD->getClassInterface();
if (!OID)
return false;
for (const ObjCCategoryDecl *Cat : OID->visible_categories())
if (ObjCMethodDecl *CatMeth =
Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod()))
if (!CatMeth->hasAttr<AvailabilityAttr>())
return true;
return false;
}
AvailabilityResult
Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
std::pair<AvailabilityResult, const NamedDecl *>
Sema::ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D,
std::string *Message) {
AvailabilityResult Result = D->getAvailability(Message);
// For typedefs, if the typedef declaration appears available look
@ -121,45 +106,23 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
}
// Forward class declarations get their attributes from their definition.
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
if (IDecl->getDefinition()) {
D = IDecl->getDefinition();
Result = D->getAvailability(Message);
}
}
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
if (Result == AR_Available) {
const DeclContext *DC = ECD->getDeclContext();
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
Result = TheEnumDecl->getAvailability(Message);
D = TheEnumDecl;
}
}
if (Result == AR_NotYetIntroduced) {
// Don't do this for enums, they can't be redeclared.
if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
return AR_Available;
bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited();
// Objective-C method declarations in categories are not modelled as
// redeclarations, so manually look for a redeclaration in a category
// if necessary.
if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D))
Warn = false;
// In general, D will point to the most recent redeclaration. However,
// for `@class A;` decls, this isn't true -- manually go through the
// redecl chain in that case.
if (Warn && isa<ObjCInterfaceDecl>(D))
for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn;
Redecl = Redecl->getPreviousDecl())
if (!Redecl->hasAttr<AvailabilityAttr>() ||
Redecl->getAttr<AvailabilityAttr>()->isInherited())
Warn = false;
return Warn ? AR_NotYetIntroduced : AR_Available;
}
return Result;
return {Result, D};
}
static void
@ -167,32 +130,34 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
bool ObjCPropertyAccess) {
std::string Message;
AvailabilityResult Result;
const NamedDecl* OffendingDecl;
// See if this declaration is unavailable, deprecated, or partial.
if (AvailabilityResult Result =
S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) {
std::tie(Result, OffendingDecl) = S.ShouldDiagnoseAvailabilityOfDecl(D, &Message);
if (Result == AR_Available)
return;
if (Result == AR_NotYetIntroduced) {
if (S.getCurFunctionOrMethodDecl()) {
S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
return;
} else if (S.getCurBlock() || S.getCurLambda()) {
S.getCurFunction()->HasPotentialAvailabilityViolations = true;
return;
}
if (Result == AR_NotYetIntroduced) {
if (S.getCurFunctionOrMethodDecl()) {
S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
return;
} else if (S.getCurBlock() || S.getCurLambda()) {
S.getCurFunction()->HasPotentialAvailabilityViolations = true;
return;
}
const ObjCPropertyDecl *ObjCPDecl = nullptr;
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
if (PDeclResult == Result)
ObjCPDecl = PD;
}
}
S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass,
ObjCPDecl, ObjCPropertyAccess);
}
const ObjCPropertyDecl *ObjCPDecl = nullptr;
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
if (PDeclResult == Result)
ObjCPDecl = PD;
}
}
S.EmitAvailabilityWarning(Result, D, OffendingDecl, Message, Loc,
UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
}
/// \brief Emit a note explaining that this function is deleted.

View File

@ -21,6 +21,9 @@ ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduce
extern void
PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8)));
#ifdef WARN_PARTIAL
// expected-note@+2 2 {{marked partial here}}
#endif
enum __attribute__((availability(macosx,introduced=10.8))) PartialEnum {
kPartialEnumConstant,
};
@ -35,11 +38,19 @@ void test_10095131() {
PartiallyAvailable();
}
#ifdef WARN_PARTIAL
// FIXME: This note should point to the declaration with the availability
// attribute.
// expected-note@+2 {{marked partial here}}
#endif
extern void PartiallyAvailable() ;
void with_redeclaration() {
PartiallyAvailable(); // Don't warn.
// enums should never warn.
#ifdef WARN_PARTIAL
// expected-warning@+4 {{'PartiallyAvailable' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}}
// expected-warning@+4 {{'PartialEnum' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}}
// expected-warning@+3 {{'kPartialEnumConstant' is only available on macOS 10.8 or newer}} expected-note@+3 {{__builtin_available}}
#endif
PartiallyAvailable();
enum PartialEnum p = kPartialEnumConstant;
}
@ -86,13 +97,13 @@ enum Original {
OriginalUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'OriginalUnavailable' has been explicitly marked unavailable here}}
};
enum AllDeprecated {
AllDeprecatedCase, // expected-note + {{'AllDeprecatedCase' has been explicitly marked deprecated here}}
enum AllDeprecated { // expected-note + {{'AllDeprecated' has been explicitly marked deprecated here}}
AllDeprecatedCase,
AllDeprecatedUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'AllDeprecatedUnavailable' has been explicitly marked unavailable here}}
} __attribute__((availability(macosx, deprecated=10.2)));
enum AllUnavailable {
AllUnavailableCase, // expected-note + {{'AllUnavailableCase' has been explicitly marked unavailable here}}
enum AllUnavailable { // expected-note + {{'AllUnavailable' has been explicitly marked unavailable here}}
AllUnavailableCase,
} __attribute__((availability(macosx, unavailable)));
enum User {

View File

@ -104,9 +104,9 @@ foo_dep test17, // expected-warning {{'foo_dep' is deprecated}}
test19;
// rdar://problem/8518751
enum __attribute__((deprecated)) Test20 { // expected-note {{'Test20' has been explicitly marked deprecated here}}
enum __attribute__((deprecated)) Test20 { // expected-note 2 {{'Test20' has been explicitly marked deprecated here}}
test20_a __attribute__((deprecated)), // expected-note {{'test20_a' has been explicitly marked deprecated here}}
test20_b // expected-note {{'test20_b' has been explicitly marked deprecated here}}
test20_b
};
void test20() {
enum Test20 f; // expected-warning {{'Test20' is deprecated}}

View File

@ -36,13 +36,13 @@ void unavail(void) {
// rdar://10201690
enum foo {
a = 1, // expected-note {{'a' has been explicitly marked deprecated here}}
a = 1,
b __attribute__((deprecated())) = 2, // expected-note {{'b' has been explicitly marked deprecated here}}
c = 3
}__attribute__((deprecated()));
}__attribute__((deprecated())); // expected-note {{'foo' has been explicitly marked deprecated here}}
enum fee { // expected-note {{'fee' has been explicitly marked unavailable here}}
r = 1, // expected-note {{'r' has been explicitly marked unavailable here}}
enum fee { // expected-note 2 {{'fee' has been explicitly marked unavailable here}}
r = 1,
s = 2,
t = 3
}__attribute__((unavailable()));

View File

@ -199,8 +199,8 @@ namespace test5 {
// rdar://problem/8518751
namespace test6 {
enum __attribute__((deprecated)) A { // expected-note {{'A' has been explicitly marked deprecated here}}
a0 // expected-note {{'a0' has been explicitly marked deprecated here}}
enum __attribute__((deprecated)) A { // expected-note 2 {{'A' has been explicitly marked deprecated here}}
a0
};
void testA() {
A x; // expected-warning {{'A' is deprecated}}
@ -218,8 +218,8 @@ namespace test6 {
}
template <class T> struct C {
enum __attribute__((deprecated)) Enum { // expected-note {{'Enum' has been explicitly marked deprecated here}}
c0 // expected-note {{'c0' has been explicitly marked deprecated here}}
enum __attribute__((deprecated)) Enum { // expected-note 2 {{'Enum' has been explicitly marked deprecated here}}
c0
};
};
void testC() {

View File

@ -13,7 +13,7 @@
@interface A <P>
- (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{'method' has been explicitly marked deprecated here}}
#if defined(WARN_PARTIAL)
// expected-note@+2 {{'partialMethod' has been explicitly marked partial here}}
// expected-note@+2 2 {{'partialMethod' has been explicitly marked partial here}}
#endif
- (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
@ -66,7 +66,10 @@ void f(A *a, B *b) {
@end
void f_after_redecl(A *a, B *b) {
[a partialMethod]; // no warning
#ifdef WARN_PARTIAL
// expected-warning@+2{{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}}
#endif
[a partialMethod];
[b partialMethod]; // no warning
[a partial_proto_method]; // no warning
[b partial_proto_method]; // no warning
@ -133,6 +136,10 @@ id NSNibOwner, topNibObjects;
@end
@interface PartialI <PartialProt>
#ifdef WARN_PARTIAL
// expected-note@+3{{marked partial here}}
// expected-note@+3{{marked partial here}}
#endif
- (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
+ (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
@end
@ -160,14 +167,20 @@ id NSNibOwner, topNibObjects;
@end
void partialfun(PartialI* a) {
[a partialMethod]; // no warning
#ifdef WARN_PARTIAL
// expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2{{@available}}
#endif
[a partialMethod];
[a ipartialMethod1]; // no warning
#if defined(WARN_PARTIAL)
// 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
[a ipartialMethod2];
[a ppartialMethod]; // no warning
[PartialI partialMethod]; // no warning
#ifdef WARN_PARTIAL
// expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}}
#endif
[PartialI partialMethod];
[PartialI ipartialMethod1]; // no warning
#if defined(WARN_PARTIAL)
// 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}}
@ -177,20 +190,23 @@ void partialfun(PartialI* a) {
}
#if defined(WARN_PARTIAL)
// expected-note@+2 {{'PartialI2' has been explicitly marked partial here}}
// expected-note@+2 2 {{'PartialI2' has been explicitly marked partial here}}
#endif
__attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2
@end
#if defined(WARN_PARTIAL)
// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'PartialI2' to silence this warning}}
// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter1' with an availability attribute to silence}}
#endif
void partialinter1(PartialI2* p) {
}
@class PartialI2;
void partialinter2(PartialI2* p) { // no warning
#ifdef WARN_PARTIAL
// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter2' with an availability attribute to silence}}
#endif
void partialinter2(PartialI2* p) {
}

View File

@ -96,16 +96,16 @@ typedef int AVAILABLE_NEXT new_int;
FUNC_AVAILABLE new_int x;
#ifndef NO_WARNING
#ifdef MAC
// expected-warning@-3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note@-3 {{explicitly redeclare 'new_int' to silence this warning}}
// expected-warning@-3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note@-3 {{annotate 'x' with an availability attribute to silence}}
#endif
#ifdef IOS
// expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{explicitly redeclare 'new_int' to silence this warning}}
// expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{annotate 'x' with an availability attribute to silence}}
#endif
#ifdef TVOS
// expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{explicitly redeclare 'new_int' to silence this warning}}
// expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{annotate 'x' with an availability attribute to silence}}
#endif
#ifdef WATCHOS
// expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{explicitly redeclare 'new_int' to silence this warning}}
// expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{annotate 'x' with an availability attribute to silence}}
#endif
#endif

View File

@ -5,6 +5,8 @@
#define AVAILABLE_10_11 __attribute__((availability(macos, introduced = 10.11)))
#define AVAILABLE_10_12 __attribute__((availability(macos, introduced = 10.12)))
typedef int AVAILABLE_10_12 new_int; // expected-note + {{marked partial here}}
int func_10_11() AVAILABLE_10_11; // expected-note 4 {{'func_10_11' has been explicitly marked partial here}}
#ifdef OBJCPP
@ -70,9 +72,9 @@ void use_typedef() {
}
__attribute__((objc_root_class))
AVAILABLE_10_11 @interface Class_10_11 {
AVAILABLE_10_11 @interface Class_10_11 { // expected-note{{annotate 'Class_10_11' with an availability attribute to silence}}
int_10_11 foo;
int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}}
}
- (void)method1;
- (void)method2;
@ -125,7 +127,7 @@ void test_blocks() {
};
}
void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{annotate 'test_params' with an availability attribute to silence}}
void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn
@ -234,3 +236,30 @@ void functionInFunction() {
}
#endif
struct InStruct { // expected-note{{annotate 'InStruct' with an availability attribute to silence}}
new_int mem; // expected-warning{{'new_int' is partial}}
struct { new_int mem; } anon; // expected-warning{{'new_int' is partial}} expected-note{{annotate anonymous struct with an availability attribute}}
};
#ifdef OBJCPP
static constexpr int AVAILABLE_10_12 SomeConstexprValue = 2; // expected-note{{marked partial here}}
typedef enum { // expected-note{{annotate anonymous enum with an availability attribute}}
SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is partial}}
} SomeEnum;
#endif
@interface InInterface
-(new_int)meth; // expected-warning{{'new_int' is partial}} expected-note{{annotate 'meth' with an availability attribute}}
@end
@interface Proper // expected-note{{annotate 'Proper' with an availability attribute}}
@property (class) new_int x; // expected-warning{{'new_int' is partial}}
@end
void with_local_struct() {
struct local { // expected-note{{annotate 'local' with an availability attribute}}
new_int x; // expected-warning{{'new_int' is partial}}
};
}