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:
parent
599a049f76
commit
81da229b08
@ -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
|
||||
|
64
gcc/c-decl.c
64
gcc/c-decl.c
@ -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;
|
||||
}
|
||||
|
@ -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"); }
|
||||
;
|
||||
|
||||
|
43
gcc/c-tree.h
43
gcc/c-tree.h
@ -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 *);
|
||||
|
@ -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
|
||||
|
59
gcc/testsuite/gcc.dg/c99-tag-3.c
Normal file
59
gcc/testsuite/gcc.dg/c99-tag-3.c
Normal 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" } */
|
11
gcc/testsuite/gcc.dg/declspec-14.c
Normal file
11
gcc/testsuite/gcc.dg/declspec-14.c
Normal 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" } */
|
Loading…
Reference in New Issue
Block a user