If I mark a class with the [[deprecated]] annotation, it complains when the class uses its own name in the implementation: class [[deprecated]] C { public: C() {} C(const C&) = default; // emits a deprecation warning C(C&&) = delete; // also emits a warning };
Additionally, any external use of a static method of a deprecated class should probably (but does not currently) emit a warning (Clang emits a warning). class [[deprecated]] C { public: void fn() {} }; int main() { C::fn(); // does not emit a deprecation warning }
See also bug 79817.
Confirmed with the following simplified C++ 98 test case: $ cat pr84222.C && gcc -O2 -c -g -Wall pr84222.C struct __attribute__ ((deprecated)) C { C() {} C(const C&); // emits a deprecation warning }; pr84222.C:3:15: warning: ‘C’ is deprecated [-Wdeprecated-declarations] C(const C&); // emits a deprecation warning ^ It's a very old regression introduced in GCC 4.3. The likely candidate is r128691: PR c++/16370 * decl.c (grokdeclarator): Look through implicit TYPE_DECLs for deprecation warnings.
This is a subset of bug 79078 that lists a number of problems with the handling of attribute deprecated. I'm keeping this one open independent of the latter since this is a regression.
With: --- gcc/cp/cp-tree.h.jj 2018-02-07 23:28:55.750401640 +0100 +++ gcc/cp/cp-tree.h 2018-02-08 20:08:49.618613211 +0100 @@ -7056,6 +7056,7 @@ extern tree cxx_copy_lang_qualifiers (c extern void cxx_print_statistics (void); extern bool maybe_warn_zero_as_null_pointer_constant (tree, location_t); +extern void cp_warn_deprecated_use (tree); /* in ptree.c */ extern void cxx_print_xnode (FILE *, tree, int); --- gcc/cp/tree.c.jj 2018-02-06 13:12:48.121808347 +0100 +++ gcc/cp/tree.c 2018-02-08 20:08:22.293628631 +0100 @@ -5348,6 +5348,19 @@ maybe_warn_zero_as_null_pointer_constant } return false; } + +/* Wrapper around warn_deprecated_use that doesn't warn for + current_class_type. */ + +void +cp_warn_deprecated_use (tree node) +{ + if (TYPE_P (node) + && current_class_type + && TYPE_MAIN_VARIANT (node) == current_class_type) + return; + warn_deprecated_use (node, NULL_TREE); +} #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) /* Complain that some language-specific thing hanging off a tree --- gcc/cp/decl.c.jj 2018-02-07 23:28:55.731401645 +0100 +++ gcc/cp/decl.c 2018-02-08 20:09:53.655577074 +0100 @@ -10363,7 +10363,7 @@ grokdeclarator (const cp_declarator *dec suppress reports of deprecated items. */ if (type && TREE_DEPRECATED (type) && deprecated_state != DEPRECATED_SUPPRESS) - warn_deprecated_use (type, NULL_TREE); + cp_warn_deprecated_use (type); if (type && TREE_CODE (type) == TYPE_DECL) { typedef_decl = type; @@ -10371,7 +10371,7 @@ grokdeclarator (const cp_declarator *dec if (TREE_DEPRECATED (type) && DECL_ARTIFICIAL (typedef_decl) && deprecated_state != DEPRECATED_SUPPRESS) - warn_deprecated_use (type, NULL_TREE); + cp_warn_deprecated_use (type); } /* No type at all: default to `int', and set DEFAULTED_INT because it was not a user-defined typedef. */ @@ -12712,7 +12712,7 @@ grokparms (tree parmlist, tree *parms) { tree deptype = type_is_deprecated (type); if (deptype) - warn_deprecated_use (deptype, NULL_TREE); + cp_warn_deprecated_use (deptype); } /* Top-level qualifiers on the parameters are --- gcc/cp/typeck2.c.jj 2018-02-06 13:12:48.146808267 +0100 +++ gcc/cp/typeck2.c 2018-02-08 20:12:48.880478192 +0100 @@ -2056,7 +2056,7 @@ build_functional_cast (tree exp, tree pa if (complain & tf_warning && TREE_DEPRECATED (type) && DECL_ARTIFICIAL (exp)) - warn_deprecated_use (type, NULL_TREE); + cp_warn_deprecated_use (type); } else type = exp; we don't warn inside of the deprecated classes or templates (which is I think a good thing), but do warn when defining methods for those classes or class templates outside of the class definitions (which is I think undesirable). Testcase: struct __attribute__((deprecated)) C { C () {} C (const C &); C (const C &x, const C &y) { C z = x; } void foo (const C &x, const C &y); }; void C::foo (const C &x, const C &y) { C z = x; } void bar (const C &x, const C &y) { C z = x; } template <int N> struct __attribute__((deprecated)) D { D () {} D (const D &); D (const D &x, const D &y) { D z = x; } void foo (const D &x, const D &y); }; template <int N> void D<N>::foo (const D &x, const D &y) { D z = x; } template <int N> void baz (const D<N> &x, const D<N> &y) { D<N> z = x; } Note, clang++ seems to warn only on bar, doesn't warn inside of the class definitions (matches the patch), doesn't warn inside of the out of class method definitions (I'd say desirable), and doesn't warn inside of baz (that looks like a bug to me, unless they warn only when it is instantiated).
Checking DECL_CONTEXT of current_function_decl if non-NULL doesn't seem to work either.
Created attachment 43651 [details] gcc8-pr84222.patch Untested fix.
Author: jakub Date: Thu Mar 15 17:45:01 2018 New Revision: 258568 URL: https://gcc.gnu.org/viewcvs?rev=258568&root=gcc&view=rev Log: PR c++/84222 * cp-tree.h (cp_warn_deprecated_use): Declare. * tree.c (cp_warn_deprecated_use): New function. * typeck2.c (build_functional_cast): Use it. * decl.c (grokparms): Likewise. (grokdeclarator): Likewise. Temporarily push nested class scope around grokparms call for out of class member definitions. * g++.dg/warn/deprecated.C (T::member3): Change dg-warning to dg-bogus. * g++.dg/warn/deprecated-6.C (T::member3): Likewise. * g++.dg/warn/deprecated-13.C: New test. Added: trunk/gcc/testsuite/g++.dg/warn/deprecated-13.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/cp-tree.h trunk/gcc/cp/decl.c trunk/gcc/cp/tree.c trunk/gcc/cp/typeck2.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/warn/deprecated-6.C trunk/gcc/testsuite/g++.dg/warn/deprecated.C
Fixed for 8.1+.
Let me change the Status to New since it's fixed for GCC 8. Jakub, do you expect to backport the patch to older branches?
Author: jakub Date: Fri Jun 22 20:43:09 2018 New Revision: 261924 URL: https://gcc.gnu.org/viewcvs?rev=261924&root=gcc&view=rev Log: Backported from mainline 2018-03-15 Jakub Jelinek <jakub@redhat.com> PR c++/84222 * cp-tree.h (cp_warn_deprecated_use): Declare. * tree.c (cp_warn_deprecated_use): New function. * typeck2.c (build_functional_cast): Use it. * decl.c (grokparms): Likewise. (grokdeclarator): Likewise. Temporarily push nested class scope around grokparms call for out of class member definitions. * g++.dg/warn/deprecated.C (T::member3): Change dg-warning to dg-bogus. * g++.dg/warn/deprecated-6.C (T::member3): Likewise. * g++.dg/warn/deprecated-13.C: New test. Added: branches/gcc-7-branch/gcc/testsuite/g++.dg/warn/deprecated-13.C Modified: branches/gcc-7-branch/gcc/cp/ChangeLog branches/gcc-7-branch/gcc/cp/cp-tree.h branches/gcc-7-branch/gcc/cp/decl.c branches/gcc-7-branch/gcc/cp/tree.c branches/gcc-7-branch/gcc/cp/typeck2.c branches/gcc-7-branch/gcc/testsuite/ChangeLog branches/gcc-7-branch/gcc/testsuite/g++.dg/warn/deprecated-6.C branches/gcc-7-branch/gcc/testsuite/g++.dg/warn/deprecated.C
Author: jakub Date: Mon Jun 25 17:32:10 2018 New Revision: 262075 URL: https://gcc.gnu.org/viewcvs?rev=262075&root=gcc&view=rev Log: Backported from mainline 2018-03-15 Jakub Jelinek <jakub@redhat.com> PR c++/84222 * cp-tree.h (cp_warn_deprecated_use): Declare. * tree.c (cp_warn_deprecated_use): New function. * typeck2.c (build_functional_cast): Use it. * decl.c (grokparms): Likewise. (grokdeclarator): Likewise. Temporarily push nested class scope around grokparms call for out of class member definitions. * g++.dg/warn/deprecated.C (T::member3): Change dg-warning to dg-bogus. * g++.dg/warn/deprecated-6.C (T::member3): Likewise. * g++.dg/warn/deprecated-13.C: New test. Added: branches/gcc-6-branch/gcc/testsuite/g++.dg/warn/deprecated-13.C Modified: branches/gcc-6-branch/gcc/cp/ChangeLog branches/gcc-6-branch/gcc/cp/cp-tree.h branches/gcc-6-branch/gcc/cp/decl.c branches/gcc-6-branch/gcc/cp/tree.c branches/gcc-6-branch/gcc/cp/typeck2.c branches/gcc-6-branch/gcc/testsuite/ChangeLog branches/gcc-6-branch/gcc/testsuite/g++.dg/warn/deprecated-6.C branches/gcc-6-branch/gcc/testsuite/g++.dg/warn/deprecated.C
Fixed for 6.5 and 7.4+ too.