forked from OSchip/llvm-project
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). llvm-svn: 156269
This commit is contained in:
parent
00a1e6d48b
commit
2d243bfe2f
|
@ -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<Availability>;
|
||||
def warn_mismatched_availability: Warning<
|
||||
"availability does not match previous declaration">, InGroup<Availability>;
|
||||
|
||||
// Thread Safety Attributes
|
||||
def warn_thread_attribute_ignored : Warning<
|
||||
|
|
|
@ -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<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)
|
||||
|
|
|
@ -1690,64 +1690,143 @@ static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
|
|||
Attr.getRange(), S.Context));
|
||||
}
|
||||
|
||||
bool checkAvailabilityAttr(Sema &S, SourceRange Range,
|
||||
IdentifierInfo *Platform,
|
||||
VersionTuple Introduced,
|
||||
VersionTuple Deprecated,
|
||||
VersionTuple Obsoleted) {
|
||||
StringRef PlatformName
|
||||
= AvailabilityAttr::getPrettyPlatformName(Platform->getName());
|
||||
if (PlatformName.empty())
|
||||
PlatformName = Platform->getName();
|
||||
|
||||
// Ensure that Introduced <= Deprecated <= Obsoleted (although not all
|
||||
// of these steps are needed).
|
||||
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.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.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();
|
||||
|
||||
StringRef PlatformName
|
||||
= AvailabilityAttr::getPrettyPlatformName(Platform->getName());
|
||||
if (PlatformName.empty()) {
|
||||
if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty())
|
||||
S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
|
||||
<< Platform;
|
||||
|
||||
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.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 (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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue