From: Joseph Myers Date: Thu, 10 May 2001 16:17:07 +0000 (+0100) Subject: c-parse.in: Remove many shift/reduce conflicts. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=25d78ace728bb05ef85d359f7c2b123cb7581475;p=gcc.git c-parse.in: Remove many shift/reduce conflicts. * c-parse.in: Remove many shift/reduce conflicts. Update %expect values. (declspecs_nosc_nots_nosa_noea, declspecs_nosc_nots_nosa_ea, declspecs_nosc_nots_sa_noea, declspecs_nosc_nots_sa_ea, declspecs_nosc_ts_nosa_noea, declspecs_nosc_ts_nosa_ea, declspecs_nosc_ts_sa_noea, declspecs_nosc_ts_sa_ea, declspecs_sc_nots_nosa_noea, declspecs_sc_nots_nosa_ea, declspecs_sc_nots_sa_noea, declspecs_sc_nots_sa_ea, declspecs_sc_ts_nosa_noea, declspecs_sc_ts_nosa_ea, declspecs_sc_ts_sa_noea, declspecs_sc_ts_sa_ea, declspecs_ts, declspecs_nots, declspecs_ts_nosa, declspecs_nots_nosa, declspecs_nosc_ts, declspecs_nosc_nots, declspecs_nosc, declspecs, maybe_type_quals_setattrs, typespec_nonattr, typespec_attr, typespec_reserved_nonattr, typespec_reserved_attr, typespec_nonreserved_nonattr, maybe_setattrs, structsp_attr, structsp_nonattr, components_notype, component_notype_declarator, absdcl1_ea, absdcl1_noea, direct_absdcl1, absdcl_maybe_attribute, firstparm, setspecs_fp): New (typed_declspecs, reserved_declspecs, typed_typespecs, reserved_typespecquals, declmods, typespec, typespecqual_reserved, typed_declspecs_no_prefix_attr reserved_declspecs_no_prefix_attr declmods_no_prefix_attr, nonempty_type_quals, structsp, type_quals): Remove. Users updated. (initdecls, notype_initdecls, after_type_declarator, parm_declarator, notype_declarator, absdcl1, components, ivars): Don't allow attributes at the start of a declarator; include them in the production containing the declarator instead. Always require type specifiers before trying to redeclare a typedef name. (typename): Allow for attributes but warn that they are ignored. (parmlist, firstparm, setspecs_fp): Include attributes in parmlist; suck them off the parser stack in firstparm using setspecs_fp. testsuite: * gcc.c-torture/compile/20010313-1.c: New test. From-SVN: r41940 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c6401124b24..db35f560fd0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,38 @@ +2001-05-10 Joseph S. Myers + + * c-parse.in: Remove many shift/reduce conflicts. Update + %expect values. + (declspecs_nosc_nots_nosa_noea, declspecs_nosc_nots_nosa_ea, + declspecs_nosc_nots_sa_noea, declspecs_nosc_nots_sa_ea, + declspecs_nosc_ts_nosa_noea, declspecs_nosc_ts_nosa_ea, + declspecs_nosc_ts_sa_noea, declspecs_nosc_ts_sa_ea, + declspecs_sc_nots_nosa_noea, declspecs_sc_nots_nosa_ea, + declspecs_sc_nots_sa_noea, declspecs_sc_nots_sa_ea, + declspecs_sc_ts_nosa_noea, declspecs_sc_ts_nosa_ea, + declspecs_sc_ts_sa_noea, declspecs_sc_ts_sa_ea, declspecs_ts, + declspecs_nots, declspecs_ts_nosa, declspecs_nots_nosa, + declspecs_nosc_ts, declspecs_nosc_nots, declspecs_nosc, declspecs, + maybe_type_quals_setattrs, typespec_nonattr, typespec_attr, + typespec_reserved_nonattr, typespec_reserved_attr, + typespec_nonreserved_nonattr, maybe_setattrs, structsp_attr, + structsp_nonattr, components_notype, component_notype_declarator, + absdcl1_ea, absdcl1_noea, direct_absdcl1, absdcl_maybe_attribute, + firstparm, setspecs_fp): New + (typed_declspecs, reserved_declspecs, typed_typespecs, + reserved_typespecquals, declmods, typespec, typespecqual_reserved, + typed_declspecs_no_prefix_attr reserved_declspecs_no_prefix_attr + declmods_no_prefix_attr, nonempty_type_quals, structsp, + type_quals): Remove. Users updated. + (initdecls, notype_initdecls, after_type_declarator, + parm_declarator, notype_declarator, absdcl1, components, ivars): + Don't allow attributes at the start of a declarator; include them + in the production containing the declarator instead. Always + require type specifiers before trying to redeclare a typedef name. + (typename): Allow for attributes but warn that they are ignored. + (parmlist, firstparm, setspecs_fp): Include attributes in + parmlist; suck them off the parser stack in firstparm using + setspecs_fp. + Thu May 10 09:17:42 2001 Jeffrey A Law (law@cygnus.com) * ifcvt.c (merge_if_block): Use any_uncondjump_p, not simplejump_p diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 657c3fb700b..e91f9ebdf9f 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -29,10 +29,10 @@ Boston, MA 02111-1307, USA. */ written by AT&T, but I have never seen it. */ ifobjc -%expect 74 +%expect 31 end ifobjc ifc -%expect 53 +%expect 10 end ifc %{ @@ -167,16 +167,27 @@ end ifc %type identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist %type expr_no_commas cast_expr unary_expr primary string STRING -%type typed_declspecs reserved_declspecs -%type typed_typespecs reserved_typespecquals -%type declmods typespec typespecqual_reserved -%type typed_declspecs_no_prefix_attr reserved_declspecs_no_prefix_attr -%type declmods_no_prefix_attr -%type SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual +%type declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea +%type declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea +%type declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea +%type declspecs_nosc_ts_sa_noea declspecs_nosc_ts_sa_ea +%type declspecs_sc_nots_nosa_noea declspecs_sc_nots_nosa_ea +%type declspecs_sc_nots_sa_noea declspecs_sc_nots_sa_ea +%type declspecs_sc_ts_nosa_noea declspecs_sc_ts_nosa_ea +%type declspecs_sc_ts_sa_noea declspecs_sc_ts_sa_ea +%type declspecs_ts declspecs_nots +%type declspecs_ts_nosa declspecs_nots_nosa +%type declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs +%type maybe_type_quals_setattrs typespec_nonattr typespec_attr +%type typespec_reserved_nonattr typespec_reserved_attr +%type typespec_nonreserved_nonattr + +%type SCSPEC TYPESPEC TYPE_QUAL maybe_type_qual %type initdecls notype_initdecls initdcl notype_initdcl %type init maybeasm %type asm_operands nonnull_asm_operands asm_operand asm_clobbers %type maybe_attribute attributes attribute attribute_list attrib +%type maybe_setattrs %type any_word extension %type compstmt compstmt_start compstmt_nostart compstmt_primary_start @@ -187,18 +198,21 @@ end ifc %type notype_declarator after_type_declarator %type parm_declarator -%type structsp component_decl_list component_decl_list2 -%type component_decl components component_declarator +%type structsp_attr structsp_nonattr +%type component_decl_list component_decl_list2 +%type component_decl components components_notype component_declarator +%type component_notype_declarator %type enumlist enumerator %type struct_head union_head enum_head -%type typename absdcl absdcl1 type_quals -%type xexpr parms parm identifiers +%type typename absdcl absdcl1 absdcl1_ea absdcl1_noea +%type direct_absdcl1 absdcl_maybe_attribute +%type xexpr parms parm firstparm identifiers %type parmlist parmlist_1 parmlist_2 %type parmlist_or_identifiers parmlist_or_identifiers_1 %type identifiers_or_typenames -%type setspecs +%type setspecs setspecs_fp %type save_filename %type save_lineno @@ -345,17 +359,15 @@ datadef: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods setspecs notype_initdecls ';' + | declspecs_nots setspecs notype_initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs setspecs initdecls ';' + | declspecs_ts setspecs initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods ';' - { pedwarn ("empty declaration"); } - | typed_declspecs ';' + | declspecs ';' { shadow_tag ($1); } | error ';' | error '}' @@ -365,7 +377,7 @@ datadef: ; fndef: - typed_declspecs setspecs declarator + declspecs_ts setspecs declarator { if (! start_function (current_declspecs, $3, prefix_attributes, NULL_TREE)) YYERROR1; @@ -379,11 +391,11 @@ fndef: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs setspecs declarator error + | declspecs_ts setspecs declarator error { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods setspecs notype_declarator + | declspecs_nots setspecs notype_declarator { if (! start_function (current_declspecs, $3, prefix_attributes, NULL_TREE)) YYERROR1; @@ -397,7 +409,7 @@ fndef: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods setspecs notype_declarator error + | declspecs_nots setspecs notype_declarator error { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } @@ -816,18 +828,18 @@ datadecls: attribute suffix, or function defn with attribute prefix on first old style parm. */ datadecl: - typed_declspecs_no_prefix_attr setspecs initdecls ';' + declspecs_ts_nosa setspecs initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods_no_prefix_attr setspecs notype_initdecls ';' + | declspecs_nots_nosa setspecs notype_initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs_no_prefix_attr ';' + | declspecs_ts_nosa ';' { shadow_tag_warned ($1, 1); pedwarn ("empty declaration"); } - | declmods_no_prefix_attr ';' + | declspecs_nots_nosa ';' { pedwarn ("empty declaration"); } ; @@ -853,106 +865,338 @@ setspecs: /* empty */ ¤t_declspecs, &prefix_attributes); } ; -/* ??? Yuck. See after_type_declarator. */ +/* ??? Yuck. See maybe_setattrs. */ setattrs: /* empty */ { prefix_attributes = chainon (prefix_attributes, $0); } ; +maybe_setattrs: + /* ??? Yuck. setattrs is a quick hack. We can't use + prefix_attributes because $1 only applies to this + declarator. We assume setspecs has already been done. + setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple + attributes could be recognized here or in `attributes'). + Properly attributes ought to be able to apply to any level of + nested declarator, but the necessary compiler support isn't + present, so the attributes apply to a declaration (which may be + nested). */ + maybe_attribute setattrs + ; + decl: - typed_declspecs setspecs initdecls ';' + declspecs_ts setspecs initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods setspecs notype_initdecls ';' + | declspecs_nots setspecs notype_initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs setspecs nested_function + | declspecs_ts setspecs nested_function { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods setspecs notype_nested_function + | declspecs_nots setspecs notype_nested_function { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs ';' + | declspecs ';' { shadow_tag ($1); } - | declmods ';' - { pedwarn ("empty declaration"); } | extension decl { RESTORE_WARN_FLAGS ($1); } ; +/* A list of declaration specifiers. These are: + + - Storage class specifiers (SCSPEC), which for GCC currently include + function specifiers ("inline"). + + - Type specifiers (typespec_*). + + - Type qualifiers (TYPE_QUAL). + + - Attribute specifier lists (attributes). + + These are stored as a TREE_LIST; the head of the list is the last + item in the specifier list. Each entry in the list has either a + TREE_PURPOSE that is an attribute specifier list, or a TREE_VALUE that + is a single other specifier or qualifier; and a TREE_CHAIN that is the + rest of the list. TREE_STATIC is set on the list if something other + than a storage class specifier or attribute has been seen; this is used + to warn for the obsolescent usage of storage class specifiers other than + at the start of the list. (Doing this properly would require function + specifiers to be handled separately from storage class specifiers.) + + The various cases below are classified according to: + + (a) Whether a storage class specifier is included or not; some + places in the grammar disallow storage class specifiers (_sc or _nosc). + + (b) Whether a type specifier has been seen; after a type specifier, + a typedef name is an identifier to redeclare (_ts or _nots). + + (c) Whether the list starts with an attribute; in certain places, + the grammar requires specifiers that don't start with an attribute + (_sa or _nosa). + + (d) Whether the list ends with an attribute (or a specifier such that + any following attribute would have been parsed as part of that specifier); + this avoids shift-reduce conflicts in the parsing of attributes + (_ea or _noea). + + TODO: + + (i) Distinguish between function specifiers and storage class specifiers, + at least for the purpose of warnings about obsolescent usage. + + (ii) Halve the number of productions here by eliminating the _sc/_nosc + distinction and instead checking where required that storage class + specifiers aren't present. */ + /* Declspecs which contain at least one type specifier or typedef name. (Just `const' or `volatile' is not enough.) A typedef'd name following these is taken as a name to be declared. Declspecs have a non-NULL TREE_VALUE, attributes do not. */ -typed_declspecs: - typespec reserved_declspecs - { $$ = tree_cons (NULL_TREE, $1, $2); } - | declmods typespec reserved_declspecs - { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } +declspecs_nosc_nots_nosa_noea: + TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_nosa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_nosa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } ; -reserved_declspecs: /* empty */ - { $$ = NULL_TREE; } - | reserved_declspecs typespecqual_reserved - { $$ = tree_cons (NULL_TREE, $2, $1); } - | reserved_declspecs SCSPEC - { if (extra_warnings) +declspecs_nosc_nots_nosa_ea: + declspecs_nosc_nots_nosa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + ; + +declspecs_nosc_nots_sa_noea: + declspecs_nosc_nots_sa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_sa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + ; + +declspecs_nosc_nots_sa_ea: + attributes + { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); + TREE_STATIC ($$) = 0; } + | declspecs_nosc_nots_sa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + ; + +declspecs_nosc_ts_nosa_noea: + typespec_nonattr + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_nosa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_nosa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_nosa_noea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_nosa_ea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_nosa_noea typespec_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_nosa_ea typespec_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + ; + +declspecs_nosc_ts_nosa_ea: + typespec_attr + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_nosa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_nosc_ts_nosa_noea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_nosa_ea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_nosa_noea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_nosa_ea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + ; + +declspecs_nosc_ts_sa_noea: + declspecs_nosc_ts_sa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_sa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_sa_noea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_sa_ea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_sa_noea typespec_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_sa_ea typespec_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + ; + +declspecs_nosc_ts_sa_ea: + declspecs_nosc_ts_sa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_nosc_ts_sa_noea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_sa_ea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_sa_noea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_sa_ea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + ; + +declspecs_sc_nots_nosa_noea: + SCSPEC + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); + TREE_STATIC ($$) = 0; } + | declspecs_sc_nots_nosa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_nosa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_nosa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); - $$ = tree_cons (NULL_TREE, $2, $1); } - | reserved_declspecs attributes - { $$ = tree_cons ($2, NULL_TREE, $1); } + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_nosc_nots_nosa_ea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_nots_nosa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_nots_nosa_ea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } ; -typed_declspecs_no_prefix_attr: - typespec reserved_declspecs_no_prefix_attr - { $$ = tree_cons (NULL_TREE, $1, $2); } - | declmods_no_prefix_attr typespec reserved_declspecs_no_prefix_attr - { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } +declspecs_sc_nots_nosa_ea: + declspecs_sc_nots_nosa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } ; -reserved_declspecs_no_prefix_attr: - /* empty */ - { $$ = NULL_TREE; } - | reserved_declspecs_no_prefix_attr typespecqual_reserved - { $$ = tree_cons (NULL_TREE, $2, $1); } - | reserved_declspecs_no_prefix_attr SCSPEC - { if (extra_warnings) +declspecs_sc_nots_sa_noea: + declspecs_sc_nots_sa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_sa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_nots_sa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_nosc_nots_sa_ea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_nots_sa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_nots_sa_ea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); - $$ = tree_cons (NULL_TREE, $2, $1); } + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } ; -/* List of just storage classes, type modifiers, and prefix attributes. - A declaration can start with just this, but then it cannot be used - to redeclare a typedef-name. - Declspecs have a non-NULL TREE_VALUE, attributes do not. */ - -declmods: - declmods_no_prefix_attr - { $$ = $1; } - | attributes - { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); } - | declmods declmods_no_prefix_attr - { $$ = chainon ($2, $1); } - | declmods attributes - { $$ = tree_cons ($2, NULL_TREE, $1); } +declspecs_sc_nots_sa_ea: + declspecs_sc_nots_sa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } ; -declmods_no_prefix_attr: - TYPE_QUAL - { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); +declspecs_sc_ts_nosa_noea: + declspecs_sc_ts_nosa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); TREE_STATIC ($$) = 1; } - | SCSPEC - { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } - | declmods_no_prefix_attr TYPE_QUAL + | declspecs_sc_ts_nosa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_ts_nosa_noea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_ts_nosa_ea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_nosa_noea typespec_nonattr { $$ = tree_cons (NULL_TREE, $2, $1); TREE_STATIC ($$) = 1; } - | declmods_no_prefix_attr SCSPEC + | declspecs_sc_nots_nosa_ea typespec_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_nosa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_nosc_ts_nosa_ea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_ts_nosa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_ts_nosa_ea SCSPEC { if (extra_warnings && TREE_STATIC ($1)) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); @@ -960,31 +1204,223 @@ declmods_no_prefix_attr: TREE_STATIC ($$) = TREE_STATIC ($1); } ; +declspecs_sc_ts_nosa_ea: + declspecs_sc_ts_nosa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_ts_nosa_noea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_ts_nosa_ea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_nosa_noea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_nosa_ea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + ; -/* Used instead of declspecs where storage classes are not allowed - (that is, for typenames and structure components). - Don't accept a typedef-name if anything but a modifier precedes it. */ +declspecs_sc_ts_sa_noea: + declspecs_sc_ts_sa_noea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_ts_sa_ea TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_ts_sa_noea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_ts_sa_ea typespec_reserved_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_sa_noea typespec_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_sa_ea typespec_nonattr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_nosc_ts_sa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_nosc_ts_sa_ea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_ts_sa_noea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_ts_sa_ea SCSPEC + { if (extra_warnings && TREE_STATIC ($1)) + warning ("`%s' is not at beginning of declaration", + IDENTIFIER_POINTER ($2)); + $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + ; -typed_typespecs: - typespec reserved_typespecquals - { $$ = tree_cons (NULL_TREE, $1, $2); } - | nonempty_type_quals typespec reserved_typespecquals - { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } +declspecs_sc_ts_sa_ea: + declspecs_sc_ts_sa_noea attributes + { $$ = tree_cons ($2, NULL_TREE, $1); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declspecs_sc_ts_sa_noea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_ts_sa_ea typespec_reserved_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_sa_noea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } + | declspecs_sc_nots_sa_ea typespec_attr + { $$ = tree_cons (NULL_TREE, $2, $1); + TREE_STATIC ($$) = 1; } ; -reserved_typespecquals: /* empty */ +/* Particular useful classes of declspecs. */ +declspecs_ts: + declspecs_nosc_ts_nosa_noea + | declspecs_nosc_ts_nosa_ea + | declspecs_nosc_ts_sa_noea + | declspecs_nosc_ts_sa_ea + | declspecs_sc_ts_nosa_noea + | declspecs_sc_ts_nosa_ea + | declspecs_sc_ts_sa_noea + | declspecs_sc_ts_sa_ea + ; + +declspecs_nots: + declspecs_nosc_nots_nosa_noea + | declspecs_nosc_nots_nosa_ea + | declspecs_nosc_nots_sa_noea + | declspecs_nosc_nots_sa_ea + | declspecs_sc_nots_nosa_noea + | declspecs_sc_nots_nosa_ea + | declspecs_sc_nots_sa_noea + | declspecs_sc_nots_sa_ea + ; + +declspecs_ts_nosa: + declspecs_nosc_ts_nosa_noea + | declspecs_nosc_ts_nosa_ea + | declspecs_sc_ts_nosa_noea + | declspecs_sc_ts_nosa_ea + ; + +declspecs_nots_nosa: + declspecs_nosc_nots_nosa_noea + | declspecs_nosc_nots_nosa_ea + | declspecs_sc_nots_nosa_noea + | declspecs_sc_nots_nosa_ea + ; + +declspecs_nosc_ts: + declspecs_nosc_ts_nosa_noea + | declspecs_nosc_ts_nosa_ea + | declspecs_nosc_ts_sa_noea + | declspecs_nosc_ts_sa_ea + ; + +declspecs_nosc_nots: + declspecs_nosc_nots_nosa_noea + | declspecs_nosc_nots_nosa_ea + | declspecs_nosc_nots_sa_noea + | declspecs_nosc_nots_sa_ea + ; + +declspecs_nosc: + declspecs_nosc_ts_nosa_noea + | declspecs_nosc_ts_nosa_ea + | declspecs_nosc_ts_sa_noea + | declspecs_nosc_ts_sa_ea + | declspecs_nosc_nots_nosa_noea + | declspecs_nosc_nots_nosa_ea + | declspecs_nosc_nots_sa_noea + | declspecs_nosc_nots_sa_ea + ; + +declspecs: + declspecs_nosc_nots_nosa_noea + | declspecs_nosc_nots_nosa_ea + | declspecs_nosc_nots_sa_noea + | declspecs_nosc_nots_sa_ea + | declspecs_nosc_ts_nosa_noea + | declspecs_nosc_ts_nosa_ea + | declspecs_nosc_ts_sa_noea + | declspecs_nosc_ts_sa_ea + | declspecs_sc_nots_nosa_noea + | declspecs_sc_nots_nosa_ea + | declspecs_sc_nots_sa_noea + | declspecs_sc_nots_sa_ea + | declspecs_sc_ts_nosa_noea + | declspecs_sc_ts_nosa_ea + | declspecs_sc_ts_sa_noea + | declspecs_sc_ts_sa_ea + ; + +/* A (possibly empty) sequence of type qualifiers and attributes, to be + followed by the effect of setattrs if any attributes were present. */ +maybe_type_quals_setattrs: + /* empty */ { $$ = NULL_TREE; } - | reserved_typespecquals typespecqual_reserved - { $$ = tree_cons (NULL_TREE, $2, $1); } + | declspecs_nosc_nots + { tree specs, attrs; + split_specs_attrs ($1, &specs, &attrs); + /* ??? Yuck. See maybe_setattrs. */ + if (attrs != NULL_TREE) + prefix_attributes = chainon (prefix_attributes, attrs); + $$ = specs; } ; -/* A typespec (but not a type qualifier). +/* A type specifier (but not a type qualifier). Once we have seen one of these in a declaration, - if a typedef name appears then it is being redeclared. */ + if a typedef name appears then it is being redeclared. -typespec: TYPESPEC - | structsp - | TYPENAME + The _reserved versions start with a reserved word and may appear anywhere + in the declaration specifiers; the _nonreserved versions may only + appear before any other type specifiers, and after that are (if names) + being redeclared. + + FIXME: should the _nonreserved version be restricted to names being + redeclared only? The other entries there relate only the GNU extensions + and Objective C, and are historically parsed thus, and don't make sense + after other type specifiers, but it might be cleaner to count them as + _reserved. + + _attr means: specifiers that either end with attributes, + or are such that any following attributes would + be parsed as part of the specifier. + + _nonattr: specifiers. */ + +typespec_nonattr: + typespec_reserved_nonattr + | typespec_nonreserved_nonattr + ; + +typespec_attr: + typespec_reserved_attr + ; + +typespec_reserved_nonattr: + TYPESPEC + | structsp_nonattr + ; + +typespec_reserved_attr: + structsp_attr + ; + +typespec_nonreserved_nonattr: + TYPENAME { /* For a typedef name, record the meaning, not the name. In case of `foo foo, bar;'. */ $$ = lookup_name ($1); } @@ -1005,21 +1441,16 @@ end ifobjc { $$ = groktypename ($3); } ; -/* A typespec that is a reserved word, or a type qualifier. */ - -typespecqual_reserved: TYPESPEC - | TYPE_QUAL - | structsp - ; +/* typespec_nonreserved_attr does not exist. */ initdecls: initdcl - | initdecls ',' initdcl + | initdecls ',' maybe_setattrs initdcl ; notype_initdecls: notype_initdcl - | notype_initdecls ',' initdcl + | notype_initdecls ',' maybe_setattrs notype_initdcl ; maybeasm: @@ -1257,8 +1688,8 @@ declarator: /* A declarator that is allowed only after an explicit typespec. */ after_type_declarator: - '(' after_type_declarator ')' - { $$ = $2; } + '(' maybe_setattrs after_type_declarator ')' + { $$ = $3; } | after_type_declarator '(' parmlist_or_identifiers %prec '.' { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } /* | after_type_declarator '(' error ')' %prec '.' @@ -1268,15 +1699,8 @@ after_type_declarator: { $$ = build_nt (ARRAY_REF, $1, $3); } | after_type_declarator '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } - | '*' type_quals after_type_declarator %prec UNARY + | '*' maybe_type_quals_setattrs after_type_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } - /* ??? Yuck. setattrs is a quick hack. We can't use - prefix_attributes because $1 only applies to this - declarator. We assume setspecs has already been done. - setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple - attributes could be recognized here or in `attributes'). */ - | attributes setattrs after_type_declarator - { $$ = $3; } | TYPENAME ifobjc | OBJECTNAME @@ -1305,15 +1729,8 @@ end ifc { $$ = build_nt (ARRAY_REF, $1, $3); } | parm_declarator '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } - | '*' type_quals parm_declarator %prec UNARY + | '*' maybe_type_quals_setattrs parm_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } - /* ??? Yuck. setattrs is a quick hack. We can't use - prefix_attributes because $1 only applies to this - declarator. We assume setspecs has already been done. - setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple - attributes could be recognized here or in `attributes'). */ - | attributes setattrs parm_declarator - { $$ = $3; } | TYPENAME ; @@ -1326,9 +1743,9 @@ notype_declarator: /* | notype_declarator '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ - | '(' notype_declarator ')' - { $$ = $2; } - | '*' type_quals notype_declarator %prec UNARY + | '(' maybe_setattrs notype_declarator ')' + { $$ = $3; } + | '*' maybe_type_quals_setattrs notype_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } ifc | notype_declarator '[' '*' ']' %prec '.' @@ -1341,13 +1758,6 @@ end ifc { $$ = build_nt (ARRAY_REF, $1, $3); } | notype_declarator '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } - /* ??? Yuck. setattrs is a quick hack. We can't use - prefix_attributes because $1 only applies to this - declarator. We assume setspecs has already been done. - setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple - attributes could be recognized here or in `attributes'). */ - | attributes setattrs notype_declarator - { $$ = $3; } | IDENTIFIER ; @@ -1372,7 +1782,13 @@ enum_head: { $$ = $2; } ; -structsp: +/* structsp_attr: struct/union/enum specifiers that either + end with attributes, or are such that any following attributes would + be parsed as part of the struct/union/enum specifier. + + structsp_nonattr: other struct/union/enum specifiers. */ + +structsp_attr: struct_head identifier '{' { $$ = start_struct (RECORD_TYPE, $2); /* Start scope of tag before parsing components. */ @@ -1383,8 +1799,6 @@ structsp: { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE), $3, chainon ($1, $5)); } - | struct_head identifier - { $$ = xref_tag (RECORD_TYPE, $2); } | union_head identifier '{' { $$ = start_struct (UNION_TYPE, $2); } component_decl_list '}' maybe_attribute @@ -1393,8 +1807,6 @@ structsp: { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE), $3, chainon ($1, $5)); } - | union_head identifier - { $$ = xref_tag (UNION_TYPE, $2); } | enum_head identifier '{' { $$ = start_enum ($2); } enumlist maybecomma_warn '}' maybe_attribute @@ -1405,6 +1817,13 @@ structsp: enumlist maybecomma_warn '}' maybe_attribute { $$ = finish_enum ($3, nreverse ($4), chainon ($1, $7)); } + ; + +structsp_nonattr: + struct_head identifier + { $$ = xref_tag (RECORD_TYPE, $2); } + | union_head identifier + { $$ = xref_tag (UNION_TYPE, $2); } | enum_head identifier { $$ = xref_tag (ENUMERAL_TYPE, $2); /* In ISO C, enumerated types can be referred to @@ -1458,22 +1877,13 @@ ifobjc end ifobjc ; -/* There is a shift-reduce conflict here, because `components' may - start with a `typename'. It happens that shifting (the default resolution) - does the right thing, because it treats the `typename' as part of - a `typed_typespecs'. - - It is possible that this same technique would allow the distinction - between `notype_initdecls' and `initdecls' to be eliminated. - But I am being cautious and not trying it. */ - component_decl: - typed_typespecs setspecs components + declspecs_nosc_ts setspecs components { $$ = $3; current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_typespecs setspecs save_filename save_lineno maybe_attribute + | declspecs_nosc_ts setspecs save_filename save_lineno { /* Support for unnamed structs or unions as members of structs or unions (which is [a] useful and [b] supports @@ -1486,12 +1896,12 @@ component_decl: prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | nonempty_type_quals setspecs components + | declspecs_nosc_nots setspecs components_notype { $$ = $3; current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | nonempty_type_quals + | declspecs_nosc_nots { if (pedantic) pedwarn ("ISO C forbids member declarations with no members"); shadow_tag($1); @@ -1505,8 +1915,14 @@ component_decl: components: component_declarator - | components ',' component_declarator - { $$ = chainon ($1, $3); } + | components ',' maybe_setattrs component_declarator + { $$ = chainon ($1, $4); } + ; + +components_notype: + component_notype_declarator + | components_notype ',' maybe_setattrs component_notype_declarator + { $$ = chainon ($1, $4); } ; component_declarator: @@ -1522,6 +1938,19 @@ component_declarator: decl_attributes ($$, $5, prefix_attributes); } ; +component_notype_declarator: + save_filename save_lineno notype_declarator maybe_attribute + { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE); + decl_attributes ($$, $4, prefix_attributes); } + | save_filename save_lineno + notype_declarator ':' expr_no_commas maybe_attribute + { $$ = grokfield ($1, $2, $3, current_declspecs, $5); + decl_attributes ($$, $6, prefix_attributes); } + | save_filename save_lineno ':' expr_no_commas maybe_attribute + { $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4); + decl_attributes ($$, $5, prefix_attributes); } + ; + /* We chain the enumerators in reverse order. They are put in forward order where enumlist is used. (The order used to be significant, but no longer is so. @@ -1547,12 +1976,16 @@ enumerator: ; typename: - typed_typespecs - { pending_xref_error (); } + declspecs_nosc + { tree specs, attrs; + pending_xref_error (); + split_specs_attrs ($1, &specs, &attrs); + /* We don't yet support attributes here. */ + if (attrs != NULL_TREE) + warning ("attributes on type name ignored"); + $$ = specs; } absdcl - { $$ = build_tree_list ($1, $3); } - | nonempty_type_quals absdcl - { $$ = build_tree_list ($1, $2); } + { $$ = build_tree_list ($2, $3); } ; absdcl: /* an absolute declarator */ @@ -1561,45 +1994,57 @@ absdcl: /* an absolute declarator */ | absdcl1 ; -nonempty_type_quals: - TYPE_QUAL - { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } - | nonempty_type_quals TYPE_QUAL - { $$ = tree_cons (NULL_TREE, $2, $1); } +absdcl_maybe_attribute: /* absdcl maybe_attribute, but not just attributes */ + /* empty */ + { $$ = build_tree_list (build_tree_list (current_declspecs, + NULL_TREE), + build_tree_list (prefix_attributes, + NULL_TREE)); } + | absdcl1 + { $$ = build_tree_list (build_tree_list (current_declspecs, + $1), + build_tree_list (prefix_attributes, + NULL_TREE)); } + | absdcl1_noea attributes + { $$ = build_tree_list (build_tree_list (current_declspecs, + $1), + build_tree_list (prefix_attributes, + $2)); } ; -type_quals: - /* empty */ - { $$ = NULL_TREE; } - | type_quals TYPE_QUAL - { $$ = tree_cons (NULL_TREE, $2, $1); } +absdcl1: /* a nonempty absolute declarator */ + absdcl1_ea + | absdcl1_noea ; -absdcl1: /* a nonempty absolute declarator */ - '(' absdcl1 ')' - { $$ = $2; } - /* `(typedef)1' is `int'. */ - | '*' type_quals absdcl1 %prec UNARY +absdcl1_noea: + direct_absdcl1 + | '*' maybe_type_quals_setattrs absdcl1_noea { $$ = make_pointer_declarator ($2, $3); } - | '*' type_quals %prec UNARY + ; + +absdcl1_ea: + '*' maybe_type_quals_setattrs { $$ = make_pointer_declarator ($2, NULL_TREE); } - | absdcl1 '(' parmlist %prec '.' + | '*' maybe_type_quals_setattrs absdcl1_ea + { $$ = make_pointer_declarator ($2, $3); } + ; + +direct_absdcl1: + '(' maybe_setattrs absdcl1 ')' + { $$ = $3; } + | direct_absdcl1 '(' parmlist { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } - | absdcl1 '[' expr ']' %prec '.' + | direct_absdcl1 '[' expr ']' { $$ = build_nt (ARRAY_REF, $1, $3); } - | absdcl1 '[' ']' %prec '.' + | direct_absdcl1 '[' ']' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } - | '(' parmlist %prec '.' + | '(' parmlist { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); } - | '[' expr ']' %prec '.' + | '[' expr ']' { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); } - | '[' ']' %prec '.' + | '[' ']' { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); } - /* ??? It appears we have to support attributes here, however - using prefix_attributes is wrong. */ - | attributes setattrs absdcl1 - { $$ = $3; } - ; /* A nonempty series of declarations and statements (possibly followed by some labels) that can form the body of a compound statement. @@ -2080,13 +2525,17 @@ asm_clobbers: ; /* This is what appears inside the parens in a function declarator. - Its value is a list of ..._TYPE nodes. */ + Its value is a list of ..._TYPE nodes. Attributes must appear here + to avoid a conflict with their appearance after an open parenthesis + in an abstract declarator, as in + "void bar (int (__attribute__((__mode__(SI))) int foo));". */ parmlist: + maybe_attribute { pushlevel (0); clear_parm_order (); declare_parm_level (0); } parmlist_1 - { $$ = $2; + { $$ = $3; parmlist_tags_warning (); poplevel (0, 0, 0); } ; @@ -2101,8 +2550,11 @@ parmlist_1: for (parm = getdecls (); parm; parm = TREE_CHAIN (parm)) TREE_ASM_WRITTEN (parm) = 1; clear_parm_order (); } + maybe_attribute + { /* Dummy action so attributes are in known place + on parser stack. */ } parmlist_1 - { $$ = $4; } + { $$ = $6; } | error ')' { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); } ; @@ -2128,7 +2580,7 @@ parmlist_2: /* empty */ ; parms: - parm + firstparm { push_parm_decl ($1); } | parms ',' parm { push_parm_decl ($3); } @@ -2137,7 +2589,7 @@ parms: /* A single parameter declaration or parameter type name, as found in a parmlist. */ parm: - typed_declspecs setspecs parm_declarator maybe_attribute + declspecs_ts setspecs parm_declarator maybe_attribute { $$ = build_tree_list (build_tree_list (current_declspecs, $3), build_tree_list (prefix_attributes, @@ -2145,7 +2597,7 @@ parm: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs setspecs notype_declarator maybe_attribute + | declspecs_ts setspecs notype_declarator maybe_attribute { $$ = build_tree_list (build_tree_list (current_declspecs, $3), build_tree_list (prefix_attributes, @@ -2153,7 +2605,12 @@ parm: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs setspecs absdcl maybe_attribute + | declspecs_ts setspecs absdcl_maybe_attribute + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); } + | declspecs_nots setspecs notype_declarator maybe_attribute { $$ = build_tree_list (build_tree_list (current_declspecs, $3), build_tree_list (prefix_attributes, @@ -2161,7 +2618,18 @@ parm: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | declmods setspecs notype_declarator maybe_attribute + + | declspecs_nots setspecs absdcl_maybe_attribute + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); } + ; + +/* The first parm, which must suck attributes from off the top of the parser + stack. */ +firstparm: + declspecs_ts_nosa setspecs_fp parm_declarator maybe_attribute { $$ = build_tree_list (build_tree_list (current_declspecs, $3), build_tree_list (prefix_attributes, @@ -2169,8 +2637,20 @@ parm: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - - | declmods setspecs absdcl maybe_attribute + | declspecs_ts_nosa setspecs_fp notype_declarator maybe_attribute + { $$ = build_tree_list (build_tree_list (current_declspecs, + $3), + build_tree_list (prefix_attributes, + $4)); + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); } + | declspecs_ts_nosa setspecs_fp absdcl_maybe_attribute + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); } + | declspecs_nots_nosa setspecs_fp notype_declarator maybe_attribute { $$ = build_tree_list (build_tree_list (current_declspecs, $3), build_tree_list (prefix_attributes, @@ -2178,6 +2658,17 @@ parm: current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } + + | declspecs_nots_nosa setspecs_fp absdcl_maybe_attribute + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + prefix_attributes = TREE_PURPOSE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); } + ; + +setspecs_fp: + setspecs + { prefix_attributes = chainon (prefix_attributes, $-2); } ; /* This is used in a function definition @@ -2459,12 +2950,12 @@ ivar_decls: But I am being cautious and not trying it. */ ivar_decl: - typed_typespecs setspecs ivars + declspecs_nosc_ts setspecs ivars { $$ = $3; current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | nonempty_type_quals setspecs ivars + | declspecs_nosc_nots setspecs ivars { $$ = $3; current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); @@ -2477,7 +2968,7 @@ ivars: /* empty */ { $$ = NULL_TREE; } | ivar_declarator - | ivars ',' ivar_declarator + | ivars ',' maybe_setattrs ivar_declarator ; ivar_declarator: @@ -2652,13 +3143,13 @@ mydecls: ; mydecl: - typed_declspecs setspecs myparms ';' + declspecs_ts setspecs myparms ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } - | typed_declspecs ';' + | declspecs_ts ';' { shadow_tag ($1); } - | declmods ';' + | declspecs_nots ';' { pedwarn ("empty declaration"); } ; @@ -2683,11 +3174,8 @@ myparm: $1), build_tree_list (prefix_attributes, $2)); } - | absdcl maybe_attribute - { $$ = build_tree_list (build_tree_list (current_declspecs, - $1), - build_tree_list (prefix_attributes, - $2)); } + | absdcl_maybe_attribute + { $$ = $1; } ; optparmlist: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a540321eefc..2bcd774917d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-05-10 Joseph S. Myers + + * gcc.c-torture/compile/20010313-1.c: New test. + 2001-05-09 Zack Weinberg * gcc.dg/cpp/direct2.c: New test. diff --git a/gcc/testsuite/gcc.c-torture/compile/20010313-1.c b/gcc/testsuite/gcc.c-torture/compile/20010313-1.c new file mode 100644 index 00000000000..a5a6ee65217 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20010313-1.c @@ -0,0 +1,5 @@ +/* Origin: Joseph Myers . */ +/* After the open parenthesis before the __attribute__, we used to shift + the __attribute__ (expecting a parenthesised abstract declarator) + instead of reducing to the start of a parameter list. */ +void bar (int (__attribute__((__mode__(__SI__))) int foo));