I am friendly pinging this patch.
Dodji Seketeli <do...@redhat.com> a écrit: > Hello, > > Jason Merrill <ja...@redhat.com> writes: > >> On 08/06/2011 06:57 AM, Dodji Seketeli wrote: >> > @@ -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); >> >> Why is this still needed? > > It is not. I just forgot to remove it. Done now. > >> >> > +/* Return TRUE if DECL is declared in the current function. */ >> > + >> > +bool >> > +local_decl_p (tree decl) >> >> I don't think we need to work so hard to compare contexts to >> current_function_decl; just checking that the decl is in some function >> should be enough, i.e. decl_function_context is non-null. > > Thanks. I didn't know about decl_function_context. I grepped for > functions containing "local" in their names but I was doomed to > failure. I am using that now. > >> >> > + static int unused_local_typedefs_warn_count; >> >> This could use a comment. > > Added. > >> >> > +/* If T is a typedef variant type or a TYPE_DECL declared locally, >> > + mark it as used. */ >> > + >> > +void >> > +maybe_record_local_typedef_use (tree t) >> >> Does this still need to handle types? And the meaning of TREE_USED >> shouldn't change depending on a warning flag or whether a decl is >> local or not; let's just mark all TYPE_DECLs as used. > > OK, done. > >> >> Seems like we don't need local_decl_p at all; at the definition point, >> if we're in a function, a new declaration must be local enough for our >> purposes. >> >> > +void >> > +cp_maybe_record_local_typedef_use (tree t) >> > +{ >> > + /* If the current function is being instantiated, bail out. */ >> >> As above, I think we shouldn't put so many conditions on setting >> TREE_USED. > > I have removed cp_maybe_record_local_typedef_use altogether and just > use maybe_record_typedef_use now. > >> >> > @@ -19572,6 +19572,9 @@ cp_parser_lookup_name (cp_parser *parser, tree >> > name, >> > if (DECL_P (decl)) >> > check_accessibility_of_qualified_id (decl, object_type, >> > parser->scope); >> > >> > + cp_maybe_record_local_typedef_use (decl); >> > + cp_maybe_record_local_typedef_use (parser->scope); >> >> Why do we need to handle parser->scope? Wasn't it previously looked up? > > Sigh, my bad.. Fixed. > > Below is the updated patch that passed bootstrap and regression tests > on x86_64-unknown-linux-gnu against trunk. > > Thanks. > > From: Dodji Seketeli <do...@redhat.com> > Date: Mon, 25 Jul 2011 19:02:07 +0200 > Subject: [PATCH] PR c++/33255 - Support -Wunused-local-typedefs warning > > gcc/ > > * c-decl.c (lookup_name): Use the new > maybe_record_typedef_use. > (pushdecl): Use the new > record_locally_defined_typedef. > (store_parm_decls): Allocate cfun->language. > (finish_function): Use the new maybe_warn_unused_local_typedefs, > and mark cfun->language to be collected. > (c_push_function_context): Allocate cfun->language here only if > needed. > (c_pop_function_context): Likewise, mark cfun->language > for collection only when it should be done. > * c-typeck.c (c_expr_sizeof_type, c_cast_expr): Use the new > maybe_record_local_typedef_use. > > gcc/c-family > > * c-common.h (struct c_language_function::local_typedefs): New > field. > (record_locally_defined_typedef, maybe_record_typedef_use) > (maybe_warn_unused_local_typedefs): Declare new functions. > * c-common.c (record_locally_defined_typedef) > (maybe_record_typedef_use) > (maybe_warn_unused_local_typedefs): Define new functions. > * c.opt: Declare new -Wunused-local-typedefs flag. > > gcc/cp > > * name-lookup.c (pushdecl_maybe_friend_1): Use the new > record_locally_defined_typedef. > * decl.c (finish_function): Use the new > maybe_warn_unused_local_typedefs. > (grokfield): Use the new record_locally_defined_typedef. > * parser.c (lookup_name): Use the new maybe_record_typedef_use. > > gcc/doc/ > > * invoke.texi: Update documentation for -Wunused-local-typedefs. > > gcc/testsuite/ > > * g++.dg/warn/Wunused-local-typedefs.C: New test file. > * c-c++-common/Wunused-local-typedefs.c: Likewise. > > libstdc++-v3/ > > * include/ext/bitmap_allocator.h > (__detail::__mini_vector::__lower_bound): Remove unused typedef. > * src/istream.cc (std::operator>>(basic_istream<char>& __in, > basic_string<char>& __str)): Likewise. > (std::getline): Likewise. > * src/valarray.cc (__valarray_product): Likewise. > --- > gcc/c-decl.c | 38 +++++- > gcc/c-family/c-common.c | 71 ++++++++++ > gcc/c-family/c-common.h | 7 + > gcc/c-family/c.opt | 4 + > gcc/cp/decl.c | 4 + > gcc/cp/decl2.c | 1 + > gcc/cp/name-lookup.c | 7 + > gcc/cp/parser.c | 2 + > gcc/doc/invoke.texi | 9 +- > .../c-c++-common/Wunused-local-typedefs.c | 38 +++++ > gcc/testsuite/g++.dg/warn/Wunused-local-typedefs.C | 146 > ++++++++++++++++++++ > libstdc++-v3/include/ext/bitmap_allocator.h | 2 - > libstdc++-v3/src/istream.cc | 3 - > libstdc++-v3/src/valarray.cc | 1 - > 14 files changed, 319 insertions(+), 14 deletions(-) > create mode 100644 gcc/testsuite/c-c++-common/Wunused-local-typedefs.c > create mode 100644 gcc/testsuite/g++.dg/warn/Wunused-local-typedefs.C > > diff --git a/gcc/c-decl.c b/gcc/c-decl.c > index 33d2615..230f1a7 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); > > @@ -3435,7 +3443,10 @@ lookup_name (tree name) > { > struct c_binding *b = I_SYMBOL_BINDING (name); > if (b && !b->invisible) > - return b->decl; > + { > + maybe_record_typedef_use (b->decl); > + return b->decl; > + } > return 0; > } > > @@ -8158,6 +8169,9 @@ store_parm_decls (void) > /* Initialize the RTL code for the function. */ > allocate_struct_function (fndecl, false); > > + if (warn_unused_local_typedefs) > + cfun->language = ggc_alloc_cleared_language_function (); > + > /* Begin the statement tree for this function. */ > DECL_SAVED_TREE (fndecl) = push_stmt_list (); > > @@ -8265,6 +8279,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; > @@ -8310,6 +8328,8 @@ finish_function (void) > if (!decl_function_context (fndecl)) > undef_nested_function = false; > > + cfun->language = NULL; > + > /* We're leaving the context of this function, so zap cfun. > It's still in DECL_STRUCT_FUNCTION, and we'll restore it in > tree_rest_of_compilation. */ > @@ -8421,9 +8441,11 @@ check_for_loop_decls (location_t loc, bool > turn_off_iso_c99_error) > void > c_push_function_context (void) > { > - struct language_function *p; > - p = ggc_alloc_language_function (); > - cfun->language = p; > + struct language_function *p = cfun->language; > + /* cfun->language might have been already allocated by the use of > + -Wunused-local-typedefs. In that case, just re-use it. */ > + if (p == NULL) > + cfun->language = p = ggc_alloc_cleared_language_function (); > > p->base.x_stmt_tree = c_stmt_tree; > c_stmt_tree.x_cur_stmt_list > @@ -8449,7 +8471,11 @@ c_pop_function_context (void) > > pop_function_context (); > p = cfun->language; > - cfun->language = NULL; > + /* When -Wunused-local-typedefs is in effect, cfun->languages is > + used to store data throughout the life time of the current cfun, > + So don't deallocate it. */ > + if (!warn_unused_local_typedefs) > + cfun->language = NULL; > > if (DECL_STRUCT_FUNCTION (current_function_decl) == 0 > && DECL_SAVED_TREE (current_function_decl) == NULL_TREE) > diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c > index 96275ba..290240a 100644 > --- a/gcc/c-family/c-common.c > +++ b/gcc/c-family/c-common.c > @@ -9604,6 +9604,77 @@ record_types_used_by_current_var_decl (tree decl) > } > } > > +/* If DECL is a typedef that is declared in the current function, > + record it for the purpose of -Wunused-local-typedefs. */ > + > +void > +record_locally_defined_typedef (tree decl) > +{ > + struct c_language_function *l; > + > + if (!warn_unused_local_typedefs > + || cfun == NULL > + /* if this is not a locally defined typedef then we are not > + interested. */ > + || !is_typedef_decl (decl) > + || !decl_function_context (decl)) > + return; > + > + l = (struct c_language_function *) cfun->language; > + VEC_safe_push (tree, gc, l->local_typedefs, decl); > +} > + > +/* If T is a TYPE_DECL declared locally, mark it as used. */ > + > +void > +maybe_record_typedef_use (tree t) > +{ > + /* We want T to be either a type or a TYPE_DECL. */ > + if (!is_typedef_decl (t)) > + return; > + > + TREE_USED (t) = true; > +} > + > +/* Warn if there are some unused locally defined typedefs in the > + current function. */ > + > +void > +maybe_warn_unused_local_typedefs (void) > +{ > + int i; > + tree decl; > + /* The number of times we have emitted -Wunused-local-typedefs > + warnings. If this is different from errorcount, that means some > + unrelated errors have been issued. In which case, we'll avoid > + emitting "unused-local-typedefs" warnings. */ > + static int unused_local_typedefs_warn_count; > + struct c_language_function *l; > + > + if (cfun == NULL) > + return; > + > + if ((l = (struct c_language_function *) cfun->language) == NULL) > + return; > + > + if (warn_unused_local_typedefs > + && errorcount == unused_local_typedefs_warn_count) > + { > + FOR_EACH_VEC_ELT (tree, l->local_typedefs, i, decl) > + if (!TREE_USED (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 (l->local_typedefs) > + { > + VEC_free (tree, gc, l->local_typedefs); > + l->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 3a49779..6b324d4 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -505,6 +505,10 @@ struct GTY(()) c_language_function { > /* While we are parsing the function, this contains information > about the statement-tree that we are building. */ > struct stmt_tree_s x_stmt_tree; > + > + /* Vector of locally defined typedefs, for > + -Wunused-local-typedefs. */ > + VEC(tree,gc) *local_typedefs; > }; > > #define stmt_list_stack (current_stmt_tree ()->x_cur_stmt_list) > @@ -986,6 +990,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_typedef_use (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/cp/decl.c b/gcc/cp/decl.c > index f0d1a1a..cc06682 100644 > --- a/gcc/cp/decl.c > +++ b/gcc/cp/decl.c > @@ -13385,6 +13385,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..68e9b9b 100644 > --- a/gcc/cp/decl2.c > +++ b/gcc/cp/decl2.c > @@ -868,6 +868,7 @@ grokfield (const cp_declarator *declarator, > && TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))) != value) > set_underlying_type (value); > > + record_locally_defined_typedef (value); > return value; > } > > 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 9b3e56d..ba27acc 100644 > --- a/gcc/cp/parser.c > +++ b/gcc/cp/parser.c > @@ -19572,6 +19572,8 @@ cp_parser_lookup_name (cp_parser *parser, tree name, > if (DECL_P (decl)) > check_accessibility_of_qualified_id (decl, object_type, parser->scope); > > + maybe_record_typedef_use (decl); > + > return decl; > } > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 6fd78d5..5430803 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/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/testsuite/g++.dg/warn/Wunused-local-typedefs.C > b/gcc/testsuite/g++.dg/warn/Wunused-local-typedefs.C > new file mode 100644 > index 0000000..87feb52 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/Wunused-local-typedefs.C > @@ -0,0 +1,146 @@ > +// 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" } > +} > + > +struct S > +{ > + typedef int T; > + S() {} > + S(int) {} > +}; > + > +template<class T> > +struct ST > +{ > + typedef T type; > + ST (int) {} > + ST () {} > +}; > + > +template<class T> > +void > +test0_tmpl(void) > +{ > + typedef struct ST<T> foo; > + foo(2); > +} > + > +int > +test0(void) > +{ > + test0_tmpl<int>(); > +} > + > +void > +test1(void) > +{ > + typedef int foo; > + ST<foo> a; > +} > + > + > +int > +test2(void) > +{ > + typedef S foo; > + foo::T i = 0; > + return i; > +} > + > +template<class T> > +void > +test3_tmpl(void) > +{ > + typedef struct ST<int> foo; > + ST<int> v; > + const foo &var = v; > +} > + > +void > +test3(void) > +{ > + test3_tmpl<int>(); > +} > + > +void > +test4(void) > +{ > + typedef int foo; > + int vec[1] = {sizeof (foo)}; > +} > + > +void > +test5(void) > +{ > + typedef int T0; > + typedef char T1; > + typedef int* T2; > + typedef unsigned T3; > + struct C0 { virtual void f(void) {}}; > + struct C1 : C0 {}; > + typedef C0 T4; > + > + int v0 = (T0) 2; > + char v1 = static_cast<T1> (0); > + reinterpret_cast<T2> (&v0); > + unsigned* const c = 0; > + unsigned* v2 = const_cast<T3* const> (c); > + C0 *p0 = 0; > + C1 *p1 = 0; > + p0 = dynamic_cast<T4*> (p1); > +} > + > +void > +test6(void) > +{ > + struct C0 {}; > + typedef C0 foo; > + C0 *v = new foo; > +} > + > +template<class T, class U> > +struct S7 > +{ > + void > + f() > + { > + typedef int foo; > + sizeof(foo); > + } > +}; > + > +template<class T> > +void > +test7(void) > +{ > + typedef typename ST<T>::T bar; // { dg-warning "locally defined but not > used" } > + typedef typename ST<T>::T foo; // We shouldn't warn for this one, as > + // it's used below. > + S7<int, foo> v; > +} > + > + > +template<class T, class U> > +void > +test8(void) > +{ > + int f(S7<T, U>); > + void g(int); > + typedef T foo; > + g(f(S7<foo, U>())); > +} > + > +int > +test9(void) > +{ > + struct s { typedef int foo;}; // { dg-warning "locally defined but not > used" } > + struct t { typedef int bar;}; > + t::bar b = 0; > + return b; > +} > 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! -- Dodji