@@ -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
@@ -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"
@@ -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. */
@@ -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);
@@ -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
@@ -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)
{
@@ -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);
@@ -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)
{
@@ -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"
@@ -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);
@@ -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.
@@ -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
@@ -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)
@@ -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)
@@ -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;
@@ -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
@@ -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. */
new file mode 100644
@@ -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)};
+}
@@ -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:
@@ -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;
@@ -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;
@@ -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!