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 "
|
"feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version "
|
||||||
"%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
|
"%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
|
||||||
"attribute ignored">, InGroup<Availability>;
|
"attribute ignored">, InGroup<Availability>;
|
||||||
|
def warn_mismatched_availability: Warning<
|
||||||
|
"availability does not match previous declaration">, InGroup<Availability>;
|
||||||
|
|
||||||
// Thread Safety Attributes
|
// Thread Safety Attributes
|
||||||
def warn_thread_attribute_ignored : Warning<
|
def warn_thread_attribute_ignored : Warning<
|
||||||
|
|
|
@ -1633,6 +1633,13 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
|
||||||
/// attribute.
|
/// attribute.
|
||||||
static bool
|
static bool
|
||||||
DeclHasAttr(const Decl *D, const Attr *A) {
|
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 OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
|
||||||
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
|
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
|
||||||
for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
|
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));
|
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,
|
static void handleAvailabilityAttr(Sema &S, Decl *D,
|
||||||
const AttributeList &Attr) {
|
const AttributeList &Attr) {
|
||||||
IdentifierInfo *Platform = Attr.getParameterName();
|
IdentifierInfo *Platform = Attr.getParameterName();
|
||||||
SourceLocation PlatformLoc = Attr.getParameterLoc();
|
SourceLocation PlatformLoc = Attr.getParameterLoc();
|
||||||
|
|
||||||
StringRef PlatformName
|
if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty())
|
||||||
= AvailabilityAttr::getPrettyPlatformName(Platform->getName());
|
|
||||||
if (PlatformName.empty()) {
|
|
||||||
S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
|
S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
|
||||||
<< Platform;
|
<< Platform;
|
||||||
|
|
||||||
PlatformName = Platform->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
|
AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
|
||||||
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
|
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
|
||||||
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
|
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
|
||||||
bool IsUnavailable = Attr.getUnavailableLoc().isValid();
|
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;
|
StringRef Str;
|
||||||
const StringLiteral *SE =
|
const StringLiteral *SE =
|
||||||
dyn_cast_or_null<const StringLiteral>(Attr.getMessageExpr());
|
dyn_cast_or_null<const StringLiteral>(Attr.getMessageExpr());
|
||||||
if (SE)
|
if (SE)
|
||||||
Str = SE->getString();
|
Str = SE->getString();
|
||||||
|
|
||||||
D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context,
|
mergeAvailabilityAttr(S, D, Attr.getRange(),
|
||||||
Platform,
|
Platform,
|
||||||
Introduced.Version,
|
Introduced.Version,
|
||||||
Deprecated.Version,
|
Deprecated.Version,
|
||||||
Obsoleted.Version,
|
Obsoleted.Version,
|
||||||
IsUnavailable,
|
IsUnavailable,
|
||||||
Str));
|
Str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||||
|
|
|
@ -24,3 +24,16 @@ enum {
|
||||||
NSDataWritingFileProtectionWriteOnly = 0x30000000,
|
NSDataWritingFileProtectionWriteOnly = 0x30000000,
|
||||||
NSDataWritingFileProtectionCompleteUntilUserAuthentication = 0x40000000,
|
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