diff mbox series

[C++] Fix up -Wdeprecated (PR c++/84222)

Message ID 20180314222600.GM8577@tucnak
State New
Headers show
Series [C++] Fix up -Wdeprecated (PR c++/84222) | expand

Commit Message

Jakub Jelinek March 14, 2018, 10:26 p.m. UTC
Hi!

As the following testcase shows, if we have a deprecated class, we warn
about any uses, including e.g. arguments of methods of that class (how can
one e.g. declare or define a copy ctor without warnings?).

The following patch changes it, so that we don't warn about deprecated uses
in methods of that deprecated class (warn about uses of other deprecated
classes of course).  There is still one xfailed case where we warn about
template-id in the containing scope if the deprecated class is a template.

clang++ warns about the bar (const C &, const C &) function, both about
the parameters and about the use in the body (like g++) and doesn't warn
inside of (perhaps uninstantiated only) templates at all (which I think is
better that we do warn).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-03-14  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.


	Jakub

Comments

Jason Merrill March 15, 2018, 12:44 a.m. UTC | #1
On Wed, Mar 14, 2018 at 6:26 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> As the following testcase shows, if we have a deprecated class, we warn
> about any uses, including e.g. arguments of methods of that class (how can
> one e.g. declare or define a copy ctor without warnings?).
>
> The following patch changes it, so that we don't warn about deprecated uses
> in methods of that deprecated class (warn about uses of other deprecated
> classes of course).  There is still one xfailed case where we warn about
> template-id in the containing scope if the deprecated class is a template.
>
> clang++ warns about the bar (const C &, const C &) function, both about
> the parameters and about the use in the body (like g++) and doesn't warn
> inside of (perhaps uninstantiated only) templates at all (which I think is
> better that we do warn).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2018-03-14  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.

I like these.

>         (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.
>
> --- gcc/cp/cp-tree.h.jj 2018-03-11 17:48:36.360061435 +0100
> +++ gcc/cp/cp-tree.h    2018-03-14 11:49:58.924816419 +0100
> @@ -7064,6 +7064,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-03-07 22:51:58.671478659 +0100
> +++ gcc/cp/tree.c       2018-03-14 11:49:58.926816421 +0100
> @@ -5347,6 +5347,19 @@ cp_tree_code_length (enum tree_code code
>      }
>  }
>
> +/* 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);
> +}
> +
>  /* Implement -Wzero_as_null_pointer_constant.  Return true if the
>     conditions for the warning hold, false otherwise.  */
>  bool
> --- gcc/cp/typeck2.c.jj 2018-03-02 00:15:54.096781050 +0100
> +++ gcc/cp/typeck2.c    2018-03-14 11:49:58.931816424 +0100
> @@ -2057,7 +2057,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;
> --- gcc/cp/decl.c.jj    2018-03-14 09:44:55.744974946 +0100
> +++ gcc/cp/decl.c       2018-03-14 12:18:08.094012453 +0100
> @@ -10448,7 +10448,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;
> @@ -10456,7 +10456,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.  */
> @@ -11271,8 +11271,18 @@ grokdeclarator (const cp_declarator *dec
>                   explicitp = 2;
>               }
>
> -           arg_types = grokparms (declarator->u.function.parameters,
> -                                  &parms);
> +           tree pushed_scope = NULL_TREE;
> +           if (funcdecl_p
> +               && decl_context != FIELD
> +               && inner_declarator->u.id.qualifying_scope
> +               && CLASS_TYPE_P (inner_declarator->u.id.qualifying_scope))
> +             pushed_scope
> +               = push_scope (inner_declarator->u.id.qualifying_scope);

Can't we use ctype here?

Jason
Jakub Jelinek March 15, 2018, 8:07 a.m. UTC | #2
On Wed, Mar 14, 2018 at 08:44:48PM -0400, Jason Merrill wrote:
> > --- gcc/cp/decl.c.jj    2018-03-14 09:44:55.744974946 +0100
> > +++ gcc/cp/decl.c       2018-03-14 12:18:08.094012453 +0100
> > @@ -10448,7 +10448,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;
> > @@ -10456,7 +10456,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.  */
> > @@ -11271,8 +11271,18 @@ grokdeclarator (const cp_declarator *dec
> >                   explicitp = 2;
> >               }
> >
> > -           arg_types = grokparms (declarator->u.function.parameters,
> > -                                  &parms);
> > +           tree pushed_scope = NULL_TREE;
> > +           if (funcdecl_p
> > +               && decl_context != FIELD
> > +               && inner_declarator->u.id.qualifying_scope
> > +               && CLASS_TYPE_P (inner_declarator->u.id.qualifying_scope))
> > +             pushed_scope
> > +               = push_scope (inner_declarator->u.id.qualifying_scope);
> 
> Can't we use ctype here?

Inside of classes ctype is non-NULL, but we don't need to push anything,
current_class_type is already the class we care about.
That's the
  tree ctype = current_class_type;
on line 10130.  Then we have this
  for (id_declarator = declarator;
       id_declarator;
       id_declarator = id_declarator->declarator)
loop, where for cdk_id at line 10242 it tweaks ctype:
                else if (TYPE_P (qualifying_scope))
                  {
                    ctype = qualifying_scope;
                    if (!MAYBE_CLASS_TYPE_P (ctype))
                      {
                        error ("%q#T is not a class or a namespace", ctype);
                        ctype = NULL_TREE;
                      }
and indeed for the cases I care about (out of class method definitions)
ctype is set to non-NULL here.  But then at line 10542 it is cleared again:
  ctype = NULL_TREE;

and at 11176:
            if (ctype == NULL_TREE
                && decl_context == FIELD
                && funcdecl_p
                && friendp == 0)
              ctype = current_class_type;
set only for selected in-class definitions, and then tested and used a couple of
times.  And that is the state we call grokparms with.
Only later at line 11529 it is set again:
  if (declarator
      && declarator->kind == cdk_id
      && declarator->u.id.qualifying_scope
      && MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope))
    {
      ctype = declarator->u.id.qualifying_scope;
      ctype = TYPE_MAIN_VARIANT (ctype);
So, if I were to use some variable without really changing the behavior of
the grokdeclarator massively, it would need to be a copy of ctype saved into
another variable (how it should be named?) above line 10542.  Given the
TYPE_MAIN_VARIANT, I guess we should be using TYPE_MAIN_VARIANT somewhere
too.

	Jakub
Jason Merrill March 15, 2018, 5:24 p.m. UTC | #3
On Thu, Mar 15, 2018 at 4:07 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Mar 14, 2018 at 08:44:48PM -0400, Jason Merrill wrote:
>> > --- gcc/cp/decl.c.jj    2018-03-14 09:44:55.744974946 +0100
>> > +++ gcc/cp/decl.c       2018-03-14 12:18:08.094012453 +0100
>> > @@ -10448,7 +10448,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;
>> > @@ -10456,7 +10456,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.  */
>> > @@ -11271,8 +11271,18 @@ grokdeclarator (const cp_declarator *dec
>> >                   explicitp = 2;
>> >               }
>> >
>> > -           arg_types = grokparms (declarator->u.function.parameters,
>> > -                                  &parms);
>> > +           tree pushed_scope = NULL_TREE;
>> > +           if (funcdecl_p
>> > +               && decl_context != FIELD
>> > +               && inner_declarator->u.id.qualifying_scope
>> > +               && CLASS_TYPE_P (inner_declarator->u.id.qualifying_scope))
>> > +             pushed_scope
>> > +               = push_scope (inner_declarator->u.id.qualifying_scope);
>>
>> Can't we use ctype here?
>
> Inside of classes ctype is non-NULL, but we don't need to push anything,
> current_class_type is already the class we care about.
> That's the
>   tree ctype = current_class_type;
> on line 10130.  Then we have this
>   for (id_declarator = declarator;
>        id_declarator;
>        id_declarator = id_declarator->declarator)
> loop, where for cdk_id at line 10242 it tweaks ctype:
>                 else if (TYPE_P (qualifying_scope))
>                   {
>                     ctype = qualifying_scope;
>                     if (!MAYBE_CLASS_TYPE_P (ctype))
>                       {
>                         error ("%q#T is not a class or a namespace", ctype);
>                         ctype = NULL_TREE;
>                       }
> and indeed for the cases I care about (out of class method definitions)
> ctype is set to non-NULL here.  But then at line 10542 it is cleared again:
>   ctype = NULL_TREE;
>
> and at 11176:
>             if (ctype == NULL_TREE
>                 && decl_context == FIELD
>                 && funcdecl_p
>                 && friendp == 0)
>               ctype = current_class_type;
> set only for selected in-class definitions, and then tested and used a couple of
> times.  And that is the state we call grokparms with.
> Only later at line 11529 it is set again:
>   if (declarator
>       && declarator->kind == cdk_id
>       && declarator->u.id.qualifying_scope
>       && MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope))
>     {
>       ctype = declarator->u.id.qualifying_scope;
>       ctype = TYPE_MAIN_VARIANT (ctype);
> So, if I were to use some variable without really changing the behavior of
> the grokdeclarator massively, it would need to be a copy of ctype saved into
> another variable (how it should be named?) above line 10542.  Given the
> TYPE_MAIN_VARIANT, I guess we should be using TYPE_MAIN_VARIANT somewhere
> too.

Wow, yeah, the use of ctype in grokdeclarator is pretty bizarre.  Your
patch is OK.

Jason
diff mbox series

Patch

--- gcc/cp/cp-tree.h.jj	2018-03-11 17:48:36.360061435 +0100
+++ gcc/cp/cp-tree.h	2018-03-14 11:49:58.924816419 +0100
@@ -7064,6 +7064,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-03-07 22:51:58.671478659 +0100
+++ gcc/cp/tree.c	2018-03-14 11:49:58.926816421 +0100
@@ -5347,6 +5347,19 @@  cp_tree_code_length (enum tree_code code
     }
 }
 
+/* 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);
+}
+
 /* Implement -Wzero_as_null_pointer_constant.  Return true if the
    conditions for the warning hold, false otherwise.  */
 bool
--- gcc/cp/typeck2.c.jj	2018-03-02 00:15:54.096781050 +0100
+++ gcc/cp/typeck2.c	2018-03-14 11:49:58.931816424 +0100
@@ -2057,7 +2057,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;
--- gcc/cp/decl.c.jj	2018-03-14 09:44:55.744974946 +0100
+++ gcc/cp/decl.c	2018-03-14 12:18:08.094012453 +0100
@@ -10448,7 +10448,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;
@@ -10456,7 +10456,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.  */
@@ -11271,8 +11271,18 @@  grokdeclarator (const cp_declarator *dec
 		  explicitp = 2;
 	      }
 
-	    arg_types = grokparms (declarator->u.function.parameters,
-				   &parms);
+	    tree pushed_scope = NULL_TREE;
+	    if (funcdecl_p
+		&& decl_context != FIELD
+		&& inner_declarator->u.id.qualifying_scope
+		&& CLASS_TYPE_P (inner_declarator->u.id.qualifying_scope))
+	      pushed_scope
+		= push_scope (inner_declarator->u.id.qualifying_scope);
+
+	    arg_types = grokparms (declarator->u.function.parameters, &parms);
+
+	    if (pushed_scope)
+	      pop_scope (pushed_scope);
 
 	    if (inner_declarator
 		&& inner_declarator->kind == cdk_id
@@ -12799,7 +12809,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/testsuite/g++.dg/warn/deprecated.C.jj	2017-04-28 22:16:51.986480480 +0200
+++ gcc/testsuite/g++.dg/warn/deprecated.C	2018-03-14 12:51:54.847224549 +0100
@@ -102,7 +102,7 @@  T *p3;				// { dg-warning "'T' is deprec
 
 inline void T::member1(int) {}
 
-int T::member3(T *p)		// { dg-warning "'T' is deprecated" }
+int T::member3(T *p)		// { dg-bogus "'T' is deprecated" }
 {
   p->member1(1);			/* { dg-warning "'void T::member1\\(int\\)' is deprecated" } */
   (*p).member1(2);			/* { dg-warning "'void T::member1\\(int\\)' is deprecated" } */
@@ -113,5 +113,3 @@  int T::member3(T *p)		// { dg-warning "'
   return f1(); 				/* { dg-warning "'INT1 f1\\(\\)' is deprecated" } */
 }
 #endif
-
-
--- gcc/testsuite/g++.dg/warn/deprecated-6.C.jj	2017-04-28 22:16:51.970480683 +0200
+++ gcc/testsuite/g++.dg/warn/deprecated-6.C	2018-03-14 12:51:15.721213235 +0100
@@ -98,7 +98,7 @@  T *p3;				// { dg-warning "'T' is deprec
 
 inline void T::member1(int) {}
 
-int T::member3(T *p)		// { dg-warning "'T' is deprecated: Please avoid T" }
+int T::member3(T *p)		// { dg-bogus "'T' is deprecated: Please avoid T" }
 {
   p->member1(1);			/* { dg-warning "'void T::member1\\(int\\)' is deprecated: Please avoid member1" } */
   (*p).member1(2);			/* { dg-warning "'void T::member1\\(int\\)' is deprecated: Please avoid member1" } */
--- gcc/testsuite/g++.dg/warn/deprecated-13.C.jj	2018-03-14 12:34:43.523210515 +0100
+++ gcc/testsuite/g++.dg/warn/deprecated-13.C	2018-03-14 12:34:13.103233036 +0100
@@ -0,0 +1,44 @@ 
+// PR c++/84222
+// { dg-do compile }
+
+struct __attribute__((deprecated)) C {		// { dg-message "declared here" }
+  C () {}
+  C (const C &);				// { dg-bogus "'C' is deprecated" }
+  C (const C &x, const C &y) { C z = x; }	// { dg-bogus "'C' is deprecated" }
+  void foo (const C &x, const C &y);		// { dg-bogus "'C' is deprecated" }
+};
+
+void
+C::foo (const C &x, const C &y)			// { dg-bogus "'C' is deprecated" }
+{
+  C z = x;					// { dg-bogus "'C' is deprecated" }
+}
+
+void
+bar (const C &x, const C &y)			// { dg-warning "'C' is deprecated" }
+{
+  C z = x;					// { dg-warning "'C' is deprecated" }
+}
+
+template <int N>
+struct __attribute__((deprecated)) D {		// { dg-message "declared here" }
+  D () {}
+  D (const D &);				// { dg-bogus "is deprecated" }
+  D (const D &x, const D &y) { D z = x; }	// { dg-bogus "is deprecated" }
+  void foo (const D &x, const D &y);		// { dg-bogus "is deprecated" }
+};
+
+template <int N>
+void
+D<N>::foo					// { dg-bogus "is deprecated" "" { xfail *-*-* } }
+(const D &x, const D &y)			// { dg-bogus "is deprecated" }
+{
+  D z = x;					// { dg-bogus "is deprecated" }
+}
+
+template <int N>
+void
+bar (const D<N> &x, const D<N> &y)		// { dg-warning "is deprecated" }
+{
+  D<N> z = x;					// { dg-warning "is deprecated" }
+}