forked from OSchip/llvm-project
Add 'nopartial' qualifier for availability attributes.
An optional nopartial can be placed after the platform name. int bar() __attribute__((availability(macosx,nopartial,introduced=10.12)) When deploying back to a platform version prior to when the declaration was introduced, with 'nopartial', Clang emits an error specifying that the function is not introduced yet; without 'nopartial', the behavior stays the same: the declaration is `weakly linked`. A member is added to the end of AttributeList to save the location of the 'nopartial' keyword. A bool member is added to AvailabilityAttr. The diagnostics for 'nopartial' not-yet-introduced is handled in the same way as we handle unavailable cases. Reviewed by Doug Gregor and Jordan Rose. rdar://23791325 llvm-svn: 261163
This commit is contained in:
parent
4083e038e9
commit
b636b904c2
|
@ -450,7 +450,8 @@ def Availability : InheritableAttr {
|
|||
let Spellings = [GNU<"availability">];
|
||||
let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">,
|
||||
VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
|
||||
BoolArgument<"unavailable">, StringArgument<"message">];
|
||||
BoolArgument<"unavailable">, StringArgument<"message">,
|
||||
BoolArgument<"nopartial">];
|
||||
let AdditionalMembers =
|
||||
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
|
||||
return llvm::StringSwitch<llvm::StringRef>(Platform)
|
||||
|
|
|
@ -685,9 +685,14 @@ are:
|
|||
Apple's watchOS operating system. The minimum deployment target is specified by
|
||||
the ``-mwatchos-version-min=*version*`` command-line argument.
|
||||
|
||||
A declaration can be used even when deploying back to a platform version prior
|
||||
to when the declaration was introduced. When this happens, the declaration is
|
||||
`weakly linked
|
||||
An optional nopartial can be placed after the platform name.
|
||||
With the optional nopartial, when deploying back to a platform version prior to
|
||||
when the declaration was introduced, Clang emits an error specifying that the
|
||||
function is not introduced yet.
|
||||
|
||||
Without the optional nopartial, a declaration can be used even when deploying back
|
||||
to a platform version prior to when the declaration was introduced. When this
|
||||
happens, the declaration is `weakly linked
|
||||
<https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html>`_,
|
||||
as if the ``weak_import`` attribute were added to the declaration. A
|
||||
weakly-linked declaration may or may not be present a run-time, and a program
|
||||
|
|
|
@ -87,6 +87,7 @@ def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
|
|||
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
||||
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
|
||||
def PartialAvailability : DiagGroup<"partial-availability">;
|
||||
def NotYetIntroducedDeclarations : DiagGroup<"not-yet-introduced-declarations">;
|
||||
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
|
||||
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
|
||||
def DeprecatedRegister : DiagGroup<"deprecated-register">;
|
||||
|
|
|
@ -837,7 +837,7 @@ def warn_accessor_property_type_mismatch : Warning<
|
|||
def not_conv_function_declared_at : Note<"type conversion function declared here">;
|
||||
def note_method_declared_at : Note<"method %0 declared here">;
|
||||
def note_property_attribute : Note<"property %0 is declared "
|
||||
"%select{deprecated|unavailable|partial}1 here">;
|
||||
"%select{deprecated|unavailable|partial|not-yet-introduced}1 here">;
|
||||
def err_setter_type_void : Error<"type of setter must be void">;
|
||||
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
|
||||
def warn_duplicate_method_decl :
|
||||
|
@ -4120,9 +4120,14 @@ def err_unavailable_message : Error<"%0 is unavailable: %1">;
|
|||
def warn_unavailable_fwdclass_message : Warning<
|
||||
"%0 may be unavailable because the receiver type is unknown">,
|
||||
InGroup<UnavailableDeclarations>;
|
||||
def err_notyetintroduced : Error<"%0 is not introduced yet">;
|
||||
def err_notyetintroduced_message : Error<"%0 is not introduced yet: %1">;
|
||||
def warn_notyetintroduced_fwdclass_message : Warning<
|
||||
"%0 may not be introduced because the receiver type is unknown">,
|
||||
InGroup<NotYetIntroducedDeclarations>;
|
||||
def note_availability_specified_here : Note<
|
||||
"%0 has been explicitly marked "
|
||||
"%select{unavailable|deleted|deprecated|partial}1 here">;
|
||||
"%select{unavailable|deleted|deprecated|partial|not-yet-introduced}1 here">;
|
||||
def note_implicitly_deleted : Note<
|
||||
"explicitly defaulted function was implicitly deleted here">;
|
||||
def note_inherited_deleted_here : Note<
|
||||
|
|
|
@ -134,6 +134,9 @@ class Parser : public CodeCompletionHandler {
|
|||
/// \brief Identifier for "message".
|
||||
IdentifierInfo *Ident_message;
|
||||
|
||||
/// \brief Identifier for "nopartial".
|
||||
IdentifierInfo *Ident_nopartial;
|
||||
|
||||
/// C++0x contextual keywords.
|
||||
mutable IdentifierInfo *Ident_final;
|
||||
mutable IdentifierInfo *Ident_override;
|
||||
|
|
|
@ -157,6 +157,17 @@ private:
|
|||
+ NumArgs)[index];
|
||||
}
|
||||
|
||||
/// The location of the 'nopartial' keyword in an availability attribute.
|
||||
SourceLocation *getNopartialSlot() {
|
||||
return reinterpret_cast<SourceLocation*>(
|
||||
&getAvailabilitySlot(ObsoletedSlot) + 1);
|
||||
}
|
||||
|
||||
SourceLocation const *getNopartialSlot() const {
|
||||
return reinterpret_cast<SourceLocation const*>(
|
||||
&getAvailabilitySlot(ObsoletedSlot) + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
struct TypeTagForDatatypeData {
|
||||
ParsedType *MatchingCType;
|
||||
|
@ -233,7 +244,7 @@ private:
|
|||
const AvailabilityChange &obsoleted,
|
||||
SourceLocation unavailable,
|
||||
const Expr *messageExpr,
|
||||
Syntax syntaxUsed)
|
||||
Syntax syntaxUsed, SourceLocation nopartial)
|
||||
: AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
|
||||
ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
|
||||
Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
|
||||
|
@ -245,6 +256,7 @@ private:
|
|||
new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
|
||||
new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
|
||||
new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
|
||||
memcpy(getNopartialSlot(), &nopartial, sizeof(SourceLocation));
|
||||
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
|
||||
}
|
||||
|
||||
|
@ -412,6 +424,11 @@ public:
|
|||
return getAvailabilitySlot(ObsoletedSlot);
|
||||
}
|
||||
|
||||
SourceLocation getNopartialLoc() const {
|
||||
assert(getKind() == AT_Availability && "Not an availability attribute");
|
||||
return *getNopartialSlot();
|
||||
}
|
||||
|
||||
SourceLocation getUnavailableLoc() const {
|
||||
assert(getKind() == AT_Availability && "Not an availability attribute");
|
||||
return UnavailableLoc;
|
||||
|
@ -488,7 +505,7 @@ public:
|
|||
AvailabilityAllocSize =
|
||||
sizeof(AttributeList)
|
||||
+ ((3 * sizeof(AvailabilityChange) + sizeof(void*) +
|
||||
sizeof(ArgsUnion) - 1)
|
||||
sizeof(ArgsUnion) + sizeof(SourceLocation) - 1)
|
||||
/ sizeof(void*) * sizeof(void*)),
|
||||
TypeTagForDatatypeAllocSize =
|
||||
sizeof(AttributeList)
|
||||
|
@ -606,13 +623,14 @@ public:
|
|||
const AvailabilityChange &obsoleted,
|
||||
SourceLocation unavailable,
|
||||
const Expr *MessageExpr,
|
||||
AttributeList::Syntax syntax) {
|
||||
AttributeList::Syntax syntax,
|
||||
SourceLocation nopartial) {
|
||||
void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
|
||||
return add(new (memory) AttributeList(attrName, attrRange,
|
||||
scopeName, scopeLoc,
|
||||
Param, introduced, deprecated,
|
||||
obsoleted, unavailable, MessageExpr,
|
||||
syntax));
|
||||
syntax, nopartial));
|
||||
}
|
||||
|
||||
AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
|
||||
|
@ -741,10 +759,12 @@ public:
|
|||
const AvailabilityChange &obsoleted,
|
||||
SourceLocation unavailable,
|
||||
const Expr *MessageExpr,
|
||||
AttributeList::Syntax syntax) {
|
||||
AttributeList::Syntax syntax,
|
||||
SourceLocation nopartial) {
|
||||
AttributeList *attr =
|
||||
pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced,
|
||||
deprecated, obsoleted, unavailable, MessageExpr, syntax);
|
||||
deprecated, obsoleted, unavailable, MessageExpr, syntax,
|
||||
nopartial);
|
||||
add(attr);
|
||||
return attr;
|
||||
}
|
||||
|
|
|
@ -113,7 +113,8 @@ private:
|
|||
/// the complete parsing of the current declaration.
|
||||
class DelayedDiagnostic {
|
||||
public:
|
||||
enum DDKind { Deprecation, Unavailable, Access, ForbiddenType };
|
||||
enum DDKind { Deprecation, Unavailable, Access, ForbiddenType,
|
||||
NotYetIntroduced };
|
||||
|
||||
unsigned char Kind; // actually a DDKind
|
||||
bool Triggered;
|
||||
|
@ -165,13 +166,15 @@ public:
|
|||
}
|
||||
|
||||
const NamedDecl *getDeprecationDecl() const {
|
||||
assert((Kind == Deprecation || Kind == Unavailable) &&
|
||||
assert((Kind == Deprecation || Kind == Unavailable ||
|
||||
Kind == NotYetIntroduced) &&
|
||||
"Not a deprecation diagnostic.");
|
||||
return DeprecationData.Decl;
|
||||
}
|
||||
|
||||
StringRef getDeprecationMessage() const {
|
||||
assert((Kind == Deprecation || Kind == Unavailable) &&
|
||||
assert((Kind == Deprecation || Kind == Unavailable ||
|
||||
Kind == NotYetIntroduced) &&
|
||||
"Not a deprecation diagnostic.");
|
||||
return StringRef(DeprecationData.Message,
|
||||
DeprecationData.MessageLen);
|
||||
|
|
|
@ -2108,6 +2108,7 @@ public:
|
|||
VersionTuple Obsoleted,
|
||||
bool IsUnavailable,
|
||||
StringRef Message,
|
||||
bool IsNopartial,
|
||||
AvailabilityMergeKind AMK,
|
||||
unsigned AttrSpellingListIndex);
|
||||
TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
|
||||
|
@ -3535,7 +3536,8 @@ public:
|
|||
|
||||
void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
|
||||
|
||||
enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable, AD_Partial };
|
||||
enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable, AD_Partial,
|
||||
AD_NotYetIntroduced };
|
||||
|
||||
void EmitAvailabilityWarning(AvailabilityDiagnostic AD,
|
||||
NamedDecl *D, StringRef Message,
|
||||
|
|
|
@ -833,11 +833,14 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
|
|||
/// \brief Parse the contents of the "availability" attribute.
|
||||
///
|
||||
/// availability-attribute:
|
||||
/// 'availability' '(' platform ',' version-arg-list, opt-message')'
|
||||
/// 'availability' '(' platform ',' opt-nopartial version-arg-list, opt-message')'
|
||||
///
|
||||
/// platform:
|
||||
/// identifier
|
||||
///
|
||||
/// opt-nopartial:
|
||||
/// 'nopartial' ','
|
||||
///
|
||||
/// version-arg-list:
|
||||
/// version-arg
|
||||
/// version-arg ',' version-arg-list
|
||||
|
@ -867,7 +870,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
return;
|
||||
}
|
||||
|
||||
// Parse the platform name,
|
||||
// Parse the platform name.
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok, diag::err_availability_expected_platform);
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
|
@ -889,10 +892,12 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
Ident_obsoleted = PP.getIdentifierInfo("obsoleted");
|
||||
Ident_unavailable = PP.getIdentifierInfo("unavailable");
|
||||
Ident_message = PP.getIdentifierInfo("message");
|
||||
Ident_nopartial = PP.getIdentifierInfo("nopartial");
|
||||
}
|
||||
|
||||
// Parse the set of introductions/deprecations/removals.
|
||||
SourceLocation UnavailableLoc;
|
||||
// Parse the optional "nopartial" and the set of
|
||||
// introductions/deprecations/removals.
|
||||
SourceLocation UnavailableLoc, NopartialLoc;
|
||||
do {
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok, diag::err_availability_expected_change);
|
||||
|
@ -902,6 +907,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
IdentifierInfo *Keyword = Tok.getIdentifierInfo();
|
||||
SourceLocation KeywordLoc = ConsumeToken();
|
||||
|
||||
if (Keyword == Ident_nopartial) {
|
||||
if (NopartialLoc.isValid()) {
|
||||
Diag(KeywordLoc, diag::err_availability_redundant)
|
||||
<< Keyword << SourceRange(NopartialLoc);
|
||||
}
|
||||
NopartialLoc = KeywordLoc;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Keyword == Ident_unavailable) {
|
||||
if (UnavailableLoc.isValid()) {
|
||||
Diag(KeywordLoc, diag::err_availability_redundant)
|
||||
|
@ -1023,7 +1037,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
Changes[Deprecated],
|
||||
Changes[Obsoleted],
|
||||
UnavailableLoc, MessageExpr.get(),
|
||||
Syntax);
|
||||
Syntax, NopartialLoc);
|
||||
}
|
||||
|
||||
/// \brief Parse the contents of the "objc_bridge_related" attribute.
|
||||
|
|
|
@ -491,6 +491,7 @@ void Parser::Initialize() {
|
|||
Ident_deprecated = nullptr;
|
||||
Ident_obsoleted = nullptr;
|
||||
Ident_unavailable = nullptr;
|
||||
Ident_nopartial = nullptr;
|
||||
|
||||
Ident__except = nullptr;
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD,
|
|||
case Sema::AD_Unavailable:
|
||||
DD.Kind = Unavailable;
|
||||
break;
|
||||
case Sema::AD_NotYetIntroduced:
|
||||
DD.Kind = NotYetIntroduced;
|
||||
break;
|
||||
case Sema::AD_Partial:
|
||||
llvm_unreachable("AD_Partial diags should not be delayed");
|
||||
}
|
||||
|
@ -63,6 +66,7 @@ void DelayedDiagnostic::Destroy() {
|
|||
|
||||
case Deprecation:
|
||||
case Unavailable:
|
||||
case NotYetIntroduced:
|
||||
delete [] DeprecationData.Message;
|
||||
break;
|
||||
|
||||
|
|
|
@ -2196,7 +2196,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
|||
NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
|
||||
AA->getIntroduced(), AA->getDeprecated(),
|
||||
AA->getObsoleted(), AA->getUnavailable(),
|
||||
AA->getMessage(), AMK,
|
||||
AA->getMessage(), AA->getNopartial(), AMK,
|
||||
AttrSpellingListIndex);
|
||||
else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
|
||||
NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
|
||||
|
|
|
@ -1916,6 +1916,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
|
|||
VersionTuple Obsoleted,
|
||||
bool IsUnavailable,
|
||||
StringRef Message,
|
||||
bool IsNopartial,
|
||||
AvailabilityMergeKind AMK,
|
||||
unsigned AttrSpellingListIndex) {
|
||||
VersionTuple MergedIntroduced = Introduced;
|
||||
|
@ -2062,7 +2063,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
|
|||
return ::new (Context) AvailabilityAttr(Range, Context, Platform,
|
||||
Introduced, Deprecated,
|
||||
Obsoleted, IsUnavailable, Message,
|
||||
AttrSpellingListIndex);
|
||||
IsNopartial, AttrSpellingListIndex);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2089,6 +2090,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
|||
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
|
||||
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
|
||||
bool IsUnavailable = Attr.getUnavailableLoc().isValid();
|
||||
bool IsNopartial = Attr.getNopartialLoc().isValid();
|
||||
StringRef Str;
|
||||
if (const StringLiteral *SE =
|
||||
dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr()))
|
||||
|
@ -2099,6 +2101,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
|||
Deprecated.Version,
|
||||
Obsoleted.Version,
|
||||
IsUnavailable, Str,
|
||||
IsNopartial,
|
||||
Sema::AMK_None,
|
||||
Index);
|
||||
if (NewAttr)
|
||||
|
@ -2143,6 +2146,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
|||
NewDeprecated,
|
||||
NewObsoleted,
|
||||
IsUnavailable, Str,
|
||||
IsNopartial,
|
||||
Sema::AMK_None,
|
||||
Index);
|
||||
if (NewAttr)
|
||||
|
@ -2165,6 +2169,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
|||
Deprecated.Version,
|
||||
Obsoleted.Version,
|
||||
IsUnavailable, Str,
|
||||
IsNopartial,
|
||||
Sema::AMK_None,
|
||||
Index);
|
||||
if (NewAttr)
|
||||
|
@ -5957,6 +5962,14 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
|
|||
property_note_select = /* partial */ 2;
|
||||
available_here_select_kind = /* partial */ 3;
|
||||
break;
|
||||
|
||||
case Sema::AD_NotYetIntroduced:
|
||||
diag = diag::err_notyetintroduced;
|
||||
diag_message = diag::err_notyetintroduced_message;
|
||||
diag_fwdclass_message = diag::warn_notyetintroduced_fwdclass_message;
|
||||
property_note_select = /* deprecated */ 3;
|
||||
available_here_select_kind = /* notyetintroduced */ 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Message.empty()) {
|
||||
|
@ -5983,10 +5996,22 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
|
|||
static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
|
||||
Decl *Ctx) {
|
||||
assert(DD.Kind == DelayedDiagnostic::Deprecation ||
|
||||
DD.Kind == DelayedDiagnostic::Unavailable);
|
||||
Sema::AvailabilityDiagnostic AD = DD.Kind == DelayedDiagnostic::Deprecation
|
||||
? Sema::AD_Deprecation
|
||||
: Sema::AD_Unavailable;
|
||||
DD.Kind == DelayedDiagnostic::Unavailable ||
|
||||
DD.Kind == DelayedDiagnostic::NotYetIntroduced);
|
||||
Sema::AvailabilityDiagnostic AD;
|
||||
switch (DD.Kind) {
|
||||
case DelayedDiagnostic::Deprecation:
|
||||
AD = Sema::AD_Deprecation;
|
||||
break;
|
||||
case DelayedDiagnostic::Unavailable:
|
||||
AD = Sema::AD_Unavailable;
|
||||
break;
|
||||
case DelayedDiagnostic::NotYetIntroduced:
|
||||
AD = Sema::AD_NotYetIntroduced;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Expecting: deprecated, unavailable, not-yet-introduced");
|
||||
}
|
||||
DD.Triggered = true;
|
||||
DoEmitAvailabilityWarning(
|
||||
S, AD, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc,
|
||||
|
|
|
@ -137,7 +137,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
|||
|
||||
const ObjCPropertyDecl *ObjCPDecl = nullptr;
|
||||
if (Result == AR_Deprecated || Result == AR_Unavailable ||
|
||||
AR_NotYetIntroduced) {
|
||||
Result == AR_NotYetIntroduced) {
|
||||
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
|
||||
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
|
||||
|
@ -159,11 +159,20 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
|||
break;
|
||||
|
||||
case AR_NotYetIntroduced: {
|
||||
// With nopartial, the compiler will emit delayed error just like how
|
||||
// "deprecated, unavailable" are handled.
|
||||
AvailabilityAttr *AA = D->getAttr<AvailabilityAttr>();
|
||||
if (AA && AA->getNopartial() &&
|
||||
S.getCurContextAvailability() != AR_NotYetIntroduced)
|
||||
S.EmitAvailabilityWarning(Sema::AD_NotYetIntroduced,
|
||||
D, Message, Loc, UnknownObjCClass, ObjCPDecl,
|
||||
ObjCPropertyAccess);
|
||||
|
||||
// Don't do this for enums, they can't be redeclared.
|
||||
if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
|
||||
break;
|
||||
|
||||
bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited();
|
||||
bool Warn = !AA->isInherited();
|
||||
// Objective-C method declarations in categories are not modelled as
|
||||
// redeclarations, so manually look for a redeclaration in a category
|
||||
// if necessary.
|
||||
|
|
|
@ -6,6 +6,7 @@ void f2(int) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5)
|
|||
void f3(int) __attribute__((availability(macosx,introduced=10.6)));
|
||||
void f4(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(ios,introduced=2.0,deprecated=3.0))); // expected-note{{explicitly marked unavailable}}
|
||||
void f5(int) __attribute__((availability(ios,introduced=3.2), availability(macosx,unavailable))); // expected-note{{'f5' has been explicitly marked unavailable here}}
|
||||
void f6(int) __attribute__((availability(macosx,nopartial,introduced=10.6))); //expected-note{{'f6' has been explicitly marked not-yet-introduced here}}
|
||||
|
||||
void test() {
|
||||
f0(0);
|
||||
|
@ -14,6 +15,7 @@ void test() {
|
|||
f3(0);
|
||||
f4(0); // expected-error{{f4' is unavailable: obsoleted in OS X 10.5}}
|
||||
f5(0); // expected-error{{'f5' is unavailable: not available on OS X}}
|
||||
f6(0); // expected-error{{'f6' is not introduced yet: introduced in OS X 10.6}}
|
||||
}
|
||||
|
||||
// rdar://10535640
|
||||
|
|
Loading…
Reference in New Issue