* 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.
testsuite:
* gcc.dg/c90-arraydecl-1.c, gcc.dg/c99-arraydecl-1.c: New tests.
From-SVN: r42574
+2001-05-25 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ * 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 <mark@codesourcery.com>
* config/i386/i386.md: Make sure cmpstr peepholes do not
}
}
\f
+/* 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;
+}
+\f
/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
tree
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;
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;
/* 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. */
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)
{
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)
%type <ttype> notype_declarator after_type_declarator
%type <ttype> parm_declarator
%type <ttype> parm_declarator_starttypename parm_declarator_nostarttypename
+%type <ttype> array_declarator
%type <ttype> structsp_attr structsp_nonattr
%type <ttype> component_decl_list component_decl_list2
/* | 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
/* | 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
;
/* | 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
{ $$ = $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
;
{ $$ = $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.
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) \
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));
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
+2001-05-25 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ * gcc.dg/c90-arraydecl-1.c, gcc.dg/c99-arraydecl-1.c: New tests.
+
2001-05-24 Mark Mitchell <mark@codesourcery.com>
G++ no longer defines builtins that do not begin with __builtin.
--- /dev/null
+/* Test for C99 forms of array declarator: rejected in C90. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { 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. */
--- /dev/null
+/* Test for C99 forms of array declarator. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { 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 } */