c-tree.h (C_DECL_USED, [...]): New.

* c-tree.h (C_DECL_USED, parser_obstack, in_alignof, in_sizeof,
	in_typeof, record_maybe_used_decl, pop_maybe_used,
	c_expr_sizeof_expr, c_expr_sizeof_type): New.
	* c-decl.c (parser_obstack): New.
	(c_init_decl_processing): Initialize parser_obstack.
	(c_write_global_declarations_1): Check for used but undefined
	static functions.
	* c-parse.in (%union): Add otype.
	(save_obstack_position): New.
	(extdefs): Use it.
	(unary_expr): Update in_sizeof and in_alignof.  Use
	c_expr_sizeof_expr and c_expr_sizeof_type.
	(sizeof): Update in_sizeof.
	(alignof): Update in_alignof.
	(typeof): Update in_typeof.
	(typespec_nonreserved_nonattr): Call pop_maybe_used.
	* c-typeck.c (in_alignof, in_sizeof, in_typeof, struct
	maybe_used_decl, maybe_used_decls, record_maybe_used_decl,
	pop_maybe_used, c_expr_sizeof_expr, c_expr_sizeof_type): New.
	(build_external_ref): Set C_DECL_USED or call
	record_maybe_used_decl if appropriate.
	* toplev.c (check_global_declarations): Check TREE_NO_WARNING.

testsuite:
	* gcc.dg/c90-static-1.c, gcc.dg/c99-static-1.c,
	gcc.dg/gnu99-static-1.c: New tests.

From-SVN: r87216
This commit is contained in:
Joseph Myers 2004-09-09 02:16:16 +01:00 committed by Joseph Myers
parent 1835f9efd2
commit bc4b653be6
10 changed files with 282 additions and 14 deletions

View File

@ -1,3 +1,28 @@
2004-09-09 Joseph S. Myers <jsm@polyomino.org.uk>
* c-tree.h (C_DECL_USED, parser_obstack, in_alignof, in_sizeof,
in_typeof, record_maybe_used_decl, pop_maybe_used,
c_expr_sizeof_expr, c_expr_sizeof_type): New.
* c-decl.c (parser_obstack): New.
(c_init_decl_processing): Initialize parser_obstack.
(c_write_global_declarations_1): Check for used but undefined
static functions.
* c-parse.in (%union): Add otype.
(save_obstack_position): New.
(extdefs): Use it.
(unary_expr): Update in_sizeof and in_alignof. Use
c_expr_sizeof_expr and c_expr_sizeof_type.
(sizeof): Update in_sizeof.
(alignof): Update in_alignof.
(typeof): Update in_typeof.
(typespec_nonreserved_nonattr): Call pop_maybe_used.
* c-typeck.c (in_alignof, in_sizeof, in_typeof, struct
maybe_used_decl, maybe_used_decls, record_maybe_used_decl,
pop_maybe_used, c_expr_sizeof_expr, c_expr_sizeof_type): New.
(build_external_ref): Set C_DECL_USED or call
record_maybe_used_decl if appropriate.
* toplev.c (check_global_declarations): Check TREE_NO_WARNING.
2004-09-08 Eric Christopher <echristo@redhat.com>
* builtins.c: Fix prototype for fold_builtin_atan.

View File

@ -109,6 +109,11 @@ static location_t current_function_prototype_locus;
static GTY(()) tree current_function_arg_info;
/* The obstack on which parser and related data structures, which are
not live beyond their top-level declaration or definition, are
allocated. */
struct obstack parser_obstack;
/* The current statement tree. */
static GTY(()) struct stmt_tree_s c_stmt_tree;
@ -2526,6 +2531,8 @@ c_init_decl_processing (void)
current_function_decl = 0;
gcc_obstack_init (&parser_obstack);
/* Make the externals scope. */
push_scope ();
external_scope = current_scope;
@ -6936,7 +6943,21 @@ c_write_global_declarations_1 (tree globals)
/* Process the decls in the order they were written. */
for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
vec[i] = decl;
{
vec[i] = decl;
/* Check for used but undefined static functions using the C
standard's definition of "used", and set TREE_NO_WARNING so
that check_global_declarations doesn't repeat the check. */
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_INITIAL (decl) == 0
&& DECL_EXTERNAL (decl)
&& !TREE_PUBLIC (decl)
&& C_DECL_USED (decl))
{
pedwarn ("%J%<%F%> used but never defined", decl, decl);
TREE_NO_WARNING (decl) = 1;
}
}
wrapup_global_declarations (vec, len);
check_global_declarations (vec, len);

View File

@ -99,8 +99,8 @@ do { \
%start program
%union {long itype; tree ttype; struct c_expr exprtype; enum tree_code code;
location_t location; }
%union {long itype; tree ttype; void *otype; struct c_expr exprtype;
enum tree_code code; location_t location; }
/* All identifiers that are not reserved words
and are not declared typedefs in the current block */
@ -241,6 +241,8 @@ do { \
%type <itype> setspecs setspecs_fp extension
%type <location> save_location
%type <otype> save_obstack_position
@@ifobjc
/* the Objective-C nonterminals */
@ -360,8 +362,11 @@ program: /* empty */
can find a valid list of type and sc specs in $0. */
extdefs:
{$<ttype>$ = NULL_TREE; } extdef
| extdefs {$<ttype>$ = NULL_TREE; ggc_collect(); } extdef
save_obstack_position { $<ttype>$ = NULL_TREE; } extdef
{ obstack_free (&parser_obstack, $1); }
| extdefs save_obstack_position
{ $<ttype>$ = NULL_TREE; ggc_collect(); } extdef
{ obstack_free (&parser_obstack, $2); }
;
extdef:
@ -375,6 +380,12 @@ extdef:
@@end_ifobjc
;
/* Record the current position of parser_obstack before a
declaration to restore it afterwards. */
save_obstack_position:
{ $$ = obstack_alloc (&parser_obstack, 0); }
;
datadef:
setspecs notype_initdecls ';'
{ if (pedantic)
@ -506,21 +517,23 @@ unary_expr:
$$.original_code = ERROR_MARK; }
| sizeof unary_expr %prec UNARY
{ skip_evaluation--;
in_sizeof--;
if (TREE_CODE ($2.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND ($2.value, 1)))
error ("`sizeof' applied to a bit-field");
$$.value = c_sizeof (TREE_TYPE ($2.value));
$$.original_code = ERROR_MARK; }
$$ = c_expr_sizeof_expr ($2); }
| sizeof '(' typename ')' %prec HYPERUNARY
{ skip_evaluation--;
$$.value = c_sizeof (groktypename ($3));
$$.original_code = ERROR_MARK; }
in_sizeof--;
$$ = c_expr_sizeof_type ($3); }
| alignof unary_expr %prec UNARY
{ skip_evaluation--;
in_alignof--;
$$.value = c_alignof_expr ($2.value);
$$.original_code = ERROR_MARK; }
| alignof '(' typename ')' %prec HYPERUNARY
{ skip_evaluation--;
in_alignof--;
$$.value = c_alignof (groktypename ($3));
$$.original_code = ERROR_MARK; }
| REALPART cast_expr %prec UNARY
@ -532,15 +545,15 @@ unary_expr:
;
sizeof:
SIZEOF { skip_evaluation++; }
SIZEOF { skip_evaluation++; in_sizeof++; }
;
alignof:
ALIGNOF { skip_evaluation++; }
ALIGNOF { skip_evaluation++; in_alignof++; }
;
typeof:
TYPEOF { skip_evaluation++; }
TYPEOF { skip_evaluation++; in_typeof++; }
;
cast_expr:
@ -1376,12 +1389,15 @@ typespec_nonreserved_nonattr:
@@end_ifobjc
| typeof '(' expr ')'
{ skip_evaluation--;
in_typeof--;
if (TREE_CODE ($3.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND ($3.value, 1)))
error ("`typeof' applied to a bit-field");
$$ = TREE_TYPE ($3.value); }
$$ = TREE_TYPE ($3.value);
pop_maybe_used (variably_modified_type_p ($$, NULL_TREE)); }
| typeof '(' typename ')'
{ skip_evaluation--; $$ = groktypename ($3); }
{ skip_evaluation--; in_typeof--; $$ = groktypename ($3);
pop_maybe_used (variably_modified_type_p ($$, NULL_TREE)); }
;
/* typespec_nonreserved_attr does not exist. */

View File

@ -99,6 +99,12 @@ struct lang_type GTY(())
they may differ for structures with volatile fields. */
#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4 (EXP)
/* Record whether a decl was used in an expression anywhere except an
unevaluated operand of sizeof / typeof / alignof. This is only
used for functions declared static but not defined, though outside
sizeof and typeof it is set for other function decls as well. */
#define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (EXP)
/* Nonzero for a decl which either doesn't exist or isn't a prototype.
N.B. Could be simplified if all built-in decls had complete prototypes
(but this is presently difficult because some of them need FILE*). */
@ -151,6 +157,7 @@ extern void c_parse_init (void);
extern void gen_aux_info_record (tree, int, int, int);
/* in c-decl.c */
extern struct obstack parser_obstack;
extern tree c_break_label;
extern tree c_cont_label;
@ -224,6 +231,10 @@ extern void c_initialize_diagnostics (diagnostic_context *);
((VOLATILE_P) ? TYPE_QUAL_VOLATILE : 0))
/* in c-typeck.c */
extern int in_alignof;
extern int in_sizeof;
extern int in_typeof;
extern struct c_switch *c_switch_stack;
extern tree require_complete_type (tree);
@ -238,6 +249,10 @@ extern tree build_component_ref (tree, tree);
extern tree build_indirect_ref (tree, const char *);
extern tree build_array_ref (tree, tree);
extern tree build_external_ref (tree, int);
extern void record_maybe_used_decl (tree);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (struct c_expr);
extern struct c_expr c_expr_sizeof_type (tree);
extern struct c_expr parser_build_binary_op (enum tree_code, struct c_expr,
struct c_expr);
extern void readonly_error (tree, const char *);

View File

@ -44,6 +44,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-iterator.h"
#include "tree-gimple.h"
/* The level of nesting inside "__alignof__". */
int in_alignof;
/* The level of nesting inside "sizeof". */
int in_sizeof;
/* The level of nesting inside "typeof". */
int in_typeof;
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
@ -1751,6 +1759,16 @@ build_external_ref (tree id, int fun)
assemble_external (ref);
TREE_USED (ref) = 1;
if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
{
if (!in_sizeof && !in_typeof)
C_DECL_USED (ref) = 1;
else if (DECL_INITIAL (ref) == 0
&& DECL_EXTERNAL (ref)
&& !TREE_PUBLIC (ref))
record_maybe_used_decl (ref);
}
if (TREE_CODE (ref) == CONST_DECL)
{
ref = DECL_INITIAL (ref);
@ -1772,6 +1790,86 @@ build_external_ref (tree id, int fun)
return ref;
}
/* Record details of decls possibly used inside sizeof or typeof. */
struct maybe_used_decl
{
/* The decl. */
tree decl;
/* The level seen at (in_sizeof + in_typeof). */
int level;
/* The next one at this level or above, or NULL. */
struct maybe_used_decl *next;
};
static struct maybe_used_decl *maybe_used_decls;
/* Record that DECL, an undefined static function reference seen
inside sizeof or typeof, might be used if the operand of sizeof is
a VLA type or the operand of typeof is a variably modified
type. */
void
record_maybe_used_decl (tree decl)
{
struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
t->decl = decl;
t->level = in_sizeof + in_typeof;
t->next = maybe_used_decls;
maybe_used_decls = t;
}
/* Pop the stack of decls possibly used inside sizeof or typeof. If
USED is false, just discard them. If it is true, mark them used
(if no longer inside sizeof or typeof) or move them to the next
level up (if still inside sizeof or typeof). */
void
pop_maybe_used (bool used)
{
struct maybe_used_decl *p = maybe_used_decls;
int cur_level = in_sizeof + in_typeof;
while (p && p->level > cur_level)
{
if (used)
{
if (cur_level == 0)
C_DECL_USED (p->decl) = 1;
else
p->level = cur_level;
}
p = p->next;
}
if (!used || cur_level == 0)
maybe_used_decls = p;
}
/* Return the result of sizeof applied to EXPR. */
struct c_expr
c_expr_sizeof_expr (struct c_expr expr)
{
struct c_expr ret;
ret.value = c_sizeof (TREE_TYPE (expr.value));
ret.original_code = ERROR_MARK;
pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
return ret;
}
/* Return the result of sizeof applied to T, a structure for the type
name passed to sizeof (rather than the type itself). */
struct c_expr
c_expr_sizeof_type (tree t)
{
tree type;
struct c_expr ret;
type = groktypename (t);
ret.value = c_sizeof (type);
ret.original_code = ERROR_MARK;
pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
return ret;
}
/* Build a function call to function FUNCTION with parameters PARAMS.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
TREE_VALUE of each node is a parameter-expression.

View File

@ -1,3 +1,8 @@
2004-09-09 Joseph S. Myers <jsm@polyomino.org.uk>
* gcc.dg/c90-static-1.c, gcc.dg/c99-static-1.c,
gcc.dg/gnu99-static-1.c: New tests.
2004-09-08 Devang Patel <dpatel@apple.com>
* gcc.dg/darwin-ld-20040828-1.c: New test.

View File

@ -0,0 +1,22 @@
/* It is a constraint violation for a static function to be declared
but not defined if it is used except in a sizeof expression. The
use of the function simply being unevaluated is not enough. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "-O2 -std=iso9899:1990 -pedantic-errors" } */
/* Constraint violation (trivial case, where function is used). */
static void f0(void); /* { dg-error "used but never defined" } */
void g0(void) { f0(); }
/* Constraint violation. */
static void f1(void); /* { dg-error "used but never defined" } */
void g1(void) { if (0) { f1(); } }
/* Constraint violation. */
static int f2(void); /* { dg-error "used but never defined" } */
void g2(void) { 0 ? f2() : 0; }
/* OK. */
static int f3(void);
void g3(void) { sizeof(f3()); }

View File

@ -0,0 +1,35 @@
/* It is a constraint violation for a static function to be declared
but not defined if it is used except in a sizeof expression whose
result is an integer constant. The use of the function simply
being unevaluated is not enough. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "-O2 -std=iso9899:1999 -pedantic-errors" } */
/* Constraint violation (trivial case, where function is used). */
static void f0(void); /* { dg-error "used but never defined" } */
void g0(void) { f0(); }
/* Constraint violation. */
static void f1(void); /* { dg-error "used but never defined" } */
void g1(void) { if (0) { f1(); } }
/* Constraint violation. */
static int f2(void); /* { dg-error "used but never defined" } */
void g2(void) { 0 ? f2() : 0; }
/* OK. */
static int f3(void);
void g3(void) { sizeof(f3()); }
/* OK (VM type, not VLA). */
static int f4(void);
void g4(void) { sizeof(int (*)[f4()]); }
/* Constraint violation (VLA). */
static int f5(void); /* { dg-error "used but never defined" "VLA" { xfail *-*-* } } */
void g5(void) { sizeof(int [0 ? f5() : 1]); }
/* OK (non-constant sizeof inside constant sizeof). */
static int f6(void);
void g6(void) { sizeof(sizeof(int [f6()])); }

View File

@ -0,0 +1,30 @@
/* It is a constraint violation for a static function to be declared
but not defined if it is used except in a sizeof expression whose
result is an integer constant. In GNU C, we need to consider
__typeof__ and __alignof__ as well. __alignof__ always returns a
constant, so static functions can always be used therein.
__typeof__ evaluates its argument iff it has variably modified
type. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "-O2 -std=gnu99 -pedantic-errors" } */
/* __alignof__, OK. */
static int f0(void);
void g0(void) { __alignof__(f0()); }
/* __typeof__ not variably modified, OK. */
static int f1(void);
void g1(void) { __typeof__(f1()) x; }
/* __typeof__ variably modified, not OK. */
static int f2(void); /* { dg-error "used but never defined" } */
void g2(void) { __typeof__(int [f2()]) x; }
/* __typeof__ variably modified, not OK. */
static int f3(void); /* { dg-error "used but never defined" } */
void g3(void) { __typeof__(int (*)[f3()]) x; }
/* Integer sizeof of VM typeof, OK. */
static int f4(void);
void g4(void) { sizeof(__typeof__(int (*)[f3()])); }

View File

@ -840,6 +840,7 @@ check_global_declarations (tree *vec, int len)
&& DECL_INITIAL (decl) == 0
&& DECL_EXTERNAL (decl)
&& ! DECL_ARTIFICIAL (decl)
&& ! TREE_NO_WARNING (decl)
&& ! TREE_PUBLIC (decl)
&& (warn_unused_function
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))