c-parse.in (array_declarator): New.
authorJoseph Myers <jsm28@cam.ac.uk>
Fri, 25 May 2001 11:12:47 +0000 (12:12 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Fri, 25 May 2001 11:12:47 +0000 (12:12 +0100)
* 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

gcc/ChangeLog
gcc/c-decl.c
gcc/c-parse.in
gcc/c-tree.h
gcc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c90-arraydecl-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-arraydecl-1.c [new file with mode: 0644]

index 264f442a3ede96759153ddd54fed75c8ec436ec8..8701ae30e454e3ec7e496a26c49bb04ef8d69259 100644 (file)
@@ -1,3 +1,21 @@
+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 
index 0c0866236e145b1a66e0e4bba2312485df9e4809..758888561a4f8c1b7ed2159d9e5a3dfd0e2e6838 100644 (file)
@@ -3278,6 +3278,60 @@ shadow_tag_warned (declspecs, warned)
     }
 }
 \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
@@ -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)
index 3a1c17eb70872cec0de3efb7bdee5fe77136f950..e64e140dfa1e5cda8ee5f75787eb7c2b5fa77d8c 100644 (file)
@@ -198,6 +198,7 @@ end ifc
 %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
@@ -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.
index a33d64d7d270f145c6d43f70ee7481558244f5a0..8264ebd06901d92c10f4f76bd4b1e107ae6fcdad 100644 (file)
@@ -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));
index f28e079e4608eb7121180fc98e39f8ca7f750c11..8f40ef77f15db795feed08ad921282f5fbd8f352 100644 (file)
@@ -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
index 5dc9c2d428b8080b76cb63f3b7333343ced0c618..5ce646c146abc4de1e5a35024db6ac01d22fb26a 100644 (file)
@@ -1,3 +1,7 @@
+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.
diff --git a/gcc/testsuite/gcc.dg/c90-arraydecl-1.c b/gcc/testsuite/gcc.dg/c90-arraydecl-1.c
new file mode 100644 (file)
index 0000000..b3e7035
--- /dev/null
@@ -0,0 +1,31 @@
+/* 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.  */
diff --git a/gcc/testsuite/gcc.dg/c99-arraydecl-1.c b/gcc/testsuite/gcc.dg/c99-arraydecl-1.c
new file mode 100644 (file)
index 0000000..24ddd65
--- /dev/null
@@ -0,0 +1,111 @@
+/* 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 } */