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

* c-tree.h (enum c_typespec_kind, struct c_typespec,
	parser_xref_tag): New.
	(struct c_declspecs): Add tag_defined_p.  Adjust definition of
	typedef_p.
	(declspecs_add_type): Adjust prototypes.
	* c-parse.in (%union): Add tstype.
	(typespec_nonattr, typespec_attr, typespec_reserved_nonattr,
	typespec_reserved_attr, typespec_nonreserved_nonattr,
	structsp_attr, structsp_nonattr): Change to tstype.  Update
	actions.
	* c-decl.c (build_null_declspecs): Initialize tag_defined_p.
	(declspecs_add_type): Update to take struct c_typespec argument.
	Set tag_defined_p and typedef_p as appropriate.
	(xref_tag): Rename to parser_xref_tag and replace by wrapper.
	Update to return struct c_typespec.
	(shadow_tag_warned): Don't let empty declarations with qualifiers
	or storage class specifiers redeclare a tag if a previous
	declaration is visible.

testsuite:
	* gcc.dg/c99-tag-3.c, gcc.dg/declspec-14.c: New tests.

From-SVN: r89021
This commit is contained in:
Joseph Myers 2004-10-14 01:34:01 +01:00 committed by Joseph Myers
parent 599a049f76
commit 81da229b08
7 changed files with 246 additions and 46 deletions

View File

@ -1,3 +1,24 @@
2004-10-14 Joseph S. Myers <jsm@polyomino.org.uk>
* c-tree.h (enum c_typespec_kind, struct c_typespec,
parser_xref_tag): New.
(struct c_declspecs): Add tag_defined_p. Adjust definition of
typedef_p.
(declspecs_add_type): Adjust prototypes.
* c-parse.in (%union): Add tstype.
(typespec_nonattr, typespec_attr, typespec_reserved_nonattr,
typespec_reserved_attr, typespec_nonreserved_nonattr,
structsp_attr, structsp_nonattr): Change to tstype. Update
actions.
* c-decl.c (build_null_declspecs): Initialize tag_defined_p.
(declspecs_add_type): Update to take struct c_typespec argument.
Set tag_defined_p and typedef_p as appropriate.
(xref_tag): Rename to parser_xref_tag and replace by wrapper.
Update to return struct c_typespec.
(shadow_tag_warned): Don't let empty declarations with qualifiers
or storage class specifiers redeclare a tag if a previous
declaration is visible.
2004-10-13 Richard Henderson <rth@redhat.com>
PR debug/15860

View File

@ -2696,8 +2696,6 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
{
bool found_tag = false;
pending_invalid_xref = 0;
if (declspecs->type && !declspecs->default_int_p && !declspecs->typedef_p)
{
tree value = declspecs->type;
@ -2721,8 +2719,29 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
warned = 1;
}
}
else if (!declspecs->tag_defined_p
&& declspecs->storage_class != csc_none)
{
if (warned != 1)
pedwarn ("empty declaration with storage class specifier "
"does not redeclare tag");
warned = 1;
pending_xref_error ();
}
else if (!declspecs->tag_defined_p
&& (declspecs->const_p
|| declspecs->volatile_p
|| declspecs->restrict_p))
{
if (warned != 1)
pedwarn ("empty declaration with type qualifier "
"does not redeclare tag");
warned = 1;
pending_xref_error ();
}
else
{
pending_invalid_xref = 0;
t = lookup_tag (code, name, 1);
if (t == 0)
@ -2747,6 +2766,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
warned = 1;
}
pending_invalid_xref = 0;
if (declspecs->inline_p)
{
error ("%<inline%> in empty declaration");
@ -4877,11 +4898,13 @@ get_parm_info (bool ellipsis)
}
/* Get the struct, enum or union (CODE says which) with tag NAME.
Define the tag as a forward-reference if it is not defined. */
Define the tag as a forward-reference if it is not defined.
Return a c_typespec structure for the type specifier. */
tree
xref_tag (enum tree_code code, tree name)
struct c_typespec
parser_xref_tag (enum tree_code code, tree name)
{
struct c_typespec ret;
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
@ -4897,8 +4920,12 @@ xref_tag (enum tree_code code, tree name)
this would not work properly if we return the reference found.
(For example, with "struct foo" in an outer scope, "union foo;"
must shadow that tag with a new one of union type.) */
ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref);
if (ref && TREE_CODE (ref) == code)
return ref;
{
ret.spec = ref;
return ret;
}
/* If no such tag is yet defined, create a forward-reference node
and record it as the "definition".
@ -4921,7 +4948,18 @@ xref_tag (enum tree_code code, tree name)
pushtag (name, ref);
return ref;
ret.spec = ref;
return ret;
}
/* Get the struct, enum or union (CODE says which) with tag NAME.
Define the tag as a forward-reference if it is not defined.
Return a tree for the type. */
tree
xref_tag (enum tree_code code, tree name)
{
return parser_xref_tag (code, name).spec;
}
/* Make sure that the tag NAME is defined *in the current scope*
@ -6643,6 +6681,7 @@ build_null_declspecs (void)
ret->storage_class = csc_none;
ret->non_sc_seen_p = false;
ret->typedef_p = false;
ret->tag_defined_p = false;
ret->explicit_signed_p = false;
ret->deprecated_p = false;
ret->default_int_p = false;
@ -6698,8 +6737,9 @@ declspecs_add_qual (struct c_declspecs *specs, tree qual)
returning SPECS. */
struct c_declspecs *
declspecs_add_type (struct c_declspecs *specs, tree type)
declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
{
tree type = spec.spec;
specs->non_sc_seen_p = true;
if (TREE_DEPRECATED (type))
specs->deprecated_p = true;
@ -6975,7 +7015,13 @@ declspecs_add_type (struct c_declspecs *specs, tree type)
specs->type = TREE_TYPE (t);
}
else if (TREE_CODE (type) != ERROR_MARK)
specs->type = type;
{
if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
specs->tag_defined_p = true;
if (spec.kind == ctsk_typeof)
specs->typedef_p = true;
specs->type = type;
}
return specs;
}

View File

@ -101,8 +101,8 @@ do { \
%union {long itype; tree ttype; void *otype; struct c_expr exprtype;
struct c_arg_info *arginfotype; struct c_declarator *dtrtype;
struct c_type_name *typenametype; struct c_parm *parmtype;
struct c_declspecs *dsptype; enum tree_code code;
location_t location; }
struct c_declspecs *dsptype; struct c_typespec tstype;
enum tree_code code; location_t location; }
/* All identifiers that are not reserved words
and are not declared typedefs in the current block */
@ -202,9 +202,9 @@ do { \
%type <dsptype> declspecs_ts_nosa declspecs_nots_nosa
%type <dsptype> declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs
%type <dsptype> maybe_type_quals_attrs
%type <ttype> typespec_nonattr typespec_attr
%type <ttype> typespec_reserved_nonattr typespec_reserved_attr
%type <ttype> typespec_nonreserved_nonattr
%type <tstype> typespec_nonattr typespec_attr
%type <tstype> typespec_reserved_nonattr typespec_reserved_attr
%type <tstype> typespec_nonreserved_nonattr
%type <ttype> offsetof_member_designator
%type <ttype> scspec SCSPEC STATIC TYPESPEC TYPE_QUAL maybe_volatile
@ -226,7 +226,7 @@ do { \
%type <dtrtype> parm_declarator_starttypename parm_declarator_nostarttypename
%type <dtrtype> array_declarator
%type <ttype> structsp_attr structsp_nonattr
%type <tstype> structsp_attr structsp_nonattr
%type <ttype> component_decl_list component_decl_list2
%type <ttype> component_decl components components_notype component_declarator
%type <ttype> component_notype_declarator
@ -1262,7 +1262,9 @@ typespec_attr:
typespec_reserved_nonattr:
TYPESPEC
{ OBJC_NEED_RAW_IDENTIFIER (1); }
{ OBJC_NEED_RAW_IDENTIFIER (1);
$$.kind = ctsk_resword;
$$.spec = $1; }
| structsp_nonattr
;
@ -1274,17 +1276,21 @@ typespec_nonreserved_nonattr:
TYPENAME
{ /* For a typedef name, record the meaning, not the name.
In case of `foo foo, bar;'. */
$$ = lookup_name ($1); }
$$.kind = ctsk_typedef;
$$.spec = lookup_name ($1); }
@@ifobjc
| CLASSNAME protocolrefs
{ $$ = objc_get_protocol_qualified_type ($1, $2); }
{ $$.kind = ctsk_objc;
$$.spec = objc_get_protocol_qualified_type ($1, $2); }
| OBJECTNAME protocolrefs
{ $$ = objc_get_protocol_qualified_type ($1, $2); }
{ $$.kind = ctsk_objc;
$$.spec = objc_get_protocol_qualified_type ($1, $2); }
/* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
- nisse@lysator.liu.se */
| non_empty_protocolrefs
{ $$ = objc_get_protocol_qualified_type (NULL_TREE, $1); }
{ $$.kind = ctsk_objc;
$$.spec = objc_get_protocol_qualified_type (NULL_TREE, $1); }
@@end_ifobjc
| typeof '(' expr ')'
{ skip_evaluation--;
@ -1292,11 +1298,17 @@ typespec_nonreserved_nonattr:
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);
pop_maybe_used (variably_modified_type_p ($$, NULL_TREE)); }
$$.kind = ctsk_typeof;
$$.spec = TREE_TYPE ($3.value);
pop_maybe_used (variably_modified_type_p ($$.spec,
NULL_TREE)); }
| typeof '(' typename ')'
{ skip_evaluation--; in_typeof--; $$ = groktypename ($3);
pop_maybe_used (variably_modified_type_p ($$, NULL_TREE)); }
{ skip_evaluation--;
in_typeof--;
$$.kind = ctsk_typeof;
$$.spec = groktypename ($3);
pop_maybe_used (variably_modified_type_p ($$.spec,
NULL_TREE)); }
;
/* typespec_nonreserved_attr does not exist. */
@ -1639,47 +1651,55 @@ enum_head:
structsp_attr:
struct_head identifier '{'
{ $$ = start_struct (RECORD_TYPE, $2);
{ $<ttype>$ = start_struct (RECORD_TYPE, $2);
/* Start scope of tag before parsing components. */
}
component_decl_list '}' maybe_attribute
{ $$ = finish_struct ($<ttype>4, nreverse ($5),
chainon ($1, $7)); }
{ $$.spec = finish_struct ($<ttype>4, nreverse ($5),
chainon ($1, $7));
$$.kind = ctsk_tagdef; }
| struct_head '{' component_decl_list '}' maybe_attribute
{ $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
nreverse ($3), chainon ($1, $5));
{ $$.spec = finish_struct (start_struct (RECORD_TYPE,
NULL_TREE),
nreverse ($3), chainon ($1, $5));
$$.kind = ctsk_tagdef;
}
| union_head identifier '{'
{ $$ = start_struct (UNION_TYPE, $2); }
{ $<ttype>$ = start_struct (UNION_TYPE, $2); }
component_decl_list '}' maybe_attribute
{ $$ = finish_struct ($<ttype>4, nreverse ($5),
chainon ($1, $7)); }
{ $$.spec = finish_struct ($<ttype>4, nreverse ($5),
chainon ($1, $7));
$$.kind = ctsk_tagdef; }
| union_head '{' component_decl_list '}' maybe_attribute
{ $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
nreverse ($3), chainon ($1, $5));
{ $$.spec = finish_struct (start_struct (UNION_TYPE,
NULL_TREE),
nreverse ($3), chainon ($1, $5));
$$.kind = ctsk_tagdef;
}
| enum_head identifier '{'
{ $$ = start_enum ($2); }
{ $<ttype>$ = start_enum ($2); }
enumlist maybecomma_warn '}' maybe_attribute
{ $$ = finish_enum ($<ttype>4, nreverse ($5),
chainon ($1, $8)); }
{ $$.spec = finish_enum ($<ttype>4, nreverse ($5),
chainon ($1, $8));
$$.kind = ctsk_tagdef; }
| enum_head '{'
{ $$ = start_enum (NULL_TREE); }
{ $<ttype>$ = start_enum (NULL_TREE); }
enumlist maybecomma_warn '}' maybe_attribute
{ $$ = finish_enum ($<ttype>3, nreverse ($4),
chainon ($1, $7)); }
{ $$.spec = finish_enum ($<ttype>3, nreverse ($4),
chainon ($1, $7));
$$.kind = ctsk_tagdef; }
;
structsp_nonattr:
struct_head identifier
{ $$ = xref_tag (RECORD_TYPE, $2); }
{ $$ = parser_xref_tag (RECORD_TYPE, $2); }
| union_head identifier
{ $$ = xref_tag (UNION_TYPE, $2); }
{ $$ = parser_xref_tag (UNION_TYPE, $2); }
| enum_head identifier
{ $$ = xref_tag (ENUMERAL_TYPE, $2);
{ $$ = parser_xref_tag (ENUMERAL_TYPE, $2);
/* In ISO C, enumerated types can be referred to
only if already defined. */
if (pedantic && !COMPLETE_TYPE_P ($$))
if (pedantic && !COMPLETE_TYPE_P ($$.spec))
pedwarn ("ISO C forbids forward references to %<enum%> types"); }
;

View File

@ -131,6 +131,39 @@ struct c_expr
enum tree_code original_code;
};
/* A kind of type specifier. Note that this information is currently
only used to distinguish tag definitions, tag references and typeof
uses. */
enum c_typespec_kind {
/* A reserved keyword type specifier. */
ctsk_resword,
/* A reference to a tag, previously declared, such as "struct foo".
This includes where the previous declaration was as a different
kind of tag, in which case this is only valid if shadowing that
tag in an inner scope. */
ctsk_tagref,
/* A reference to a tag, not previously declared in a visible
scope. */
ctsk_tagfirstref,
/* A definition of a tag such as "struct foo { int a; }". */
ctsk_tagdef,
/* A typedef name. */
ctsk_typedef,
/* An ObjC-specific kind of type specifier. */
ctsk_objc,
/* A typeof specifier. */
ctsk_typeof
};
/* A type specifier: this structure is created in the parser and
passed to declspecs_add_type only. */
struct c_typespec {
/* What kind of type specifier this is. */
enum c_typespec_kind kind;
/* The specifier itself. */
tree spec;
};
/* A storage class specifier. */
enum c_storage_class {
csc_none,
@ -178,8 +211,12 @@ struct c_declspecs {
specifiers to be handled separately from storage class
specifiers.) */
BOOL_BITFIELD non_sc_seen_p : 1;
/* Whether the type is specified by a typedef. */
/* Whether the type is specified by a typedef or typeof name. */
BOOL_BITFIELD typedef_p : 1;
/* Whether a struct, union or enum type either had its content
defined by a type specifier in the list or was the first visible
declaration of its tag. */
BOOL_BITFIELD tag_defined_p : 1;
/* Whether the type is explicitly "signed" or specified by a typedef
whose type is explicitly "signed". */
BOOL_BITFIELD explicit_signed_p : 1;
@ -371,6 +408,7 @@ extern tree start_struct (enum tree_code, tree);
extern void store_parm_decls (void);
extern void store_parm_decls_from (struct c_arg_info *);
extern tree xref_tag (enum tree_code, tree);
extern struct c_typespec parser_xref_tag (enum tree_code, tree);
extern int c_expand_decl (tree);
extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
struct c_declarator *);
@ -383,7 +421,8 @@ extern struct c_declarator *make_pointer_declarator (struct c_declspecs *,
struct c_declarator *);
extern struct c_declspecs *build_null_declspecs (void);
extern struct c_declspecs *declspecs_add_qual (struct c_declspecs *, tree);
extern struct c_declspecs *declspecs_add_type (struct c_declspecs *, tree);
extern struct c_declspecs *declspecs_add_type (struct c_declspecs *,
struct c_typespec);
extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree);
extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree);
extern struct c_declspecs *finish_declspecs (struct c_declspecs *);

View File

@ -1,3 +1,7 @@
2004-10-14 Joseph S. Myers <jsm@polyomino.org.uk>
* gcc.dg/c99-tag-3.c, gcc.dg/declspec-14.c: New tests.
2004-10-14 Hans-Peter Nilsson <hp@axis.com>
PR target/17984

View File

@ -0,0 +1,59 @@
/* Test for handling of tags. "const struct foo;" and similar does
not redeclare an existing tag. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
/* Plain "struct s;" always declares a tag: the same as one declared
in that scope, or shadowing one from an outer scope. */
struct s0;
struct s0 { int a; };
struct s0;
void f (void) { struct s0; }
/* A declaration with a qualifier or storage class specifier declares
the tag if no other declaration of it is visible. */
const union u0; /* { dg-warning "warning: useless type qualifier in empty declaration" } */
union u0 { long b; };
extern struct s1; /* { dg-warning "warning: useless storage class specifier in empty declaration" } */
/* But if a declaration of the tag is visible, whether at the same
scope or an outer scope, the declaration specifies the same type as
the previous declaration and does not redeclare the tag (C99
6.7.2.3#8). Thus, as it does not declare a declarator, a tag or
the members of an enumeration, it is a constraint violation. */
struct s2 { char x; };
const struct s2; /* { dg-error "error: empty declaration with type qualifier does not redeclare tag" } */
union u1;
extern union u1; /* { dg-error "error: empty declaration with storage class specifier does not redeclare tag" } */
union u2 { long b; };
void g(void) { const union u2; } /* { dg-error "error: empty declaration with type qualifier does not redeclare tag" } */
/* And it does not redeclare the tag either if the outer tag is the
wrong kind of tag. This also yields an error for the reference to
the wrong kind of tag in addition to the pedwarn for the empty
declaration. */
union u3 { float v; };
void h(void) { const struct u3; } /* { dg-error "'u3' defined as wrong kind of tag" } */
/* { dg-error "error: empty declaration with type qualifier does not redeclare tag" "wrong tag empty" { target *-*-* } 42 } */
/* However, such useless specifiers are OK if the contents of the tag
are being defined, or shadowed in an inner scope with the contents
included in the shadowing. */
struct s3;
const struct s3 { int a; }; /* { dg-warning "warning: useless type qualifier in empty declaration" } */
union u4;
extern union u4 { int z; }; /* { dg-warning "warning: useless storage class specifier in empty declaration" } */
enum e0 { E0 };
void i(void) { const enum e0 { E1 }; } /* { dg-warning "warning: useless type qualifier in empty declaration" } */
union u5 { int p; };
void j(void) { extern struct u5 { int q; }; } /* { dg-warning "warning: useless storage class specifier in empty declaration" } */

View File

@ -0,0 +1,11 @@
/* Test that "typeof(struct foo)" and similar as declaration
specifiers act like typedef. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "" } */
typeof(struct foo); /* { dg-warning "warning: useless type name in empty declaration" } */
struct bar { int a; } x;
typeof(x); /* { dg-warning "warning: useless type name in empty declaration" } */