Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2873,7 +2873,7 @@ def warn_partial_availability : Warning<"%0 is only available conditionally">, InGroup, DefaultIgnore; def note_partial_availability_silence : Note< - "explicitly redeclare %0 to silence this warning">; + "annotate %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">; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -6901,6 +6901,23 @@ return true; } +static NamedDecl *findEnclosingDeclToAnnotate(Decl *Ctx) { + while (Ctx) { + if (isa(Ctx) || isa(Ctx)) + return cast(Ctx); + if (auto *CD = dyn_cast(Ctx)) { + if (auto *Imp = dyn_cast(Ctx)) + return Imp->getClassInterface(); + return CD; + } + if (auto *MD = dyn_cast(Ctx)) + return MD; + Ctx = cast_or_null(Ctx->getDeclContext()); + } + + return nullptr; +} + static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, @@ -7057,7 +7074,9 @@ << D << available_here_select_kind; if (K == AR_NotYetIntroduced) - S.Diag(Loc, diag::note_partial_availability_silence) << D; + if (NamedDecl *Enclosing = findEnclosingDeclToAnnotate(Ctx)) + S.Diag(Enclosing->getLocStart(), diag::note_partial_availability_silence) + << Enclosing; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -87,22 +87,6 @@ } } -static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) { - const auto *OMD = dyn_cast(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()) - return true; - return false; -} - AvailabilityResult Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { AvailabilityResult Result = D->getAvailability(Message); @@ -128,37 +112,15 @@ } } - if (const EnumConstantDecl *ECD = dyn_cast(D)) + if (EnumConstantDecl *ECD = dyn_cast(D)) if (Result == AR_Available) { - const DeclContext *DC = ECD->getDeclContext(); - if (const EnumDecl *TheEnumDecl = dyn_cast(DC)) + DeclContext *DC = ECD->getDeclContext(); + if (EnumDecl *TheEnumDecl = dyn_cast(DC)) { Result = TheEnumDecl->getAvailability(Message); + D = TheEnumDecl; + } } - if (Result == AR_NotYetIntroduced) { - // Don't do this for enums, they can't be redeclared. - if (isa(D) || isa(D)) - return AR_Available; - - bool Warn = !D->getAttr()->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(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr() || - Redecl->getAttr()->isInherited()) - Warn = false; - - return Warn ? AR_NotYetIntroduced : AR_Available; - } - return Result; } Index: test/Sema/attr-availability.c =================================================================== --- test/Sema/attr-availability.c +++ test/Sema/attr-availability.c @@ -21,6 +21,9 @@ 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,18 @@ 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@+3 {{'PartiallyAvailable' is only available on macOS 10.8 or newer}} expected-note@+3 {{__builtin_available}} + // expected-warning@+3 2 {{'PartialEnum' is only available on macOS 10.8 or newer}} expected-note@+3 2 {{__builtin_available}} +#endif + PartiallyAvailable(); enum PartialEnum p = kPartialEnumConstant; } @@ -86,13 +96,13 @@ 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 { Index: test/Sema/attr-deprecated.c =================================================================== --- test/Sema/attr-deprecated.c +++ test/Sema/attr-deprecated.c @@ -104,14 +104,14 @@ 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}} f = test20_a; // expected-warning {{'test20_a' is deprecated}} - f = test20_b; // expected-warning {{'test20_b' is deprecated}} + f = test20_b; // expected-warning {{'Test20' is deprecated}} } char test21[__has_feature(attribute_deprecated_with_message) ? 1 : -1]; Index: test/Sema/attr-unavailable-message.c =================================================================== --- test/Sema/attr-unavailable-message.c +++ test/Sema/attr-unavailable-message.c @@ -36,21 +36,21 @@ // 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())); enum fee f() { // expected-error {{'fee' is unavailable}} - int i = a; // expected-warning {{'a' is deprecated}} + int i = a; // expected-warning {{'foo' is deprecated}} i = b; // expected-warning {{'b' is deprecated}} - return r; // expected-error {{'r' is unavailable}} + return r; // expected-error {{'fee' is unavailable}} } Index: test/SemaCXX/attr-deprecated.cpp =================================================================== --- test/SemaCXX/attr-deprecated.cpp +++ test/SemaCXX/attr-deprecated.cpp @@ -199,12 +199,12 @@ // 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}} - x = a0; // expected-warning {{'a0' is deprecated}} + x = a0; // expected-warning {{'A' is deprecated}} } enum B { @@ -218,13 +218,13 @@ } template 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() { C::Enum x; // expected-warning {{'Enum' is deprecated}} - x = C::c0; // expected-warning {{'c0' is deprecated}} + x = C::c0; // expected-warning {{'Enum' is deprecated}} } template struct D { Index: test/SemaObjC/attr-availability.m =================================================================== --- test/SemaObjC/attr-availability.m +++ test/SemaObjC/attr-availability.m @@ -13,7 +13,7 @@ @interface A

- (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 @@ @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 @@ @end @interface PartialI +#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,13 +167,19 @@ @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 +#ifdef WARN_PARTIAL + // expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}} +#endif [PartialI partialMethod]; // no warning [PartialI ipartialMethod1]; // no warning #if defined(WARN_PARTIAL) @@ -177,20 +190,23 @@ } #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) { } Index: test/SemaObjC/unguarded-availability.m =================================================================== --- test/SemaObjC/unguarded-availability.m +++ test/SemaObjC/unguarded-availability.m @@ -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 @@ } __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_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,23 @@ } #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 '' with an availability attribute}} +}; + +@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}} + }; +}