On 03/20/2017 03:11 PM, Jason Merrill wrote:
On Thu, Feb 23, 2017 at 6:33 PM, Jason Merrill <ja...@redhat.com> wrote:
On Thu, Feb 23, 2017 at 12:56 PM, Martin Sebor <mse...@gmail.com> wrote:
On 02/22/2017 05:43 PM, Jason Merrill wrote:
On Wed, Feb 22, 2017 at 3:44 PM, Martin Sebor <mse...@gmail.com> wrote:
On 02/22/2017 11:02 AM, Jason Merrill wrote:

The TREE_USED bit on the type (i.e., on
TREE_TYPE(decl) where decl is the u in the test case above) is
set when the function template is instantiated, in
set_underlying_type called from tsubst_decl.

Aha!  That seems like the problem.  Does removing that copy of
TREE_USED from the decl to the type break anything?

As far as I can see it breaks just gcc.dg/unused-3.c which is:

  typedef short unused_type __attribute__ ((unused));

  void f (void)
  {
    unused_type y;
  }

Ah.  So the problem here is that we're using TREE_USED on a TYPE_DECL
for two things: to track whether the typedef has been used, and to
determine whether to treat a variable of that type as already used.
Normally this isn't too much of a problem because we copy the
TREE_USED flag from decl to type before there could be any uses, but
in a template I guess we mark the typedef within the template when it
is used, and then when we instantiate the typedef we incorrectly pass
that mark along to the type.

Your patch deals with this by ignoring TREE_USED on the type, so it
doesn't matter that it's wrong.  Another approach would be to correct
the setting of TREE_USED by setting it based on looking up the unused
attribute, rather than copying it from the TYPE_DECL.  So also going
back to the attribute, but in set_underlying_type rather than
poplevel.

Thoughts?

I'm not 100% sure I understand what changes you're suggesting
but the attached patch does what I think you're after.  Is that
what you had in mind?

Martin
PR c++/79548 - missing -Wunused-variable on a typedef'd variable in a function template

gcc/c-family/ChangeLog:

	PR c++/79548
	* c-common.c (set_underlying_type): Mark type used only when
	original del is declared unused.

gcc/testsuite/ChangeLog:

	PR c++/79548
	* g++.dg/warn/Wunused-var-26.C: New test.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 885ea6d..65ffd8c 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -7476,7 +7476,12 @@ set_underlying_type (tree x)
       tt = build_variant_type_copy (tt);
       TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
       TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
+
+      /* Mark the type as used only when its type decl is decorated
+	 with attribute unused.  */
+      if (lookup_attribute ("unused", DECL_ATTRIBUTES (x)))
+	TREE_USED (tt) = 1;
+
       TREE_TYPE (x) = tt;
     }
 }
diff --git a/gcc/testsuite/g++.dg/warn/Wunused-var-26.C b/gcc/testsuite/g++.dg/warn/Wunused-var-26.C
new file mode 100644
index 0000000..b3e020b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wunused-var-26.C
@@ -0,0 +1,147 @@
+// PR c++/79548 - missing -Wunused-variable on a typedef'd variable
+// in a function template
+// { dg-do compile }
+// { dg-options "-Wunused" }
+
+
+#define UNUSED __attribute__ ((unused))
+
+template <class T>
+void f_int ()
+{
+  T t;                        // { dg-warning "unused variable" }
+
+  typedef T U;
+  U u;                        // { dg-warning "unused variable" }
+}
+
+template void f_int<int>();
+
+
+template <class T>
+void f_intptr ()
+{
+  T *t = 0;                   // { dg-warning "unused variable" }
+
+  typedef T U;
+  U *u = 0;                   // { dg-warning "unused variable" }
+}
+
+template void f_intptr<int>();
+
+
+template <class T>
+void f_var_unused ()
+{
+  // The variable is marked unused.
+  T t UNUSED;
+
+  typedef T U;
+  U u UNUSED;
+}
+
+template void f_var_unused<int>();
+
+
+template <class T>
+void f_var_type_unused ()
+{
+  // The variable's type is marked unused.
+  T* UNUSED t = new T;   // { dg-bogus "unused variable" "bug 79585" { xfail *-*-* } }
+
+  typedef T U;
+  U* UNUSED u = new U;   // { dg-bogus "unused variable" "bug 79585" { xfail *-*-* } }
+
+  typedef T UNUSED U;
+  U v = U ();   // { dg-bogus "unused variable" "bug 79585" }
+}
+
+template void f_var_type_unused<int>();
+
+
+struct A { int i; };
+
+template <class T>
+void f_A ()
+{
+  T t;                        // { dg-warning "unused variable" }
+
+  typedef T U;
+  U u;                        // { dg-warning "unused variable" }
+}
+
+template void f_A<A>();
+
+
+template <class T>
+void f_A_unused ()
+{
+  T t UNUSED;
+
+  typedef T U;
+  U u UNUSED;
+}
+
+template void f_A_unused<A>();
+
+
+struct B { B (); };
+
+template <class T>
+void f_B ()
+{
+  T t;
+
+  typedef T U;
+  U u;
+}
+
+template void f_B<B>();
+
+
+struct NonTrivialDtor { ~NonTrivialDtor (); };
+
+template <class T>
+void f_with_NonTrivialDtor ()
+{
+  // Expect no warnings when instantiated on a type with a non-trivial
+  // destructor.
+  T t;
+
+  typedef T U;
+  U u;
+}
+
+template void f_with_NonTrivialDtor<NonTrivialDtor>();
+
+
+struct D { NonTrivialDtor b; };
+
+template <class T>
+void f_D ()
+{
+  // Same as f_with_NonTrivialDtor but with a class that has a member
+  // with a non-trivial dtor.
+  T t;
+
+  typedef T U;
+  U u;
+}
+
+template void f_D<D>();
+
+
+struct UNUSED DeclaredUnused { };
+
+template <class T>
+void f_with_unused ()
+{
+  // Expect no warnings when instantiatiated on a type declared
+  // with attribute unused.
+  T t;
+
+  typedef T U;
+  U u;
+}
+
+template void f_with_unused<DeclaredUnused>();

Reply via email to