diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 264f442a3ed..8701ae30e45 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2001-05-25 Joseph S. Myers + + * c-parse.in (array_declarator): New. Handle C99 constructs. + Don't restrict [*] declarators to C only. + (after_type_declarator, parm_declarator_starttypename, + parm_declarator_nostarttypename, notype_declarator, + direct_absdcl1): Use it. + * c-decl.c (build_array_declarator, set_array_declarator_type): + New functions. Warn that [*] isn't properly implemented; pedwarn + for [*] outside C99 mode if pedantic rather than giving a hard + error. + (grokdeclarator): Handle static and type qualifiers in parameter + array declarators. + * c-tree.h (build_array_declarator, set_array_declarator_type): + Declare. + * extend.texi (Attribute Syntax): Document attributes in parameter + array declarators. + 2001-05-25 Mark * config/i386/i386.md: Make sure cmpstr peepholes do not diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 0c0866236e1..758888561a4 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -3278,6 +3278,60 @@ shadow_tag_warned (declspecs, warned) } } +/* Construct an array declarator. EXPR is the expression inside [], or + NULL_TREE. QUALS are the type qualifiers inside the [] (to be applied + to the pointer to which a parameter array is converted). STATIC_P is + non-zero if "static" is inside the [], zero otherwise. VLA_UNSPEC_P + is non-zero is the array is [*], a VLA of unspecified length which is + nevertheless a complete type (not currently implemented by GCC), + zero otherwise. The declarator is constructed as an ARRAY_REF + (to be decoded by grokdeclarator), whose operand 0 is what's on the + left of the [] (filled by in set_array_declarator_type) and operand 1 + is the expression inside; whose TREE_TYPE is the type qualifiers and + which has TREE_STATIC set if "static" is used. */ + +tree +build_array_declarator (expr, quals, static_p, vla_unspec_p) + tree expr; + tree quals; + int static_p; + int vla_unspec_p; +{ + tree decl; + decl = build_nt (ARRAY_REF, NULL_TREE, expr); + TREE_TYPE (decl) = quals; + TREE_STATIC (decl) = (static_p ? 1 : 0); + if (pedantic && !flag_isoc99) + { + if (static_p || quals != NULL_TREE) + pedwarn ("ISO C89 does not support `static' or type qualifiers in parameter array declarators"); + if (vla_unspec_p) + pedwarn ("ISO C89 does not support `[*]' array declarators"); + } + if (vla_unspec_p) + warning ("GCC does not yet properly implement `[*]' array declarators"); + return decl; +} + +/* Set the type of an array declarator. DECL is the declarator, as + constructed by build_array_declarator; TYPE is what appears on the left + of the [] and goes in operand 0. ABSTRACT_P is non-zero if it is an + abstract declarator, zero otherwise; this is used to reject static and + type qualifiers in abstract declarators, where they are not in the + C99 grammar. */ + +tree +set_array_declarator_type (decl, type, abstract_p) + tree decl; + tree type; + int abstract_p; +{ + TREE_OPERAND (decl, 0) = type; + if (abstract_p && (TREE_TYPE (decl) != NULL_TREE || TREE_STATIC (decl))) + error ("static or type qualifiers in abstract declarator"); + return decl; +} + /* Decode a "typename", such as "int **", returning a ..._TYPE node. */ tree @@ -3861,6 +3915,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) int bitfield = 0; int size_varies = 0; tree decl_machine_attr = NULL_TREE; + tree array_ptr_quals = NULL_TREE; + int array_parm_static = 0; if (decl_context == BITFIELD) bitfield = 1, decl_context = FIELD; @@ -4289,6 +4345,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) array or function or pointer, and DECLARATOR has had its outermost layer removed. */ + if (array_ptr_quals != NULL_TREE || array_parm_static) + { + /* Only the innermost declarator (making a parameter be of + array type which is converted to pointer type) + may have static or type qualifiers. */ + error ("static or type qualifiers in non-parameter array declarator"); + array_ptr_quals = NULL_TREE; + array_parm_static = 0; + } + if (TREE_CODE (declarator) == ARRAY_REF) { register tree itype = NULL_TREE; @@ -4296,6 +4362,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) /* The index is a signed object `sizetype' bits wide. */ tree index_type = signed_type (sizetype); + array_ptr_quals = TREE_TYPE (declarator); + array_parm_static = TREE_STATIC (declarator); + declarator = TREE_OPERAND (declarator, 0); /* Check for some types that there cannot be arrays of. */ @@ -4445,6 +4514,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) TYPE_SIZE (type) = bitsize_zero_node; TYPE_SIZE_UNIT (type) = size_zero_node; } + if (decl_context != PARM + && (array_ptr_quals != NULL_TREE || array_parm_static)) + { + error ("static or type qualifiers in non-parameter array declarator"); + array_ptr_quals = NULL_TREE; + array_parm_static = 0; + } } else if (TREE_CODE (declarator) == CALL_EXPR) { @@ -4696,6 +4772,44 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) type = c_build_qualified_type (type, type_quals); type = build_pointer_type (type); type_quals = TYPE_UNQUALIFIED; + if (array_ptr_quals) + { + tree new_ptr_quals, new_ptr_attrs; + int erred = 0; + split_specs_attrs (array_ptr_quals, &new_ptr_quals, &new_ptr_attrs); + /* We don't yet implement attributes in this context. */ + if (new_ptr_attrs != NULL_TREE) + warning ("attributes in parameter array declarator ignored"); + + constp = 0; + volatilep = 0; + restrictp = 0; + for (; new_ptr_quals; new_ptr_quals = TREE_CHAIN (new_ptr_quals)) + { + tree qualifier = TREE_VALUE (new_ptr_quals); + + if (C_IS_RESERVED_WORD (qualifier)) + { + if (C_RID_CODE (qualifier) == RID_CONST) + constp++; + else if (C_RID_CODE (qualifier) == RID_VOLATILE) + volatilep++; + else if (C_RID_CODE (qualifier) == RID_RESTRICT) + restrictp++; + else + erred++; + } + else + erred++; + } + + if (erred) + error ("invalid type modifier within array declarator"); + + type_quals = ((constp ? TYPE_QUAL_CONST : 0) + | (restrictp ? TYPE_QUAL_RESTRICT : 0) + | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + } size_varies = 0; } else if (TREE_CODE (type) == FUNCTION_TYPE) diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 3a1c17eb708..e64e140dfa1 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -198,6 +198,7 @@ end ifc %type notype_declarator after_type_declarator %type parm_declarator %type parm_declarator_starttypename parm_declarator_nostarttypename +%type array_declarator %type structsp_attr structsp_nonattr %type component_decl_list component_decl_list2 @@ -1668,10 +1669,8 @@ after_type_declarator: /* | after_type_declarator '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ - | after_type_declarator '[' expr ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, $3); } - | after_type_declarator '[' ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | after_type_declarator array_declarator %prec '.' + { $$ = set_array_declarator_type ($2, $1, 0); } | '*' maybe_type_quals_setattrs after_type_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | TYPENAME @@ -1695,17 +1694,8 @@ parm_declarator_starttypename: /* | parm_declarator_starttypename '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ -ifc - | parm_declarator_starttypename '[' '*' ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); - if (! flag_isoc99) - error ("`[*]' in parameter declaration only allowed in ISO C 99"); - } -end ifc - | parm_declarator_starttypename '[' expr ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, $3); } - | parm_declarator_starttypename '[' ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | parm_declarator_starttypename array_declarator %prec '.' + { $$ = set_array_declarator_type ($2, $1, 0); } | TYPENAME ; @@ -1715,17 +1705,8 @@ parm_declarator_nostarttypename: /* | parm_declarator_nostarttypename '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ -ifc - | parm_declarator_nostarttypename '[' '*' ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); - if (! flag_isoc99) - error ("`[*]' in parameter declaration only allowed in ISO C 99"); - } -end ifc - | parm_declarator_nostarttypename '[' expr ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, $3); } - | parm_declarator_nostarttypename '[' ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | parm_declarator_nostarttypename array_declarator %prec '.' + { $$ = set_array_declarator_type ($2, $1, 0); } | '*' maybe_type_quals_setattrs parm_declarator_starttypename %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | '*' maybe_type_quals_setattrs parm_declarator_nostarttypename %prec UNARY @@ -1747,17 +1728,8 @@ notype_declarator: { $$ = $3; } | '*' maybe_type_quals_setattrs notype_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } -ifc - | notype_declarator '[' '*' ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); - if (! flag_isoc99) - error ("`[*]' in parameter declaration only allowed in ISO C 99"); - } -end ifc - | notype_declarator '[' expr ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, $3); } - | notype_declarator '[' ']' %prec '.' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | notype_declarator array_declarator %prec '.' + { $$ = set_array_declarator_type ($2, $1, 0); } | IDENTIFIER ; @@ -2035,16 +2007,42 @@ direct_absdcl1: { $$ = $3; } | direct_absdcl1 '(' parmlist { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } - | direct_absdcl1 '[' expr ']' - { $$ = build_nt (ARRAY_REF, $1, $3); } - | direct_absdcl1 '[' ']' - { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | direct_absdcl1 array_declarator + { $$ = set_array_declarator_type ($2, $1, 1); } | '(' parmlist { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); } - | '[' expr ']' - { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); } + | array_declarator + { $$ = set_array_declarator_type ($1, NULL_TREE, 1); } + ; + +/* The [...] part of a declarator for an array type. */ + +array_declarator: + '[' expr ']' + { $$ = build_array_declarator ($2, NULL_TREE, 0, 0); } + | '[' declspecs_nosc expr ']' + { $$ = build_array_declarator ($3, $2, 0, 0); } | '[' ']' - { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); } + { $$ = build_array_declarator (NULL_TREE, NULL_TREE, 0, 0); } + | '[' declspecs_nosc ']' + { $$ = build_array_declarator (NULL_TREE, $2, 0, 0); } + | '[' '*' ']' + { $$ = build_array_declarator (NULL_TREE, NULL_TREE, 0, 1); } + | '[' declspecs_nosc '*' ']' + { $$ = build_array_declarator (NULL_TREE, $2, 0, 1); } + | '[' SCSPEC expr ']' + { if (C_RID_CODE ($2) != RID_STATIC) + error ("storage class specifier in array declarator"); + $$ = build_array_declarator ($3, NULL_TREE, 1, 0); } + | '[' SCSPEC declspecs_nosc expr ']' + { if (C_RID_CODE ($2) != RID_STATIC) + error ("storage class specifier in array declarator"); + $$ = build_array_declarator ($4, $3, 1, 0); } + | '[' declspecs_nosc SCSPEC expr ']' + { if (C_RID_CODE ($3) != RID_STATIC) + error ("storage class specifier in array declarator"); + $$ = build_array_declarator ($4, $2, 1, 0); } + ; /* A nonempty series of declarations and statements (possibly followed by some labels) that can form the body of a compound statement. diff --git a/gcc/c-tree.h b/gcc/c-tree.h index a33d64d7d27..8264ebd0690 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -153,6 +153,7 @@ extern int yyparse_1 PARAMS ((void)); extern void gen_aux_info_record PARAMS ((tree, int, int, int)); /* in c-decl.c */ +extern tree build_array_declarator PARAMS ((tree, tree, int, int)); extern tree build_enumerator PARAMS ((tree, tree)); #define c_build_type_variant(TYPE, CONST_P, VOLATILE_P) \ @@ -197,6 +198,7 @@ extern void push_label_level PARAMS ((void)); extern void push_parm_decl PARAMS ((tree)); extern tree pushdecl_top_level PARAMS ((tree)); extern void pushtag PARAMS ((tree, tree)); +extern tree set_array_declarator_type PARAMS ((tree, tree, int)); extern tree shadow_label PARAMS ((tree)); extern void shadow_record_fields PARAMS ((tree)); extern void shadow_tag PARAMS ((tree)); diff --git a/gcc/extend.texi b/gcc/extend.texi index f28e079e460..8f40ef77f15 100644 --- a/gcc/extend.texi +++ b/gcc/extend.texi @@ -2182,6 +2182,13 @@ An attribute specifier list may, in future, be permitted to appear after the declarator in a function definition (before any old-style parameter declarations or the function body). +Attribute specifiers may be mixed with type qualifiers appearing inside +the @code{[]} of a parameter array declarator, in the C99 construct by +which such qualifiers are applied to the pointer to which the array is +implicitly converted. Such attribute specifiers apply to the pointer, +not to the array, but at present this is not implemented and they are +ignored. + An attribute specifier list may appear at the start of a nested declarator. At present, there are some limitations in this usage: the attributes apply to the identifer declared, and to all subsequent diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5dc9c2d428b..5ce646c146a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-05-25 Joseph S. Myers + + * gcc.dg/c90-arraydecl-1.c, gcc.dg/c99-arraydecl-1.c: New tests. + 2001-05-24 Mark Mitchell G++ no longer defines builtins that do not begin with __builtin. diff --git a/gcc/testsuite/gcc.dg/c90-arraydecl-1.c b/gcc/testsuite/gcc.dg/c90-arraydecl-1.c new file mode 100644 index 00000000000..b3e7035c059 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-arraydecl-1.c @@ -0,0 +1,31 @@ +/* Test for C99 forms of array declarator: rejected in C90. */ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */ + +/* Use of [*] (possibly with type qualifiers) in an array declarator with + function prototype scope is a C99 feature. GCC does not yet implement + it correctly, so gives a warning about this. so we can't yet test here + that we get just one error and no warnings. */ + +void foo0 (int a, int b[*]); /* { dg-error "ISO C89" "\[*\] not in C89" } */ +/* { dg-warning "implement" "\[*\] not implemented" { target *-*-* } 11 } */ +void foo1 (int, int [*]); /* { dg-error "ISO C89" "\[*\] not in C89" } */ +/* { dg-warning "implement" "\[*\] not implemented" { target *-*-* } 13 } */ + +/* Use of static and type qualifiers (not allowed with abstract declarators) + is a C99 feature. */ + +void bar0 (int a[const]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "ISO C89" "\[quals\] not in C89" { target *-*-* } 19 } */ +void bar1 (int a[const 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "ISO C89" "\[quals expr\] not in C89" { target *-*-* } 21 } */ +void bar2 (int a[static 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "ISO C89" "\[static expr\] not in C89" { target *-*-* } 23 } */ +void bar3 (int a[static const 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "ISO C89" "\[static quals expr\] not in C89" { target *-*-* } 25 } */ +void bar4 (int a[const static 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "ISO C89" "\[quals static expr\] not in C89" { target *-*-* } 27 } */ + +/* Because [*] isn't properly implemented and so warns, we don't test here + for [const *] yet. */ diff --git a/gcc/testsuite/gcc.dg/c99-arraydecl-1.c b/gcc/testsuite/gcc.dg/c99-arraydecl-1.c new file mode 100644 index 00000000000..24ddd6571cd --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-arraydecl-1.c @@ -0,0 +1,111 @@ +/* Test for C99 forms of array declarator. */ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */ + +/* Because GCC doesn't yet implement it, we don't yet test for [*] here. */ + +/* Test each of: [quals], [quals expr], [static expr], [static quals expr], + [quals static expr]. Not yet: [quals *]. */ + +void f00 (int a[const]); +void f01 (int [const]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "abstract" "\[quals\] in abstract declarator" { target *-*-* } 12 } */ +void +f02 (int a[const]) +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 17 } */ + int *const *c = &a; +} +void +f03 (a) + int a[const]; +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 25 } */ + int *const *c = &a; +} + +void f10 (int a[const 2]); +void f11 (int [const 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "abstract" "\[quals expr\] in abstract declarator" { target *-*-* } 31 } */ +void +f12 (int a[const 2]) +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 36 } */ + int *const *c = &a; +} +void +f13 (a) + int a[const 2]; +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 44 } */ + int *const *c = &a; +} + +void f20 (int a[static 2]); +void f21 (int [static 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "abstract" "\[static expr\] in abstract declarator" { target *-*-* } 50 } */ +void +f22 (int a[static 2]) +{ + int **b = &a; + int *const *c = &a; +} +void +f23 (a) + int a[static 2]; +{ + int **b = &a; + int *const *c = &a; +} + +void f30 (int a[static const 2]); +void f31 (int [static const 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "abstract" "\[static quals expr\] in abstract declarator" { target *-*-* } 67 } */ +void +f32 (int a[static const 2]) +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 72 } */ + int *const *c = &a; +} +void +f33 (a) + int a[static const 2]; +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 80 } */ + int *const *c = &a; +} + +void f40 (int a[const static 2]); +void f41 (int [const static 2]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "abstract" "\[quals static expr\] in abstract declarator" { target *-*-* } 86 } */ +void +f42 (int a[const static 2]) +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 91 } */ + int *const *c = &a; +} +void +f43 (a) + int a[const static 2]; +{ + int **b = &a; /* { dg-bogus "warning" "warning in place of error" } */ + /* { dg-error "discards" "discards quals" { target *-*-* } 99 } */ + int *const *c = &a; +} + +/* Test rejection of static and type qualifiers in non-parameter contexts. */ +int x[const 2]; /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "non-parameter" "quals in non-parm array" { target *-*-* } 105 } */ +int y[static 2]; /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "non-parameter" "static in non-parm array" { target *-*-* } 107 } */ +void g (int a[static 2][3]); +void h (int a[2][static 3]); /* { dg-bogus "warning" "warning in place of error" } */ +/* { dg-error "non-parameter" "static in non-final parm array" { target *-*-* } 110 } */