[cfe-commits] r156269 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp test/Sema/attr-availability.c
Rafael Espindola
rafael.espindola at gmail.com
Sun May 6 12:56:25 PDT 2012
Author: rafael
Date: Sun May 6 14:56:25 2012
New Revision: 156269
URL: http://llvm.org/viewvc/llvm-project?rev=156269&view=rev
Log:
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).
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/test/Sema/attr-availability.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=156269&r1=156268&r2=156269&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun May 6 14:56:25 2012
@@ -1672,6 +1672,8 @@
"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<Availability>;
+def warn_mismatched_availability: Warning<
+ "availability does not match previous declaration">, InGroup<Availability>;
// Thread Safety Attributes
def warn_thread_attribute_ignored : Warning<
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=156269&r1=156268&r2=156269&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun May 6 14:56:25 2012
@@ -1633,6 +1633,13 @@
/// 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<AvailabilityAttr>(A);
+ if (AA)
+ return false;
+
const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=156269&r1=156268&r2=156269&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Sun May 6 14:56:25 2012
@@ -1690,64 +1690,143 @@
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();
- return;
+ 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<AvailabilityAttr>
+ i = D->specific_attr_begin<AvailabilityAttr>(),
+ e = D->specific_attr_end<AvailabilityAttr>();
+ 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<const StringLiteral>(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) {
Modified: cfe/trunk/test/Sema/attr-availability.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-availability.c?rev=156269&r1=156268&r2=156269&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-availability.c (original)
+++ cfe/trunk/test/Sema/attr-availability.c Sun May 6 14:56:25 2012
@@ -24,3 +24,16 @@
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}}
More information about the cfe-commits
mailing list