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:
parent
1835f9efd2
commit
bc4b653be6
@ -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.
|
||||
|
23
gcc/c-decl.c
23
gcc/c-decl.c
@ -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);
|
||||
|
@ -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. */
|
||||
|
15
gcc/c-tree.h
15
gcc/c-tree.h
@ -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 *);
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
22
gcc/testsuite/gcc.dg/c90-static-1.c
Normal file
22
gcc/testsuite/gcc.dg/c90-static-1.c
Normal 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()); }
|
35
gcc/testsuite/gcc.dg/c99-static-1.c
Normal file
35
gcc/testsuite/gcc.dg/c99-static-1.c
Normal 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()])); }
|
30
gcc/testsuite/gcc.dg/gnu99-static-1.c
Normal file
30
gcc/testsuite/gcc.dg/gnu99-static-1.c
Normal 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()])); }
|
@ -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))))
|
||||
|
Loading…
Reference in New Issue
Block a user