Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -722,7 +722,9 @@ def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, CXX11<"","deprecated", 201309>]; - let Args = [StringArgument<"Message", 1>]; + let Args = [StringArgument<"Message", 1>, + // An optional string argument that enables us to provide a Fix-It. + StringArgument<"Replacement", 1>]; let Documentation = [Undocumented]; } 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/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5127,12 +5127,27 @@ } } + // Handle the cases where the attribute has a text message. + StringRef Str, Replacement; + if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) && + !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + return; + + // Only support a single optional message for Declspec and CXX11. + if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute()) + checkAttributeAtMostNumArgs(S, Attr, 1); + else if (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())); + if (!S.getLangOpts().CPlusPlus14) if (Attr.isCXX11Attribute() && !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName(); - - handleAttrWithMessage(S, D, Attr); } static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -6198,18 +6213,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/SemaCXX/attr-deprecated-replacement-error.cpp =================================================================== --- test/SemaCXX/attr-deprecated-replacement-error.cpp +++ test/SemaCXX/attr-deprecated-replacement-error.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -verify -fsyntax-only -std=c++11 -fms-extensions %s + +#if !__has_feature(attribute_deprecated_with_replacement) +#error "Missing __has_feature" +#endif + +int a1 [[deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}} +int a2 [[deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}} + +int b1 [[gnu::deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}} +int b2 [[gnu::deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}} + +__declspec(deprecated("warning", "fixit")) int c1; // expected-error{{'deprecated' attribute takes no more than 1 argument}} +__declspec(deprecated("warning", 1)) int c2; // expected-error{{'deprecated' attribute takes no more than 1 argument}} + +int d1 __attribute__((deprecated("warning", "fixit"))); +int d2 __attribute__((deprecated("warning", 1))); // expected-error{{'deprecated' attribute requires a string}} Index: test/SemaCXX/attr-deprecated-replacement-fixit.cpp =================================================================== --- test/SemaCXX/attr-deprecated-replacement-fixit.cpp +++ test/SemaCXX/attr-deprecated-replacement-fixit.cpp @@ -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("message", "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,18 @@ // 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")]]; int b [[gnu::deprecated("warning")]]; +// CHECK: __attribute__((deprecated("", ""))); +int c __attribute__((deprecated)); + +// CHECK: int d {{\[}}[deprecated("warning")]]; +int d [[deprecated("warning")]]; + // CHECK: int cxx11_alignas alignas(4); alignas(4) int cxx11_alignas; Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -1228,6 +1228,11 @@ unsigned index = 0; for (const auto &arg : Args) { if (arg->isFake()) continue; + // Only GNU deprecated has an optional fixit argument at the second + // position. + if ((Spelling == "deprecated" || Spelling == "gnu::deprecated") && + Variety != "GNU" && index == 1) + continue; if (index++) OS << ", "; arg->writeValue(OS); }