Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -711,7 +711,8 @@ def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, CXX11<"","deprecated", 201309>]; - let Args = [StringArgument<"Message", 1>]; + let Args = [StringArgument<"Message", 1>, + StringArgument<"Replacement", 1>]; let Documentation = [Undocumented]; } Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -137,6 +137,9 @@ /// \brief Identifier for "strict". IdentifierInfo *Ident_strict; + /// \brief Identifier for "replacement". + IdentifierInfo *Ident_replacement; + /// C++0x contextual keywords. mutable IdentifierInfo *Ident_final; mutable IdentifierInfo *Ident_override; @@ -2222,6 +2225,14 @@ SourceLocation ScopeLoc, AttributeList::Syntax Syntax); + unsigned ParseDeprecatedAttribute(IdentifierInfo &Deprecated, + SourceLocation DeprecatedLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax); + void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated, SourceLocation ObjCBridgeRelatedLoc, ParsedAttributes &attrs, Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -1079,6 +1079,7 @@ .Case("attribute_cf_returns_retained", true) .Case("attribute_cf_returns_on_parameters", true) .Case("attribute_deprecated_with_message", true) + .Case("attribute_deprecated_with_replacement", true) .Case("attribute_ext_vector_type", true) .Case("attribute_ns_returns_not_retained", true) .Case("attribute_ns_returns_retained", true) Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -349,6 +349,10 @@ ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Syntax); return; + } else if (AttrKind == AttributeList::AT_Deprecated) { + ParseDeprecatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, + ScopeLoc, Syntax); + return; } else if (AttrKind == AttributeList::AT_ObjCBridgeRelated) { ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Syntax); @@ -1040,6 +1044,65 @@ Syntax, StrictLoc); } +/// \brief Parse the contents of the "deprecated" attribute. +unsigned Parser::ParseDeprecatedAttribute(IdentifierInfo &Deprecated, + SourceLocation DeprecatedLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax) { + // Ignore the left paren location for now. + ConsumeParen(); + + if (!Ident_replacement) + Ident_replacement = PP.getIdentifierInfo("replacement"); + + ExprResult ReplacementExpr, MessageExpr; + if (Tok.isNot(tok::r_paren)) { + do { + if (Tok.is(tok::identifier)) { + IdentifierInfo *Keyword = Tok.getIdentifierInfo(); + ConsumeToken(); + if (Keyword != Ident_replacement) { + } + + if (Tok.isNot(tok::equal)) { + Diag(Tok, diag::err_expected_after) << Keyword << tok::equal; + SkipUntil(tok::r_paren, StopAtSemi); + return 0; + } + ConsumeToken(); + + if (Tok.isNot(tok::string_literal)) { + Diag(Tok, diag::err_expected_string_literal) + << /*Source='availability attribute'*/2; + SkipUntil(tok::r_paren, StopAtSemi); + return 0; + } + ReplacementExpr = ParseStringLiteralExpression(); + } else if (Tok.is(tok::string_literal)) { + MessageExpr = ParseStringLiteralExpression(true); + } + } while (TryConsumeToken(tok::comma)); + } + + SourceLocation RParen = Tok.getLocation(); + ArgsVector ArgExprs; + if (!ExpectAndConsume(tok::r_paren)) { + ArgExprs.push_back(MessageExpr.get()); + ArgExprs.push_back(ReplacementExpr.get()); + SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : DeprecatedLoc; + Attrs.addNew(&Deprecated, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, + ArgExprs.data(), ArgExprs.size(), Syntax); + } + + if (EndLoc) + *EndLoc = RParen; + + return static_cast(ArgExprs.size()); +} + /// \brief Parse the contents of the "objc_bridge_related" attribute. /// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')' /// related_class: Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -492,6 +492,7 @@ Ident_obsoleted = nullptr; Ident_unavailable = nullptr; Ident_strict = nullptr; + Ident_replacement = nullptr; Ident__except = nullptr; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5068,7 +5068,18 @@ !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) S.Diag(Attr.getLoc(), diag::ext_deprecated_attr_is_a_cxx14_extension); - handleAttrWithMessage(S, D, Attr); + // Handle the cases where the attribute has a text message or a replacement + // string, or both. + StringRef Str, Replacement; + if ((Attr.isArgExpr(0) && Attr.getArgAsExpr(0) && + !S.checkStringLiteralArgumentAttr(Attr, 0, Str))|| + (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) && + !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement))) + return; + + D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str, + Replacement, + Attr.getAttributeSpellingListIndex())); } static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -6126,18 +6137,35 @@ break; } + CharSourceRange UseRange; + StringRef Replacement; + if (K == Sema::AD_Deprecation) { + if (auto attr = D->getAttr()) + Replacement = attr->getReplacement(); + + if (!Replacement.empty()) + UseRange = + CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + } + if (!Message.empty()) { - S.Diag(Loc, diag_message) << D << Message; + S.Diag(Loc, diag_message) << D << Message + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << D; + S.Diag(Loc, diag) << D + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << D; + S.Diag(Loc, diag_fwdclass_message) << D + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } Index: test/Sema/attr-availability-replacement.c =================================================================== --- test/Sema/attr-availability-replacement.c +++ test/Sema/attr-availability-replacement.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: cp %s %t +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fixit %t +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -Werror %t + +#if !__has_feature(attribute_deprecated_with_replacement) +#error "Missing __has_feature" +#endif + +void f_8(int) __attribute__((deprecated(replacement="new8"))); // expected-note {{'f_8' has been explicitly marked deprecated here}} +void new8(int); +void test() { + f_8(0); // expected-warning{{'f_8' is deprecated}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:6}:"new8" +} Index: test/SemaCXX/cxx11-attr-print.cpp =================================================================== --- test/SemaCXX/cxx11-attr-print.cpp +++ test/SemaCXX/cxx11-attr-print.cpp @@ -10,12 +10,15 @@ // CHECK: int z {{\[}}[gnu::aligned(4)]]; int z [[gnu::aligned(4)]]; -// CHECK: __attribute__((deprecated("warning"))); +// CHECK: __attribute__((deprecated("warning", ""))); int a __attribute__((deprecated("warning"))); -// CHECK: int b {{\[}}[gnu::deprecated("warning")]]; +// CHECK: int b {{\[}}[gnu::deprecated("warning", "")]]; int b [[gnu::deprecated("warning")]]; +// CHECK: __attribute__((deprecated("", ""))); +int c __attribute__((deprecated)); + // CHECK: int cxx11_alignas alignas(4); alignas(4) int cxx11_alignas;