Clang implements something we don't have: __attribute__((deprecated("message", "replacement")));
which seems pretty neat so I wrote this patch to add it to gcc. It doesn't allow the optional second argument in the standard [[]] form so as not to clash with possible future standard additions. I had hoped we could print a nice fix-it replacement hint, but that won't be possible until warn_deprecated_use gets something better than input_location. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? PR c++/102049 gcc/c-family/ChangeLog: * c-attribs.c (c_common_attribute_table): Increase max_len for deprecated. (handle_deprecated_attribute): Allow an optional second argument in the GNU form of attribute deprecated. gcc/c/ChangeLog: * c-parser.c (c_parser_std_attribute): Give a diagnostic when the standard form of an attribute deprecated has a second argument. gcc/ChangeLog: * doc/extend.texi: Document attribute deprecated with an optional second argument. * tree.c (warn_deprecated_use): Print the replacement argument, if any. gcc/testsuite/ChangeLog: * gcc.dg/c2x-attr-deprecated-3.c: Adjust dg-error. * c-c++-common/Wdeprecated-arg-1.c: New test. --- gcc/c-family/c-attribs.c | 17 ++++++++++++- gcc/c/c-parser.c | 8 ++++++ gcc/doc/extend.texi | 24 ++++++++++++++++++ .../c-c++-common/Wdeprecated-arg-1.c | 21 ++++++++++++++++ gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c | 2 +- gcc/tree.c | 25 +++++++++++++++---- 6 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Wdeprecated-arg-1.c diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 007b928c54b..ef857a9ae2c 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -409,7 +409,7 @@ const struct attribute_spec c_common_attribute_table[] = to prevent its usage in source code. */ { "no vops", 0, 0, true, false, false, false, handle_novops_attribute, NULL }, - { "deprecated", 0, 1, false, false, false, false, + { "deprecated", 0, 2, false, false, false, false, handle_deprecated_attribute, NULL }, { "unavailable", 0, 1, false, false, false, false, handle_unavailable_attribute, NULL }, @@ -4107,6 +4107,21 @@ handle_deprecated_attribute (tree *node, tree name, error ("deprecated message is not a string"); *no_add_attrs = true; } + else if (TREE_CHAIN (args) != NULL_TREE) + { + /* We allow an optional second argument in the GNU form of + attribute deprecated, which specifies the replacement. */ + if (flags & ATTR_FLAG_CXX11) + { + error ("replacement argument only allowed in GNU attributes"); + *no_add_attrs = true; + } + else if (TREE_CODE (TREE_VALUE (TREE_CHAIN (args))) != STRING_CST) + { + error ("replacement argument is not a string"); + *no_add_attrs = true; + } + } if (DECL_P (*node)) { diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index fa29d2c15fc..2b47f01d166 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -4952,6 +4952,14 @@ c_parser_std_attribute (c_parser *parser, bool for_tm) TREE_VALUE (attribute) = c_parser_attribute_arguments (parser, takes_identifier, require_string, false); + if (c_parser_next_token_is (parser, CPP_COMMA) + && strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0) + { + error_at (open_loc, "replacement argument only allowed in " + "GNU attributes"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_mark_node; + } } else c_parser_balanced_token_sequence (parser); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 9501a60f20e..7d399f4b2bc 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2860,6 +2860,7 @@ StrongAlias (allocate, alloc); @item deprecated @itemx deprecated (@var{msg}) +@itemx deprecated (@var{msg}, @var{replacement}) @cindex @code{deprecated} function attribute The @code{deprecated} attribute results in a warning if the function is used anywhere in the source file. This is useful when identifying @@ -2880,6 +2881,13 @@ results in a warning on line 3 but not line 2. The optional @var{msg} argument, which must be a string, is printed in the warning if present. +This attribute accepts an optional second argument which specifies +the replacement that ought to be used instead: + +@smallexample +int old_fn () __attribute__ ((deprecated("unsafe", "new_fn"))); +@end smallexample + The @code{deprecated} attribute can also be used for variables and types (@pxref{Variable Attributes}, @pxref{Type Attributes}.) @@ -7409,6 +7417,7 @@ attribute is also not copied. @xref{Common Function Attributes}. @item deprecated @itemx deprecated (@var{msg}) +@itemx deprecated (@var{msg}, @var{replacement}) @cindex @code{deprecated} variable attribute The @code{deprecated} attribute results in a warning if the variable is used anywhere in the source file. This is useful when identifying @@ -7429,6 +7438,13 @@ results in a warning on line 3 but not line 2. The optional @var{msg} argument, which must be a string, is printed in the warning if present. +This attribute accepts an optional second argument which specifies +the replacement that ought to be used instead: + +@smallexample +extern int old_var __attribute__ ((deprecated("unsafe", "new_var"))); +@end smallexample + The @code{deprecated} attribute can also be used for functions and types (@pxref{Common Function Attributes}, @pxref{Common Type Attributes}). @@ -8492,6 +8508,7 @@ struct __attribute__ ((copy ( (struct A *)0)) B @{ /* @r{@dots{}} */ @}; @item deprecated @itemx deprecated (@var{msg}) +@itemx deprecated (@var{msg}, @var{replacement}) @cindex @code{deprecated} type attribute The @code{deprecated} attribute results in a warning if the type is used anywhere in the source file. This is useful when identifying @@ -8522,6 +8539,13 @@ present. Control characters in the string will be replaced with escape sequences, and if the @option{-fmessage-length} option is set to 0 (its default value) then any newline characters will be ignored. +This attribute accepts an optional second argument which specifies +the replacement that ought to be used instead: + +@smallexample +typedef int oldtype __attribute__ ((deprecated("unsafe", "newtype"))); +@end smallexample + The @code{deprecated} attribute can also be used for functions and variables (@pxref{Function Attributes}, @pxref{Variable Attributes}.) diff --git a/gcc/testsuite/c-c++-common/Wdeprecated-arg-1.c b/gcc/testsuite/c-c++-common/Wdeprecated-arg-1.c new file mode 100644 index 00000000000..b03e0e42ad6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wdeprecated-arg-1.c @@ -0,0 +1,21 @@ +/* PR c++/102049 */ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +typedef int __attribute__((deprecated("obsolete", "newtype"))) oldtype; +__attribute__((deprecated("unsafe", "get_it_s"))) void get_it (int); /* { dg-message "declared here" } */ +[[gnu::deprecated("g", "")]] void g(); /* { dg-error "only allowed in GNU attributes" } */ +[[deprecated("h", "")]] void h(); /* { dg-error "only allowed in GNU attributes" } */ +__attribute__((deprecated("unsafe", 1))) void f2(); /* { dg-error "argument is not a string" } */ +__attribute__((deprecated("unsafe", "newvar"))) int oldvar; /* { dg-message "declared here" } */ + +int +main () +{ + get_it (42); /* { dg-warning "is deprecated: unsafe" } */ + /* { dg-message "use .get_it_s. instead" "" { target *-*-* } .-1 } */ + oldtype t; /* { dg-warning "is deprecated: obsolete" } */ + /* { dg-message "use .newtype. instead" "" { target *-*-* } .-1 } */ + int i = oldvar; /* { dg-warning "is deprecated: unsafe" } */ + /* { dg-message "use .newvar. instead" "" { target *-*-* } .-1 } */ +} diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c index 044725e5123..6cb70705bbf 100644 --- a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c +++ b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c @@ -6,6 +6,6 @@ [[deprecated(0)]] int b; /* { dg-error "expected" } */ -[[deprecated("", 123)]] int c; /* { dg-error "expected" } */ +[[deprecated("", 123)]] int c; /* { dg-error "only allowed in GNU attributes" } */ [[deprecated((""))]] int d; /* { dg-error "expected" } */ diff --git a/gcc/tree.c b/gcc/tree.c index 561b9cd56bd..5cb2d57a960 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -12002,8 +12002,9 @@ bool warn_deprecated_use (tree node, tree attr) { escaped_string msg; + escaped_string rep; - if (node == 0 || !warn_deprecated_decl) + if (node == NULL_TREE || !warn_deprecated_decl) return false; if (!attr) @@ -12023,7 +12024,12 @@ warn_deprecated_use (tree node, tree attr) attr = lookup_attribute ("deprecated", attr); if (attr) - msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))); + { + tree val = TREE_VALUE (attr); + msg.escape (TREE_STRING_POINTER (TREE_VALUE (val))); + if (TREE_CHAIN (val)) + rep.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_CHAIN (val)))); + } bool w = false; if (DECL_P (node)) @@ -12036,7 +12042,11 @@ warn_deprecated_use (tree node, tree attr) w = warning (OPT_Wdeprecated_declarations, "%qD is deprecated", node); if (w) - inform (DECL_SOURCE_LOCATION (node), "declared here"); + { + if (rep) + inform (input_location, "use %qs instead", (const char *) rep); + inform (DECL_SOURCE_LOCATION (node), "declared here"); + } } else if (TYPE_P (node)) { @@ -12072,8 +12082,13 @@ warn_deprecated_use (tree node, tree attr) "type is deprecated"); } - if (w && decl) - inform (DECL_SOURCE_LOCATION (decl), "declared here"); + if (w) + { + if (rep) + inform (input_location, "use %qs instead", (const char *) rep); + if (decl) + inform (DECL_SOURCE_LOCATION (decl), "declared here"); + } } return w; base-commit: f6a05b23cc2e53c38e8321ddb5d2cbe40737e506 -- 2.31.1