aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2011-12-10 00:28:41 +0000
committerFariborz Jahanian <fjahanian@apple.com>2011-12-10 00:28:41 +0000
commit006e42f0c8b65b783d565ef10b938a9e82fc02e3 (patch)
treef541c4d72facab26b9a3ca324fa9566e46310453
parentd937c21f53587e6481589553ab4f7b557ebb6337 (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.td2
-rw-r--r--include/clang/Parse/Parser.h3
-rw-r--r--include/clang/Sema/AttributeList.h18
-rw-r--r--lib/AST/DeclBase.cpp17
-rw-r--r--lib/Parse/ParseDecl.cpp20
-rw-r--r--lib/Sema/SemaDeclAttr.cpp9
-rw-r--r--test/Parser/attr-availability.c8
-rw-r--r--test/Sema/attr-availability.c12
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}}
+}