diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2011-12-10 00:28:41 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2011-12-10 00:28:41 +0000 |
commit | 006e42f0c8b65b783d565ef10b938a9e82fc02e3 (patch) | |
tree | f541c4d72facab26b9a3ca324fa9566e46310453 | |
parent | d937c21f53587e6481589553ab4f7b557ebb6337 (diff) |
Add ability to supply additional message to availability macros,
// rdar://10095131
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146304 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/Attr.td | 2 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 3 | ||||
-rw-r--r-- | include/clang/Sema/AttributeList.h | 18 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 17 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 9 | ||||
-rw-r--r-- | test/Parser/attr-availability.c | 8 | ||||
-rw-r--r-- | test/Sema/attr-availability.c | 12 |
8 files changed, 76 insertions, 13 deletions
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 2a4ba5c6c7..0839df8baf 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -146,7 +146,7 @@ def Availability : InheritableAttr { let Spellings = ["availability"]; let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">, VersionArgument<"deprecated">, VersionArgument<"obsoleted">, - BoolArgument<"unavailable">]; + BoolArgument<"unavailable">, StringArgument<"message">]; let AdditionalMembers = [{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) { return llvm::StringSwitch<llvm::StringRef>(Platform) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0ebf9c3a70..a60800630e 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -147,6 +147,9 @@ class Parser : public CodeCompletionHandler { /// \brief Identifier for "unavailable". IdentifierInfo *Ident_unavailable; + + /// \brief Identifier for "message". + IdentifierInfo *Ident_message; /// C++0x contextual keywords. mutable IdentifierInfo *Ident_final; diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index bcacf7aa14..0c64e2c487 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -85,6 +85,8 @@ private: /// \brief The location of the 'unavailable' keyword in an /// availability attribute. SourceLocation UnavailableLoc; + + const Expr *MessageExpr; /// The next attribute in the current position. AttributeList *NextInPosition; @@ -138,13 +140,15 @@ private: const AvailabilityChange &introduced, const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, - SourceLocation unavailable, + SourceLocation unavailable, + const Expr *messageExpr, bool declspec, bool cxx0x) : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), - UnavailableLoc(unavailable), NextInPosition(0), NextInPool(0) { + UnavailableLoc(unavailable), MessageExpr(messageExpr), + NextInPosition(0), NextInPool(0) { new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated); new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted); @@ -371,6 +375,11 @@ public: assert(getKind() == AT_availability && "Not an availability attribute"); return UnavailableLoc; } + + const Expr * getMessageExpr() const { + assert(getKind() == AT_availability && "Not an availability attribute"); + return MessageExpr; + } }; /// A factory, from which one makes pools, from which one creates @@ -492,13 +501,14 @@ public: const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, + const Expr *MessageExpr, bool declspec = false, bool cxx0x = false) { void *memory = allocate(AttributeFactory::AvailabilityAllocSize); return add(new (memory) AttributeList(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, introduced, deprecated, obsoleted, - unavailable, + unavailable, MessageExpr, declspec, cxx0x)); } @@ -616,10 +626,12 @@ public: const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, + const Expr *MessageExpr, bool declspec = false, bool cxx0x = false) { AttributeList *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, introduced, deprecated, obsoleted, unavailable, + MessageExpr, declspec, cxx0x); add(attr); return attr; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 37e0892c5c..b7941506b0 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -282,13 +282,20 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, // Match the platform name. if (A->getPlatform()->getName() != TargetPlatform) return AR_Available; - + + std::string HintMessage; + if (!A->getMessage().empty()) { + HintMessage = " - "; + HintMessage += A->getMessage(); + } + // Make sure that this declaration has not been marked 'unavailable'. if (A->getUnavailable()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); - Out << "not available on " << PrettyPlatformName; + Out << "not available on " << PrettyPlatformName + << HintMessage; } return AR_Unavailable; @@ -301,7 +308,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, Message->clear(); llvm::raw_string_ostream Out(*Message); Out << "introduced in " << PrettyPlatformName << ' ' - << A->getIntroduced(); + << A->getIntroduced() << HintMessage; } return AR_NotYetIntroduced; @@ -313,7 +320,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, Message->clear(); llvm::raw_string_ostream Out(*Message); Out << "obsoleted in " << PrettyPlatformName << ' ' - << A->getObsoleted(); + << A->getObsoleted() << HintMessage; } return AR_Unavailable; @@ -325,7 +332,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, Message->clear(); llvm::raw_string_ostream Out(*Message); Out << "first deprecated in " << PrettyPlatformName << ' ' - << A->getDeprecated(); + << A->getDeprecated() << HintMessage; } return AR_Deprecated; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 61048f54e4..ff3084d0cb 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -522,7 +522,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { /// \brief Parse the contents of the "availability" attribute. /// /// availability-attribute: -/// 'availability' '(' platform ',' version-arg-list ')' +/// 'availability' '(' platform ',' version-arg-list, opt-message')' /// /// platform: /// identifier @@ -536,6 +536,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { /// 'deprecated' '=' version /// 'removed' = version /// 'unavailable' +/// opt-message: +/// 'message' '=' <string> void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, @@ -545,6 +547,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; + ExprResult MessageExpr; // Opening '('. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -573,6 +576,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Ident_deprecated = PP.getIdentifierInfo("deprecated"); Ident_obsoleted = PP.getIdentifierInfo("obsoleted"); Ident_unavailable = PP.getIdentifierInfo("unavailable"); + Ident_message = PP.getIdentifierInfo("message"); } // Parse the set of introductions/deprecations/removals. @@ -599,7 +603,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, ConsumeToken(); continue; } - + if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_equal_after) << Keyword; @@ -607,6 +611,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, return; } ConsumeToken(); + if (Keyword == Ident_message) { + if (!isTokenStringLiteral()) { + Diag(Tok, diag::err_expected_string_literal); + SkipUntil(tok::r_paren); + return; + } + MessageExpr = ParseStringLiteralExpression(); + break; + } SourceRange VersionRange; VersionTuple Version = ParseVersionTuple(VersionRange); @@ -682,7 +695,8 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], - UnavailableLoc, false, false); + UnavailableLoc, MessageExpr.take(), + false, false); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index e60cd63369..63714fdfa7 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1624,12 +1624,19 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, 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)); + IsUnavailable, + Str)); } static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { diff --git a/test/Parser/attr-availability.c b/test/Parser/attr-availability.c index 269f90847d..7b00f06ca5 100644 --- a/test/Parser/attr-availability.c +++ b/test/Parser/attr-availability.c @@ -18,3 +18,11 @@ void f5() __attribute__((availability(macosx,introduced=10.5), availability(ios, void f6() __attribute__((availability(macosx,unavailable,introduced=10.5))); // expected-warning{{warning: 'unavailable' availability overrides all other availability information}} +// rdar://10095131 +enum E{ + gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal}} + garf __attribute__((availability(macosx,introduced=8.5, message))), // expected-error {{expected '=' after 'message'}} + + foo __attribute__((availability(macosx,introduced=8.5,deprecated=9.0, message="Use CTFontCopyPostScriptName()", deprecated=10.0))) // expected-error {{expected ')'}} \ + // expected-note {{to match this '('}} +}; diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c index f6ed13190e..4dfe65d3d6 100644 --- a/test/Sema/attr-availability.c +++ b/test/Sema/attr-availability.c @@ -5,3 +5,15 @@ void f1() __attribute__((availability(ios,obsoleted=2.1,deprecated=3.0))); // e void f2() __attribute__((availability(ios,introduced=2.1,deprecated=2.1))); void f3() __attribute__((availability(otheros,introduced=2.2))); // expected-warning{{unknown platform 'otheros' in availability macro}} + +// rdar://10095131 +extern void +ATSFontGetName(const char *oName) __attribute__((availability(macosx,introduced=8.0,deprecated=9.0, message="use CTFontCopyFullName"))); + +extern void +ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduced=8.0,obsoleted=9.0, message="use ATSFontGetFullPostScriptName"))); // expected-note {{function has been explicitly marked unavailable here}} + +void test_10095131() { + ATSFontGetName("Hello"); // expected-warning {{'ATSFontGetName' is deprecated: first deprecated in Mac OS X 9.0 - use CTFontCopyFullName}} + ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in Mac OS X 9.0 - use ATSFontGetFullPostScriptName}} +} |