diff mbox

PR c++/33255 - Support -Wunused-local-typedefs warning

Message ID m3r55bcumi.fsf@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli July 27, 2011, 8:54 p.m. UTC
Hello,

The patch below implements a new flag to warn when a typedef defined
in a function is unused.  The warning is -Wunused-local-typedef, is
active for the C and C++ FEs and is intended for trunk.

With this patch the compiler caught a few spots of unused local
typedefs in libstdc++ that I have fixed thus.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

Comments

Jason Merrill July 29, 2011, 7:01 a.m. UTC | #1
On 07/27/2011 01:54 PM, Dodji Seketeli wrote:
> +  /*  Set of typedefs that are used in this function.  */
> +  struct pointer_set_t * GTY((skip)) used_local_typedefs;

Is there a reason not to just use TREE_USED for this?

> +  /* Vector of locally defined typedefs, for
> +     -Wunused-local-typedefs.  */
> +  VEC(tree,gc) *local_typedefs;

If the accessors are in c-common, this field should be in 
c_language_function.

> +      /* We are only interested in a typedef declared locally.  */
> +      if (DECL_CONTEXT (typedef_decl) != current_function_decl)
> +	return;

What if it's used in a nested function/local class/lambda?

> @@ -4175,6 +4175,9 @@ mark_used (tree decl)
>
>    /* Set TREE_USED for the benefit of -Wunused.  */
>    TREE_USED (decl) = 1;
> +
> +  maybe_record_local_typedef_use (TREE_TYPE (decl));

Why is this needed?  If the decl has the typedef for a type, we should 
have already marked it as used in grokdeclarator.

Actually, couldn't we just mark a typedef as used when when lookup finds 
it?  That would avoid having to mark in so many places and avoid the 
need for walk_tree.

I think -Wunused and -Wall should imply -Wunused-local-typedefs unless 
the user specifies -Wno-unused-local-typedefs.

Jason
Paolo Carlini July 29, 2011, 9:34 a.m. UTC | #2
Hi,
> I think -Wunused and -Wall should imply -Wunused-local-typedefs unless 
> the user specifies -Wno-unused-local-typedefs.
IMHO, this is a very good idea looking forward, but then I think we 
should make sure the warning plays well with system headers either as-is 
or together with some other pending work of Dodji. In particular, as I 
probably mentioned already in the trail, we really want to double check 
that debug-mode does not trigger warnings, I'm a bit of worried because 
many people use and like it.

Paolo.
Dodji Seketeli July 29, 2011, 10:35 a.m. UTC | #3
Jason Merrill <jason@redhat.com> writes:

> On 07/27/2011 01:54 PM, Dodji Seketeli wrote:
>> +  /*  Set of typedefs that are used in this function.  */
>> +  struct pointer_set_t * GTY((skip)) used_local_typedefs;
>
> Is there a reason not to just use TREE_USED for this?

I wasn't sure if that flag wasn't (or couldn't be) used for some "core"
functionality with another meaning for this type of tree, and so would
cause some conflict.

>
>> +  /* Vector of locally defined typedefs, for
>> +     -Wunused-local-typedefs.  */
>> +  VEC(tree,gc) *local_typedefs;
>
> If the accessors are in c-common, this field should be in
> c_language_function.
>

Thanks, I didn't realize this existed.

> Actually, couldn't we just mark a typedef as used when when lookup
> finds it?  That would avoid having to mark in so many places and avoid
> the need for walk_tree.

This would indeed simplify things.  I'll try it.

> I think -Wunused and -Wall should imply -Wunused-local-typedefs unless
> the user specifies -Wno-unused-local-typedefs.

I actually first tried this (actually adding it to -Wall -extra and
-Wunused) and found out the following issue.

A typedef can be defined in a macro in a system header, be expanded in a
function and not be used by the function.  In this case we shouldn't
warn, but PR preprocessor/7263 makes us warn nonetheless.  There are
many spots of that kind in the libstdc++ test suite.

Paolo Carlini <paolo.carlini@oracle.com> writes:

> Hi,
>> I think -Wunused and -Wall should imply -Wunused-local-typedefs
>> unless the user specifies -Wno-unused-local-typedefs.
> IMHO, this is a very good idea looking forward, but then I think we
> should make sure the warning plays well with system headers either
> as-is or together with some other pending work of Dodji. In
> particular, as I probably mentioned already in the trail, we really
> want to double check that debug-mode does not trigger warnings, I'm a
> bit of worried because many people use and like it.

Exactly.  This would be a side effect of PR preprocessor/7263?

So do you guys think we should add it nonetheless and just add
-Wno-unused-local-typedefs to the tests that exhibit the above issue
before fixing PR preprocessor/7263?

Thanks.
Paolo Carlini July 29, 2011, 12:09 p.m. UTC | #4
Hi,
>> I think -Wunused and -Wall should imply -Wunused-local-typedefs unless
>> the user specifies -Wno-unused-local-typedefs.
> I actually first tried this (actually adding it to -Wall -extra and
> -Wunused) and found out the following issue.
>
> A typedef can be defined in a macro in a system header, be expanded in a
> function and not be used by the function.  In this case we shouldn't
> warn, but PR preprocessor/7263 makes us warn nonetheless.  There are
> many spots of that kind in the libstdc++ test suite.
>
> Paolo Carlini<paolo.carlini@oracle.com>  writes:
>
>> Hi,
>>> I think -Wunused and -Wall should imply -Wunused-local-typedefs
>>> unless the user specifies -Wno-unused-local-typedefs.
>> IMHO, this is a very good idea looking forward, but then I think we
>> should make sure the warning plays well with system headers either
>> as-is or together with some other pending work of Dodji. In
>> particular, as I probably mentioned already in the trail, we really
>> want to double check that debug-mode does not trigger warnings, I'm a
>> bit of worried because many people use and like it.
> Exactly.  This would be a side effect of PR preprocessor/7263?
>
> So do you guys think we should add it nonetheless and just add
> -Wno-unused-local-typedefs to the tests that exhibit the above issue
> before fixing PR preprocessor/7263?
Personally, I don't have a strong opinion, but I think it's very 
important to have a solid plan for 4.7.0: we don't want to regress in 
terms of warnings spilled from system headers, we slowly made good 
progress over the years and now the situation is pretty good and much 
less confusing than it used to be to the users. For sure, anyway, I'm 
available to clean up a bit some of the warnings emitted by the library, 
if that can help the process.

Paolo.
Dodji Seketeli July 29, 2011, 3:36 p.m. UTC | #5
Jason Merrill <jason@redhat.com> writes:

> On 07/27/2011 01:54 PM, Dodji Seketeli wrote:
>> +  /*  Set of typedefs that are used in this function.  */
>> +  struct pointer_set_t * GTY((skip)) used_local_typedefs;
>
> Is there a reason not to just use TREE_USED for this?
>
>> +  /* Vector of locally defined typedefs, for
>> +     -Wunused-local-typedefs.  */
>> +  VEC(tree,gc) *local_typedefs;
>
> If the accessors are in c-common, this field should be in
> c_language_function.

Looking into this a bit, it seems to me that I can access
cfun->language->base (of type c_language_function) from inside either
the C or C++ FE only, as the type of cfun->language -- which is of type
struct language_function -- is only defined either in c-lang.h or
cp-tree.h.  I cannot access it from c-common.c.

This is consistent with the comment of the language field of the
function struct:

  /* Language-specific code can use this to store whatever it likes.  */
  struct language_function * language;

What am I missing?
Jason Merrill July 29, 2011, 4 p.m. UTC | #6
On 07/29/2011 08:36 AM, Dodji Seketeli wrote:
> Looking into this a bit, it seems to me that I can access
> cfun->language->base (of type c_language_function) from inside either
> the C or C++ FE only, as the type of cfun->language -- which is of type
> struct language_function -- is only defined either in c-lang.h or
> cp-tree.h.  I cannot access it from c-common.c.

I think you can use (struct c_language_function *)cfun->language.

Jason
Jason Merrill July 29, 2011, 4:56 p.m. UTC | #7
On 07/29/2011 03:35 AM, Dodji Seketeli wrote:
> So do you guys think we should add it nonetheless and just add
> -Wno-unused-local-typedefs to the tests that exhibit the above issue
> before fixing PR preprocessor/7263?

Does your set of linemap patches fix the issue?  In that case, we can 
add it when those go in.  Speaking of which, sorry I haven't found the 
time to review them yet.

Jason
Dodji Seketeli July 29, 2011, 5:23 p.m. UTC | #8
Jason Merrill <jason@redhat.com> writes:

> On 07/29/2011 03:35 AM, Dodji Seketeli wrote:
>> So do you guys think we should add it nonetheless and just add
>> -Wno-unused-local-typedefs to the tests that exhibit the above issue
>> before fixing PR preprocessor/7263?
>
> Does your set of linemap patches fix the issue?

Yes it does.  Particularly this patch
http://gcc.gnu.org/ml/gcc-patches/2011-07/msg01318.html 

>  In that case, we can add it when those go in.

OK.

>  Speaking of which, sorry I haven't found the time to review them yet.

No problem.
Dodji Seketeli July 29, 2011, 5:27 p.m. UTC | #9
Jason Merrill <jason@redhat.com> writes:

> On 07/29/2011 08:36 AM, Dodji Seketeli wrote:
>> Looking into this a bit, it seems to me that I can access
>> cfun->language->base (of type c_language_function) from inside either
>> the C or C++ FE only, as the type of cfun->language -- which is of type
>> struct language_function -- is only defined either in c-lang.h or
>> cp-tree.h.  I cannot access it from c-common.c.
>
> I think you can use (struct c_language_function *)cfun->language.

I see.

Looking a bit further, it looks like the C FE uses cfun->language only
to store the context of the outer function when faced with a nested
function.  This is done by c_push_function_context, called by
c_parser_declaration_or_fndef.  Otherwise, cfun->language is not
allocated.  Is it appropriate that -Wunused-local-typedefs allocates it
as well?
Jason Merrill July 29, 2011, 9:46 p.m. UTC | #10
On 07/29/2011 10:27 AM, Dodji Seketeli wrote:
> Jason Merrill<jason@redhat.com>  writes:
>
>> On 07/29/2011 08:36 AM, Dodji Seketeli wrote:
>>> Looking into this a bit, it seems to me that I can access
>>> cfun->language->base (of type c_language_function) from inside either
>>> the C or C++ FE only, as the type of cfun->language -- which is of type
>>> struct language_function -- is only defined either in c-lang.h or
>>> cp-tree.h.  I cannot access it from c-common.c.
>>
>> I think you can use (struct c_language_function *)cfun->language.
>
> I see.
>
> Looking a bit further, it looks like the C FE uses cfun->language only
> to store the context of the outer function when faced with a nested
> function.  This is done by c_push_function_context, called by
> c_parser_declaration_or_fndef.  Otherwise, cfun->language is not
> allocated.  Is it appropriate that -Wunused-local-typedefs allocates it
> as well?

I think so.  Joseph?

Jason
Joseph Myers July 30, 2011, 1:50 p.m. UTC | #11
On Fri, 29 Jul 2011, Jason Merrill wrote:

> > Looking a bit further, it looks like the C FE uses cfun->language only
> > to store the context of the outer function when faced with a nested
> > function.  This is done by c_push_function_context, called by
> > c_parser_declaration_or_fndef.  Otherwise, cfun->language is not
> > allocated.  Is it appropriate that -Wunused-local-typedefs allocates it
> > as well?
> 
> I think so.  Joseph?

Seems reasonable.
diff mbox

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 593c951..f92f650 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -937,7 +937,7 @@  ALIAS_H = alias.h coretypes.h
 EMIT_RTL_H = emit-rtl.h
 FLAGS_H = flags.h coretypes.h flag-types.h $(OPTIONS_H)
 OPTIONS_H = options.h flag-types.h $(OPTIONS_H_EXTRA)
-FUNCTION_H = function.h $(TREE_H) $(HASHTAB_H) vecprim.h $(TM_H) hard-reg-set.h
+FUNCTION_H = function.h $(TREE_H) $(HASHTAB_H) vecprim.h $(TM_H) hard-reg-set.h pointer-set.h
 EXPR_H = expr.h insn-config.h $(FUNCTION_H) $(RTL_H) $(FLAGS_H) $(TREE_H) $(MACHMODE_H) $(EMIT_RTL_H)
 OPTABS_H = optabs.h insn-codes.h
 REGS_H = regs.h $(MACHMODE_H) hard-reg-set.h
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 33d2615..0ffa831 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -2769,7 +2769,15 @@  pushdecl (tree x)
 
  skip_external_and_shadow_checks:
   if (TREE_CODE (x) == TYPE_DECL)
-    set_underlying_type (x);
+    {
+      /* So this is a typedef, set its underlying type.  */
+      set_underlying_type (x);
+
+      /* If X is a typedef defined in the current function, record it
+	 for the purpose of implementing the -Wunused-local-typedefs
+	 warning.  */
+      record_locally_defined_typedef (x);
+    }
 
   bind (name, x, scope, /*invisible=*/false, nested, locus);
 
@@ -6076,6 +6084,8 @@  grokdeclarator (const struct c_declarator *declarator,
      name of a variable.  Thus, if it's known before this, die horribly.  */
     gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl));
 
+    maybe_record_local_typedef_use (TREE_TYPE (decl));
+
     if (warn_cxx_compat
 	&& TREE_CODE (decl) == VAR_DECL
 	&& TREE_PUBLIC (decl)
@@ -8265,6 +8275,10 @@  finish_function (void)
 		      "parameter %qD set but not used", decl);
     }
 
+  /* Complain about locally defined typedefs that are not used in this
+     function.  */
+  maybe_warn_unused_local_typedefs ();
+
   /* Store the end of the function, so that we get good line number
      info for the epilogue.  */
   cfun->function_end_locus = input_location;
@@ -9888,4 +9902,42 @@  c_register_addr_space (const char *word, addr_space_t as)
   ridpointers [rid] = id;
 }
 
+/* Subroutine of c_maybe_record_local_typedef_use, called from
+   walk_tree_without_duplicates.   */
+
+static tree
+maybe_record_local_typedef_use_r (tree *tp,
+				  int *walk_subtrees ATTRIBUTE_UNUSED,
+				  void *data ATTRIBUTE_UNUSED)
+{
+  maybe_record_local_typedef_use_real (*tp);
+  return NULL_TREE;
+}
+
+/* A subroutine of maybe_record_local_typedef_use.  */
+
+static void
+c_maybe_record_local_typedef_use (tree t)
+{
+    if (!warn_unused_local_typedefs)
+      return;
+
+    maybe_record_local_typedef_use_real (t);
+
+    /* Record the typedefs used by subtypes of TYPE.  */
+    walk_tree_without_duplicates (&t,
+				  maybe_record_local_typedef_use_r,
+				  NULL_TREE);
+}
+
+/* If T is a typedef variant type or a TYPE_DECL declared locally,
+   record it in CFUN->USED_LOCAL_TYPEDEFS.  This function also records
+   the typedefs that are direct or indirect subtypes of T.  */
+
+void
+maybe_record_local_typedef_use (tree t)
+{
+  c_maybe_record_local_typedef_use (t);
+}
+
 #include "gt-c-decl.h"
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 96275ba..7036da6 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -4340,6 +4340,8 @@  c_sizeof_or_alignof_type (location_t loc,
   value = fold_convert_loc (loc, size_type_node, value);
   gcc_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)));
 
+  maybe_record_local_typedef_use (type);
+
   return value;
 }
 
@@ -9604,6 +9606,99 @@  record_types_used_by_current_var_decl (tree decl)
     }
 }
 
+/* If DECL is a typedef that is declared in the current function,
+   record it in CFUN->LOCAL_TYPEDEFS, for the purpose of
+   -Wunused-local-typedefs.  */
+
+void
+record_locally_defined_typedef (tree decl)
+{
+  if (!warn_unused_local_typedefs
+      /* if this is not a locally defined typedef then we are not
+	 interested.  */
+      || !is_typedef_decl (decl)
+      || !DECL_CONTEXT (decl)
+      || DECL_CONTEXT (decl) != current_function_decl)
+    return;
+
+  VEC_safe_push (tree, gc, cfun->local_typedefs, decl);
+}
+
+/* If T is a typedef variant type or a TYPE_DECL declared locally,
+   record it in CFUN->USED_LOCAL_TYPEDEFS.  Note that this function
+   does not record the typedefs presents in the subtypes of T.  */
+
+void
+maybe_record_local_typedef_use_real (tree t)
+{
+  tree typedef_decl = NULL_TREE;
+
+  /* We want T to be either a type or a TYPE_DECL.   */
+  if (t == NULL_TREE
+      || (!TYPE_P (t) && TREE_CODE (t) != TYPE_DECL))
+    return;
+
+  if (TYPE_P (t))
+    {
+      if (typedef_variant_p (t))
+	typedef_decl = TYPE_NAME (t);
+    }
+  else
+    {
+      if (is_typedef_decl (t))
+	typedef_decl = t;
+    }
+
+  if (typedef_decl != NULL_TREE)
+    {
+      /* We are only interested in a typedef declared locally.  */
+      if (DECL_CONTEXT (typedef_decl) != current_function_decl)
+	return;
+
+      /* If this typedef is local, really record its use now.  */
+      if (cfun->used_local_typedefs == NULL)
+	cfun->used_local_typedefs = pointer_set_create ();
+      pointer_set_insert (cfun->used_local_typedefs, typedef_decl);
+    }
+}
+
+/* Warn if there are some unused locally defined typedefs in the
+   current function. */
+
+void
+maybe_warn_unused_local_typedefs (void)
+{
+  int i;
+  tree decl;
+  static int unused_local_typedefs_warn_count;
+
+  if (cfun->used_local_typedefs != NULL)
+    gcc_assert (cfun->local_typedefs != NULL);
+
+  if (warn_unused_local_typedefs
+      && errorcount == unused_local_typedefs_warn_count)
+    {
+      FOR_EACH_VEC_ELT (tree, cfun->local_typedefs, i, decl)
+	if (cfun->used_local_typedefs == NULL
+	    || !pointer_set_contains (cfun->used_local_typedefs, decl))
+	  warning_at (DECL_SOURCE_LOCATION (decl),
+		      OPT_Wunused_local_typedefs,
+		      "typedef %qD locally defined but not used", decl);
+      unused_local_typedefs_warn_count = errorcount;
+    }
+
+  if (cfun->used_local_typedefs)
+    {
+      pointer_set_destroy (cfun->used_local_typedefs);
+      cfun->used_local_typedefs = NULL;
+    }
+  if (cfun->local_typedefs)
+    {
+      VEC_free (tree, gc, cfun->local_typedefs);
+      cfun->local_typedefs = NULL;
+    }
+}
+
 /* The C and C++ parsers both use vectors to hold function arguments.
    For efficiency, we keep a cache of unused vectors.  This is the
    cache.  */
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4ac7c4a..12a1550 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -705,6 +705,7 @@  extern tree (*make_fname_decl) (location_t, tree, int);
 
 /* In c-decl.c and cp/tree.c.  FIXME.  */
 extern void c_register_addr_space (const char *str, addr_space_t as);
+extern void maybe_record_local_typedef_use (tree);
 
 /* In c-common.c.  */
 extern bool in_late_binary_op;
@@ -986,6 +987,9 @@  extern void warn_for_sign_compare (location_t,
 extern void do_warn_double_promotion (tree, tree, tree, const char *, 
 				      location_t);
 extern void set_underlying_type (tree);
+extern void record_locally_defined_typedef (tree);
+extern void maybe_record_local_typedef_use_real (tree);
+extern void maybe_warn_unused_local_typedefs (void);
 extern VEC(tree,gc) *make_tree_vector (void);
 extern void release_tree_vector (VEC(tree,gc) *);
 extern VEC(tree,gc) *make_tree_vector_single (tree);
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 617ea2d..e6ac5dc 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -653,6 +653,10 @@  Wunsuffixed-float-constants
 C ObjC Var(warn_unsuffixed_float_constants) Warning
 Warn about unsuffixed float constants
 
+Wunused-local-typedefs
+C ObjC C++ ObjC++ Var(warn_unused_local_typedefs) Warning
+Warn about
+
 Wunused-macros
 C ObjC C++ ObjC++ Warning
 Warn about macros defined in the main file that are not used
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index aeb6625..4cd4301 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -2633,6 +2633,9 @@  c_expr_sizeof_type (location_t loc, struct c_type_name *t)
   ret.value = c_sizeof (loc, type);
   ret.original_code = ERROR_MARK;
   ret.original_type = NULL;
+
+  maybe_record_local_typedef_use (type);
+
   if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
       && c_vla_type_p (type))
     {
@@ -4737,6 +4740,8 @@  c_cast_expr (location_t loc, struct c_type_name *type_name, tree expr)
   type = groktypename (type_name, &type_expr, &type_expr_const);
   warn_strict_prototypes = saved_wsp;
 
+  maybe_record_local_typedef_use (type);
+
   ret = build_c_cast (loc, type, expr);
   if (type_expr)
     {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fb17178..38be149 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5001,6 +5001,7 @@  extern void note_vague_linkage_fn		(tree);
 extern tree build_artificial_parm		(tree, tree);
 extern bool possibly_inlined_p			(tree);
 extern int parm_index                           (tree);
+void maybe_record_local_typedef_use             (tree);
 
 /* in error.c */
 extern void init_error				(void);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2000bd4..199e51b 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10318,6 +10318,8 @@  grokdeclarator (const cp_declarator *declarator,
     if (!processing_template_decl)
       cp_apply_type_quals_to_decl (type_quals, decl);
 
+    maybe_record_local_typedef_use (TREE_TYPE (decl));
+
     return decl;
   }
 }
@@ -13378,6 +13380,10 @@  finish_function (int flags)
       unused_but_set_errorcount = errorcount;
     }
 
+  /* Complain about locally defined typedefs that are not used in this
+     function.  */
+  maybe_warn_unused_local_typedefs ();
+
   /* Genericize before inlining.  */
   if (!processing_template_decl)
     {
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index f05b0f8..10882dd 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4175,6 +4175,9 @@  mark_used (tree decl)
 
   /* Set TREE_USED for the benefit of -Wunused.  */
   TREE_USED (decl) = 1;
+
+  maybe_record_local_typedef_use (TREE_TYPE (decl));
+
   if (DECL_CLONED_FUNCTION_P (decl))
     TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1;
 
@@ -4335,4 +4338,47 @@  mark_used (tree decl)
     }
 }
 
+/* Subroutine of cp_maybe_record_local_typedef_use, called from
+   cp_walk_tree_without_duplicate.   */
+
+static tree
+cp_maybe_record_local_typedef_use_r (tree *tp,
+				     int *walk_subtrees ATTRIBUTE_UNUSED,
+				     void *data ATTRIBUTE_UNUSED)
+{
+  maybe_record_local_typedef_use_real (*tp);
+  return NULL_TREE;
+}
+
+/* A subroutine of maybe_record_local_typedef_use.  */
+
+static void
+cp_maybe_record_local_typedef_use (tree t)
+{
+  if (!warn_unused_local_typedefs)
+    return;
+
+  /*  If the current function is being instantiated, bail out.  */
+  if (current_instantiation () != NULL
+      && (current_instantiation ()->decl == current_function_decl))
+    return;
+
+  maybe_record_local_typedef_use_real (t);
+
+  /* Record the typedefs used by subtypes of TYPE.  */
+  cp_walk_tree_without_duplicates (&t,
+				   cp_maybe_record_local_typedef_use_r,
+				   NULL_TREE);
+}
+
+/* If T is a typedef variant type or a TYPE_DECL declared locally,
+   record it in CFUN->USED_LOCAL_TYPEDEFS.  This function also records
+   the typedefs that are direct or indirect subtypes of T.  */
+
+void
+maybe_record_local_typedef_use (tree t)
+{
+  cp_maybe_record_local_typedef_use (t);
+}
+
 #include "gt-cp-decl2.h"
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 52b9484..4880903 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2612,6 +2612,8 @@  build_new (VEC(tree,gc) **placement, tree type, tree nelts,
   if (type == error_mark_node)
     return error_mark_node;
 
+  maybe_record_local_typedef_use (type);
+
   if (nelts == NULL_TREE && VEC_length (tree, *init) == 1)
     {
       tree auto_node = type_uses_auto (type);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 1afd9ed..512480c 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -868,6 +868,13 @@  pushdecl_maybe_friend_1 (tree x, bool is_friend)
 	      && TYPE_NAME (type)
 	      && TYPE_IDENTIFIER (type))
 	    set_identifier_type_value (DECL_NAME (x), x);
+
+	  /* If this is a locally defined typedef in a function that
+	     is not a template instantation, record it to implement
+	     -Wunused-local-typedefs.  */
+	  if (current_instantiation () == NULL
+	      || (current_instantiation ()->decl != current_function_decl))
+	  record_locally_defined_typedef (x);
 	}
 
       /* Multiple external decls of the same identifier ought to match.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b7410d5..7097f0d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4707,6 +4707,7 @@  cp_parser_qualifying_entity (cp_parser *parser,
       scope = cp_parser_namespace_name (parser);
     }
 
+  maybe_record_local_typedef_use (scope);
   return scope;
 }
 
@@ -11705,6 +11706,12 @@  cp_parser_template_id (cp_parser *parser,
       template_id = lookup_template_function (templ, arguments);
     }
 
+  /* Mark the possible use of a typedefs in the arguments, for the
+     purpose of -Wunused-local-typedefs.  */
+  if (arguments != NULL_TREE)
+    for (i = 0; i < TREE_VEC_LENGTH (arguments); ++i)
+      maybe_record_local_typedef_use (TREE_VEC_ELT (arguments, i));
+
   /* If parsing tentatively, replace the sequence of tokens that makes
      up the template-id with a CPP_TEMPLATE_ID token.  That way,
      should we re-parse the token stream, we will not have to repeat
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index 434b772..b1483e9 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -523,6 +523,8 @@  build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain)
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (type);
 
+  maybe_record_local_typedef_use (type);
+
   /* T shall be a pointer or reference to a complete class type, or
      `pointer to cv void''.  */
   switch (tc)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ab08eae..5990f09 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1534,6 +1534,7 @@  cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
     {
       value = build_min (op, size_type_node, type);
       TREE_READONLY (value) = 1;
+      maybe_record_local_typedef_use (type);
       return value;
     }
 
@@ -5714,6 +5715,8 @@  build_static_cast_1 (tree type, tree expr, bool c_cast_p,
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (type);
 
+  maybe_record_local_typedef_use (type);
+
   /* [expr.static.cast]
 
      An lvalue of type "cv1 B", where B is a class type, can be cast
@@ -6017,6 +6020,8 @@  build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (type);
 
+  maybe_record_local_typedef_use (type);
+
   /* [expr.reinterpret.cast]
      An lvalue expression of type T1 can be cast to the type
      "reference to T2" if an expression of type "pointer to T1" can be
@@ -6237,6 +6242,8 @@  build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain,
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (dst_type);
 
+  maybe_record_local_typedef_use (dst_type);
+
   src_type = TREE_TYPE (expr);
   /* Expressions do not really have reference types.  */
   if (TREE_CODE (src_type) == REFERENCE_TYPE)
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 727a88b..5ac24e4 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1607,6 +1607,8 @@  build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
       type = error_mark_node;
     }
 
+  maybe_record_local_typedef_use (type);
+
   if (processing_template_decl)
     {
       tree t;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index db9a5da..1289dd4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -267,8 +267,9 @@  Objective-C and Objective-C++ Dialects}.
 -Wsystem-headers  -Wtrampolines  -Wtrigraphs  -Wtype-limits  -Wundef @gol
 -Wuninitialized  -Wunknown-pragmas  -Wno-pragmas @gol
 -Wunsuffixed-float-constants  -Wunused  -Wunused-function @gol
--Wunused-label  -Wunused-parameter -Wno-unused-result -Wunused-value @gol
--Wunused-variable -Wunused-but-set-parameter -Wunused-but-set-variable @gol
+-Wunused-label  -Wunused-local-typedefs -Wunused-parameter @gol
+-Wno-unused-result -Wunused-value @gol -Wunused-variable @gol
+-Wunused-but-set-parameter -Wunused-but-set-variable @gol
 -Wvariadic-macros -Wvla -Wvolatile-register-var  -Wwrite-strings}
 
 @item C and Objective-C-only Warning Options
@@ -3499,6 +3500,10 @@  This warning is enabled by @option{-Wall}.
 To suppress this warning use the @samp{unused} attribute
 (@pxref{Variable Attributes}).
 
+@item -Wunused-local-typedefs @r{(C, Objective-C, C++ and Objective-C++ only)}
+@opindex Wunused-local-typedefs
+Warn when a typedef locally defined in a function is not used.
+
 @item -Wunused-parameter
 @opindex Wunused-parameter
 @opindex Wno-unused-parameter
diff --git a/gcc/function.h b/gcc/function.h
index ff193bc..ee13506 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -27,6 +27,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "vecprim.h"
 #include "tm.h"		/* For CUMULATIVE_ARGS.  */
 #include "hard-reg-set.h"
+#include "pointer-set.h"
 
 /* Stack of pending (incomplete) sequences saved by `start_sequence'.
    Each element describes one pending sequence.
@@ -532,6 +533,13 @@  struct GTY(()) function {
   /* Vector of function local variables, functions, types and constants.  */
   VEC(tree,gc) *local_decls;
 
+  /* Vector of locally defined typedefs, for
+     -Wunused-local-typedefs.  */
+  VEC(tree,gc) *local_typedefs;
+
+  /*  Set of typedefs that are used in this function.  */
+  struct pointer_set_t * GTY((skip)) used_local_typedefs;
+
   /* For md files.  */
 
   /* tm.h can use this to store whatever it likes.  */
diff --git a/gcc/testsuite/c-c++-common/Wunused-local-typedefs.c b/gcc/testsuite/c-c++-common/Wunused-local-typedefs.c
new file mode 100644
index 0000000..32fb723
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wunused-local-typedefs.c
@@ -0,0 +1,38 @@ 
+/*  Origin PR c++/33255
+    { dg-options "-Wunused-local-typedefs" }
+    { dg-do compile }
+*/
+
+void
+test_warn ()
+{
+  typedef int foo; // { dg-warning "locally defined but not used" }
+}
+
+void
+test0 ()
+{
+    typedef int foo;
+    foo var __attribute__((unused));
+}
+
+void
+test1 ()
+{
+    typedef int foo;
+    const foo *var = 0;
+}
+
+void
+test2 ()
+{
+  typedef int foo;
+  void func(foo);  
+}
+
+void
+test7 (void)
+{
+  typedef int foo;
+  int vec[1] = {sizeof (foo)};
+}
diff --git a/gcc/tree.c b/gcc/tree.c
index 30ff80f..a1dda11 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -10323,6 +10323,11 @@  walk_type_fields (tree type, walk_tree_fn func, void *data,
 {
   tree result = NULL_TREE;
 
+  /* If this type is a typedef variant, walk the fields of its
+     underlying type.  */
+  if (typedef_variant_p (type))
+    WALK_SUBTREE (DECL_ORIGINAL_TYPE (TYPE_NAME (type)));
+
   switch (TREE_CODE (type))
     {
     case POINTER_TYPE:
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index dd0634b..41b0b1f 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -238,8 +238,6 @@  namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
       __lower_bound(_ForwardIterator __first, _ForwardIterator __last,
 		    const _Tp& __val, _Compare __comp)
       {
-	typedef typename __mv_iter_traits<_ForwardIterator>::value_type
-	  _ValueType;
 	typedef typename __mv_iter_traits<_ForwardIterator>::difference_type
 	  _DistanceType;
 
diff --git a/libstdc++-v3/src/istream.cc b/libstdc++-v3/src/istream.cc
index f161016..6bcf2db 100644
--- a/libstdc++-v3/src/istream.cc
+++ b/libstdc++-v3/src/istream.cc
@@ -280,7 +280,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       typedef basic_istream<char>       	__istream_type;
       typedef __istream_type::int_type		__int_type;
-      typedef __istream_type::char_type		__char_type;
       typedef __istream_type::traits_type	__traits_type;
       typedef __istream_type::__streambuf_type  __streambuf_type;
       typedef __istream_type::__ctype_type	__ctype_type;
@@ -364,7 +363,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef __istream_type::char_type		__char_type;
       typedef __istream_type::traits_type	__traits_type;
       typedef __istream_type::__streambuf_type  __streambuf_type;
-      typedef __istream_type::__ctype_type	__ctype_type;
       typedef basic_string<char>        	__string_type;
       typedef __string_type::size_type		__size_type;
 
@@ -610,7 +608,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef __istream_type::char_type		__char_type;
       typedef __istream_type::traits_type	__traits_type;
       typedef __istream_type::__streambuf_type  __streambuf_type;
-      typedef __istream_type::__ctype_type	__ctype_type;
       typedef basic_string<wchar_t>        	__string_type;
       typedef __string_type::size_type		__size_type;
 
diff --git a/libstdc++-v3/src/valarray.cc b/libstdc++-v3/src/valarray.cc
index 4d21ab1..5de146b 100644
--- a/libstdc++-v3/src/valarray.cc
+++ b/libstdc++-v3/src/valarray.cc
@@ -49,7 +49,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   inline size_t
   __valarray_product(const valarray<size_t>& __a)
   {
-    typedef const size_t* __restrict__ _Tp;
     const size_t __n = __a.size();
     // XXX: This ugly cast is necessary because
     //      valarray::operator[]() const return a VALUE!