From: Rafael Espindola Date: Sun, 6 May 2012 19:56:25 +0000 (+0000) Subject: Split mergeAvailabilityAttr out of handleAvailabilityAttr. This is important X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3b294360febd89e3383143af086efe2014571afa;p=clang Split mergeAvailabilityAttr out of handleAvailabilityAttr. This is important for having a uniform logic for adding attributes to a decl. This in turn is needed to fix the FIXME: // FIXME: This needs to happen before we merge declarations. Then, // let attribute merging cope with attribute conflicts. ProcessDeclAttributes(S, NewFD, D, /*NonInheritable=*/false, /*Inheritable=*/true); The idea is that mergeAvailabilityAttr will become a method. Once attributes are processed before merging, it will be called from handleAvailabilityAttr to handle multiple attributes in one decl: void f(int) __attribute__((availability(ios,deprecated=3.0), availability(ios,introduced=2.0))); and from SemaDecl.cpp to handle multiple decls: void f(int) __attribute__((availability(ios,deprecated=3.0))); void f(int) __attribute__((availability(ios,introduced=2.0))); As a bonus, use the new structure to diagnose incompatible availability attributes added to different decls (see included testcases). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156269 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7680ae17df..e7960e9fe4 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1672,6 +1672,8 @@ def warn_availability_version_ordering : Warning< "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " "attribute ignored">, InGroup; +def warn_mismatched_availability: Warning< + "availability does not match previous declaration">, InGroup; // Thread Safety Attributes def warn_thread_attribute_ignored : Warning< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d1cc73c3f8..500de928bf 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1633,6 +1633,13 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { /// attribute. static bool DeclHasAttr(const Decl *D, const Attr *A) { + // There can be multiple AvailabilityAttr in a Decl. Make sure we copy + // all of them. It is mergeAvailabilityAttr in SemaDeclAttr.cpp that is + // responsible for making sure they are consistent. + const AvailabilityAttr *AA = dyn_cast(A); + if (AA) + return false; + const OwnershipAttr *OA = dyn_cast(A); const AnnotateAttr *Ann = dyn_cast(A); for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index af3fabb9d1..c0bc369012 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1690,64 +1690,143 @@ static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D, Attr.getRange(), S.Context)); } -static void handleAvailabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - IdentifierInfo *Platform = Attr.getParameterName(); - SourceLocation PlatformLoc = Attr.getParameterLoc(); - +bool checkAvailabilityAttr(Sema &S, SourceRange Range, + IdentifierInfo *Platform, + VersionTuple Introduced, + VersionTuple Deprecated, + VersionTuple Obsoleted) { StringRef PlatformName = AvailabilityAttr::getPrettyPlatformName(Platform->getName()); - if (PlatformName.empty()) { - S.Diag(PlatformLoc, diag::warn_availability_unknown_platform) - << Platform; - + if (PlatformName.empty()) PlatformName = Platform->getName(); - } - - AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); - AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); - AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); - bool IsUnavailable = Attr.getUnavailableLoc().isValid(); // Ensure that Introduced <= Deprecated <= Obsoleted (although not all // of these steps are needed). - if (Introduced.isValid() && Deprecated.isValid() && - !(Introduced.Version <= Deprecated.Version)) { - S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) - << 1 << PlatformName << Deprecated.Version.getAsString() - << 0 << Introduced.Version.getAsString(); - return; + if (!Introduced.empty() && !Deprecated.empty() && + !(Introduced <= Deprecated)) { + S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) + << 1 << PlatformName << Deprecated.getAsString() + << 0 << Introduced.getAsString(); + return true; } - if (Introduced.isValid() && Obsoleted.isValid() && - !(Introduced.Version <= Obsoleted.Version)) { - S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) - << 2 << PlatformName << Obsoleted.Version.getAsString() - << 0 << Introduced.Version.getAsString(); - return; + if (!Introduced.empty() && !Obsoleted.empty() && + !(Introduced <= Obsoleted)) { + S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) + << 2 << PlatformName << Obsoleted.getAsString() + << 0 << Introduced.getAsString(); + return true; } - if (Deprecated.isValid() && Obsoleted.isValid() && - !(Deprecated.Version <= Obsoleted.Version)) { - S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering) - << 2 << PlatformName << Obsoleted.Version.getAsString() - << 1 << Deprecated.Version.getAsString(); + if (!Deprecated.empty() && !Obsoleted.empty() && + !(Deprecated <= Obsoleted)) { + S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) + << 2 << PlatformName << Obsoleted.getAsString() + << 1 << Deprecated.getAsString(); + return true; + } + + return false; +} + +static void mergeAvailabilityAttr(Sema &S, Decl *D, SourceRange Range, + IdentifierInfo *Platform, + VersionTuple Introduced, + VersionTuple Deprecated, + VersionTuple Obsoleted, + bool IsUnavailable, + StringRef Message) { + VersionTuple MergedIntroduced; + VersionTuple MergedDeprecated; + VersionTuple MergedObsoleted; + bool FoundAny = false; + + for (specific_attr_iterator + i = D->specific_attr_begin(), + e = D->specific_attr_end(); + i != e ; ++i) { + const AvailabilityAttr *OldAA = *i; + IdentifierInfo *OldPlatform = OldAA->getPlatform(); + if (OldPlatform != Platform) + continue; + FoundAny = true; + VersionTuple OldIntroduced = OldAA->getIntroduced(); + VersionTuple OldDeprecated = OldAA->getDeprecated(); + VersionTuple OldObsoleted = OldAA->getObsoleted(); + bool OldIsUnavailable = OldAA->getUnavailable(); + StringRef OldMessage = OldAA->getMessage(); + + if ((!OldIntroduced.empty() && !Introduced.empty() && + OldIntroduced != Introduced) || + (!OldDeprecated.empty() && !Deprecated.empty() && + OldDeprecated != Deprecated) || + (!OldObsoleted.empty() && !Obsoleted.empty() && + OldObsoleted != Obsoleted) || + (OldIsUnavailable != IsUnavailable) || + (OldMessage != Message)) { + S.Diag(Range.getBegin(), diag::warn_mismatched_availability); + S.Diag(OldAA->getLocation(), diag::note_previous_attribute); + return; + } + if (MergedIntroduced.empty()) + MergedIntroduced = OldIntroduced; + if (MergedDeprecated.empty()) + MergedDeprecated = OldDeprecated; + if (MergedObsoleted.empty()) + MergedObsoleted = OldObsoleted; + } + + if (FoundAny && + MergedIntroduced == Introduced && + MergedDeprecated == Deprecated && + MergedObsoleted == Obsoleted) return; + + if (MergedIntroduced.empty()) + MergedIntroduced = Introduced; + if (MergedDeprecated.empty()) + MergedDeprecated = Deprecated; + if (MergedObsoleted.empty()) + MergedObsoleted = Obsoleted; + + if (!checkAvailabilityAttr(S, Range, Platform, MergedIntroduced, + MergedDeprecated, MergedObsoleted)) { + D->addAttr(::new (S.Context) AvailabilityAttr(Range, S.Context, + Platform, + Introduced, + Deprecated, + Obsoleted, + IsUnavailable, + Message)); } +} +static void handleAvailabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + IdentifierInfo *Platform = Attr.getParameterName(); + SourceLocation PlatformLoc = Attr.getParameterLoc(); + + if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty()) + S.Diag(PlatformLoc, diag::warn_availability_unknown_platform) + << Platform; + + AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); + AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); + AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); + bool IsUnavailable = Attr.getUnavailableLoc().isValid(); StringRef Str; const StringLiteral *SE = dyn_cast_or_null(Attr.getMessageExpr()); if (SE) Str = SE->getString(); - - D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context, - Platform, - Introduced.Version, - Deprecated.Version, - Obsoleted.Version, - IsUnavailable, - Str)); + + mergeAvailabilityAttr(S, D, Attr.getRange(), + Platform, + Introduced.Version, + Deprecated.Version, + Obsoleted.Version, + IsUnavailable, + Str); } static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c index 5fb63cd722..89252a6cc4 100644 --- a/test/Sema/attr-availability.c +++ b/test/Sema/attr-availability.c @@ -24,3 +24,16 @@ enum { NSDataWritingFileProtectionWriteOnly = 0x30000000, NSDataWritingFileProtectionCompleteUntilUserAuthentication = 0x40000000, }; + +void f4(int) __attribute__((availability(ios,deprecated=3.0))); +void f4(int) __attribute__((availability(ios,introduced=4.0))); // expected-warning {{feature cannot be deprecated in iOS version 3.0 before it was introduced in version 4.0; attribute ignored}} + +void f5(int) __attribute__((availability(ios,deprecated=3.0), // expected-warning {{feature cannot be deprecated in iOS version 3.0 before it was introduced in version 4.0; attribute ignored}} + availability(ios,introduced=4.0))); + +void f6(int) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{previous attribute is here}} +void f6(int) __attribute__((availability(ios,deprecated=4.0))); // expected-warning {{availability does not match previous declaration}} + +void f7(int) __attribute__((availability(ios,introduced=2.0))); +void f7(int) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{previous attribute is here}} +void f7(int) __attribute__((availability(ios,deprecated=4.0))); // expected-warning {{availability does not match previous declaration}}