* c-common.c (c_expand_expr_stmt): Apply default conversions to
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 6 Nov 2001 12:39:36 +0000 (12:39 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 6 Nov 2001 12:39:36 +0000 (12:39 +0000)
non-lvalue arrays if C99.
* c-typeck.c (default_conversion): Split out code handling
array-to-pointer and function-to-pointer conversions into a
separate default_function_array_conversion function.
(default_function_array_conversion): New function.  Keep track of
whether any NON_LVALUE_EXPRs were stripped.  Return non-lvalue
arrays unchanged outside C99 mode instead of giving an error for
them.
(build_component_ref): Use pedantic_non_lvalue when handling
COMPOUND_EXPR.  Don't handle COND_EXPR specially.
(convert_arguments): Use default_function_array_conversion.
(build_unary_op): For ADDR_EXPR, take a flag indicating whether
non-lvalues are OK.
(unary_complex_lvalue): Likewise.
(internal_build_compound_expr): Use
default_function_array_conversion.  Apply default conversions to
function in compound expression.
(build_c_cast, build_modify_expr, digest_init, build_asm_stmt):
Use default_function_array_conversion.
* doc/extend.texi: Update documentation of subscripting non-lvalue
arrays.
Fixes PR c/461.

testsuite:
* gcc.dg/c90-array-lval-1.c, gcc.dg/c90-array-lval-2.c,
gcc.dg/c99-array-lval-1.c, gcc.dg/c99-array-lval-2.c: Remove
XFAILs.  Adjust expected error texts.
* gcc.c-torture/compile/20011106-1.c,
gcc.c-torture/compile/20011106-2.c, gcc.dg/c90-array-lval-3.c,
gcc.dg/c90-array-lval-4.c, gcc.dg/c90-array-lval-5.c,
gcc.dg/c99-array-lval-3.c, gcc.dg/c99-array-lval-4.c,
gcc.dg/c99-array-lval-5.c: New tests.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@46805 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-typeck.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/20011106-1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/compile/20011106-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c90-array-lval-1.c
gcc/testsuite/gcc.dg/c90-array-lval-2.c
gcc/testsuite/gcc.dg/c90-array-lval-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c90-array-lval-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c90-array-lval-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-array-lval-1.c
gcc/testsuite/gcc.dg/c99-array-lval-2.c
gcc/testsuite/gcc.dg/c99-array-lval-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-array-lval-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-array-lval-5.c [new file with mode: 0644]

index 5382834..823e380 100644 (file)
@@ -1,3 +1,29 @@
+2001-11-06  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * c-common.c (c_expand_expr_stmt): Apply default conversions to
+       non-lvalue arrays if C99.
+       * c-typeck.c (default_conversion): Split out code handling
+       array-to-pointer and function-to-pointer conversions into a
+       separate default_function_array_conversion function.
+       (default_function_array_conversion): New function.  Keep track of
+       whether any NON_LVALUE_EXPRs were stripped.  Return non-lvalue
+       arrays unchanged outside C99 mode instead of giving an error for
+       them.
+       (build_component_ref): Use pedantic_non_lvalue when handling
+       COMPOUND_EXPR.  Don't handle COND_EXPR specially.
+       (convert_arguments): Use default_function_array_conversion.
+       (build_unary_op): For ADDR_EXPR, take a flag indicating whether
+       non-lvalues are OK.
+       (unary_complex_lvalue): Likewise.
+       (internal_build_compound_expr): Use
+       default_function_array_conversion.  Apply default conversions to
+       function in compound expression.
+       (build_c_cast, build_modify_expr, digest_init, build_asm_stmt):
+       Use default_function_array_conversion.
+       * doc/extend.texi: Update documentation of subscripting non-lvalue
+       arrays.
+       Fixes PR c/461.
+
 2001-11-05  Zack Weinberg  <zack@codesourcery.com>
 
        * aclocal.m4: (AM_WITH_NLS): Don't look at ALL_LINGUAS.
index ee633a5..312060d 100644 (file)
@@ -1181,7 +1181,8 @@ c_expand_expr_stmt (expr)
 {
   /* Do default conversion if safe and possibly important,
      in case within ({...}).  */
-  if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr))
+  if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+       && (flag_isoc99 || lvalue_p (expr)))
       || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
     expr = default_conversion (expr);
 
index 34c7ba8..e3e541b 100644 (file)
@@ -55,11 +55,12 @@ static int comp_target_types                PARAMS ((tree, tree));
 static int function_types_compatible_p PARAMS ((tree, tree));
 static int type_lists_compatible_p     PARAMS ((tree, tree));
 static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
+static tree default_function_array_conversion  PARAMS ((tree));
 static tree lookup_field               PARAMS ((tree, tree));
 static tree convert_arguments          PARAMS ((tree, tree, tree, tree));
 static tree pointer_int_sum            PARAMS ((enum tree_code, tree, tree));
 static tree pointer_diff               PARAMS ((tree, tree));
-static tree unary_complex_lvalue       PARAMS ((enum tree_code, tree));
+static tree unary_complex_lvalue       PARAMS ((enum tree_code, tree, int));
 static void pedantic_lvalue_warning    PARAMS ((enum tree_code));
 static tree internal_build_compound_expr PARAMS ((tree, int));
 static tree convert_for_assignment     PARAMS ((tree, tree, const char *,
@@ -838,6 +839,110 @@ decl_constant_value_for_broken_optimization (decl)
     return decl_constant_value (decl);
 }
 
+
+/* Perform the default conversion of arrays and functions to pointers.
+   Return the result of converting EXP.  For any other expression, just
+   return EXP.  */
+
+static tree
+default_function_array_conversion (exp)
+     tree exp;
+{
+  tree orig_exp;
+  tree type = TREE_TYPE (exp);
+  enum tree_code code = TREE_CODE (type);
+  int not_lvalue = 0;
+
+  /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
+     an lvalue. 
+
+     Do not use STRIP_NOPS here!  It will remove conversions from pointer
+     to integer and cause infinite recursion.  */
+  orig_exp = exp;
+  while (TREE_CODE (exp) == NON_LVALUE_EXPR
+        || (TREE_CODE (exp) == NOP_EXPR
+            && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
+    {
+      if (TREE_CODE (exp) == NON_LVALUE_EXPR)
+       not_lvalue = 1;
+      exp = TREE_OPERAND (exp, 0);
+    }
+
+  /* Preserve the original expression code.  */
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
+    C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
+
+  if (code == FUNCTION_TYPE)
+    {
+      return build_unary_op (ADDR_EXPR, exp, 0);
+    }
+  if (code == ARRAY_TYPE)
+    {
+      tree adr;
+      tree restype = TREE_TYPE (type);
+      tree ptrtype;
+      int constp = 0;
+      int volatilep = 0;
+      int lvalue_array_p;
+
+      if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
+       {
+         constp = TREE_READONLY (exp);
+         volatilep = TREE_THIS_VOLATILE (exp);
+       }
+
+      if (TYPE_QUALS (type) || constp || volatilep)
+       restype 
+         = c_build_qualified_type (restype,
+                                   TYPE_QUALS (type) 
+                                   | (constp * TYPE_QUAL_CONST)
+                                   | (volatilep * TYPE_QUAL_VOLATILE));
+
+      if (TREE_CODE (exp) == INDIRECT_REF)
+       return convert (TYPE_POINTER_TO (restype),
+                       TREE_OPERAND (exp, 0));
+
+      if (TREE_CODE (exp) == COMPOUND_EXPR)
+       {
+         tree op1 = default_conversion (TREE_OPERAND (exp, 1));
+         return build (COMPOUND_EXPR, TREE_TYPE (op1),
+                       TREE_OPERAND (exp, 0), op1);
+       }
+
+      lvalue_array_p = !not_lvalue && lvalue_p (exp);
+      if (!flag_isoc99 && !lvalue_array_p
+         && !(TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
+       {
+         /* Before C99, non-lvalue arrays do not decay to pointers.
+            Normally, using such an array would be invalid; but it can
+            be used correctly inside sizeof or as a statement expression.
+            Thus, do not give an error here; an error will result later.  */
+         return exp;
+       }
+
+      ptrtype = build_pointer_type (restype);
+
+      if (TREE_CODE (exp) == VAR_DECL)
+       {
+         /* ??? This is not really quite correct
+            in that the type of the operand of ADDR_EXPR
+            is not the target type of the type of the ADDR_EXPR itself.
+            Question is, can this lossage be avoided?  */
+         adr = build1 (ADDR_EXPR, ptrtype, exp);
+         if (mark_addressable (exp) == 0)
+           return error_mark_node;
+         TREE_CONSTANT (adr) = staticp (exp);
+         TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
+         return adr;
+       }
+      /* This way is better for a COMPONENT_REF since it can
+        simplify the offset for a component.  */
+      adr = build_unary_op (ADDR_EXPR, exp, 1);
+      return convert (ptrtype, adr);
+    }
+  return exp;
+}
+
 /* Perform default promotions for C data used in expressions.
    Arrays and functions are converted to pointers;
    enumeral types or short or char, to int.
@@ -851,6 +956,9 @@ default_conversion (exp)
   tree type = TREE_TYPE (exp);
   enum tree_code code = TREE_CODE (type);
 
+  if (code == FUNCTION_TYPE || code == ARRAY_TYPE)
+    return default_function_array_conversion (exp);
+
   /* Constants can be used directly unless they're not loadable.  */
   if (TREE_CODE (exp) == CONST_DECL)
     exp = DECL_INITIAL (exp);
@@ -924,69 +1032,6 @@ default_conversion (exp)
       error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
-  if (code == FUNCTION_TYPE)
-    {
-      return build_unary_op (ADDR_EXPR, exp, 0);
-    }
-  if (code == ARRAY_TYPE)
-    {
-      tree adr;
-      tree restype = TREE_TYPE (type);
-      tree ptrtype;
-      int constp = 0;
-      int volatilep = 0;
-
-      if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
-       {
-         constp = TREE_READONLY (exp);
-         volatilep = TREE_THIS_VOLATILE (exp);
-       }
-
-      if (TYPE_QUALS (type) || constp || volatilep)
-       restype 
-         = c_build_qualified_type (restype,
-                                   TYPE_QUALS (type) 
-                                   | (constp * TYPE_QUAL_CONST)
-                                   | (volatilep * TYPE_QUAL_VOLATILE));
-
-      if (TREE_CODE (exp) == INDIRECT_REF)
-       return convert (TYPE_POINTER_TO (restype),
-                       TREE_OPERAND (exp, 0));
-
-      if (TREE_CODE (exp) == COMPOUND_EXPR)
-       {
-         tree op1 = default_conversion (TREE_OPERAND (exp, 1));
-         return build (COMPOUND_EXPR, TREE_TYPE (op1),
-                       TREE_OPERAND (exp, 0), op1);
-       }
-
-      if (! lvalue_p (exp)
-         && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
-       {
-         error ("invalid use of non-lvalue array");
-         return error_mark_node;
-       }
-
-      ptrtype = build_pointer_type (restype);
-
-      if (TREE_CODE (exp) == VAR_DECL)
-       {
-         /* ??? This is not really quite correct
-            in that the type of the operand of ADDR_EXPR
-            is not the target type of the type of the ADDR_EXPR itself.
-            Question is, can this lossage be avoided?  */
-         adr = build1 (ADDR_EXPR, ptrtype, exp);
-         if (mark_addressable (exp) == 0)
-           return error_mark_node;
-         TREE_CONSTANT (adr) = staticp (exp);
-         TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
-         return adr;
-       }
-      /* This way is better for a COMPONENT_REF since it can
-        simplify the offset for a component.  */
-      adr = build_unary_op (ADDR_EXPR, exp, 1);
-      return convert (ptrtype, adr);
-    }
   return exp;
 }
 \f
@@ -1098,22 +1143,22 @@ build_component_ref (datum, component)
   tree field = NULL;
   tree ref;
 
-  /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it
-     unless we are not to support things not strictly ANSI.  */
+  /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
+     If pedantic ensure that the arguments are not lvalues; otherwise,
+     if the component is an array, it would wrongly decay to a pointer in
+     C89 mode.
+     We cannot do this with a COND_EXPR, because in a conditional expression
+     the default promotions are applied to both sides, and this would yield
+     the wrong type of the result; for example, if the components have
+     type "char".  */
   switch (TREE_CODE (datum))
     {
     case COMPOUND_EXPR:
       {
        tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
        return build (COMPOUND_EXPR, TREE_TYPE (value),
-                     TREE_OPERAND (datum, 0), value);
+                     TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
       }
-    case COND_EXPR:
-      return build_conditional_expr
-       (TREE_OPERAND (datum, 0),
-        build_component_ref (TREE_OPERAND (datum, 1), component),
-        build_component_ref (TREE_OPERAND (datum, 2), component));
-
     default:
       break;
     }
@@ -1586,9 +1631,7 @@ convert_arguments (typelist, values, name, fundecl)
       if (TREE_CODE (val) == NON_LVALUE_EXPR)
        val = TREE_OPERAND (val, 0);
 
-      if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE)
-       val = default_conversion (val);
+      val = default_function_array_conversion (val);
 
       val = require_complete_type (val);
 
@@ -2771,20 +2814,25 @@ pointer_diff (op0, op1)
 \f
 /* Construct and perhaps optimize a tree representation
    for a unary operation.  CODE, a tree_code, specifies the operation
-   and XARG is the operand.  NOCONVERT nonzero suppresses
-   the default promotions (such as from short to int).  */
+   and XARG is the operand.
+   For any CODE other than ADDR_EXPR, FLAG nonzero suppresses
+   the default promotions (such as from short to int).
+   For ADDR_EXPR, the default promotions are not applied; FLAG nonzero
+   allows non-lvalues; this is only used to handle conversion of non-lvalue
+   arrays to pointers in C99.  */
 
 tree
-build_unary_op (code, xarg, noconvert)
+build_unary_op (code, xarg, flag)
      enum tree_code code;
      tree xarg;
-     int noconvert;
+     int flag;
 {
   /* No default_conversion here.  It causes trouble for ADDR_EXPR.  */
   tree arg = xarg;
   tree argtype = 0;
   enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
   tree val;
+  int noconvert = flag;
 
   if (typecode == ERROR_MARK)
     return error_mark_node;
@@ -2898,7 +2946,7 @@ build_unary_op (code, xarg, noconvert)
       /* Handle complex lvalues (when permitted)
         by reduction to simpler cases.  */
 
-      val = unary_complex_lvalue (code, arg);
+      val = unary_complex_lvalue (code, arg, 0);
       if (val != 0)
        return val;
 
@@ -3045,8 +3093,7 @@ build_unary_op (code, xarg, noconvert)
       }
 
     case ADDR_EXPR:
-      /* Note that this operation never does default_conversion
-        regardless of NOCONVERT.  */
+      /* Note that this operation never does default_conversion.  */
 
       /* Let &* cancel out to simplify resulting code.  */
       if (TREE_CODE (arg) == INDIRECT_REF)
@@ -3068,7 +3115,7 @@ build_unary_op (code, xarg, noconvert)
 
       /* Handle complex lvalues (when permitted)
         by reduction to simpler cases.  */
-      val = unary_complex_lvalue (code, arg);
+      val = unary_complex_lvalue (code, arg, flag);
       if (val != 0)
        return val;
 
@@ -3099,8 +3146,8 @@ build_unary_op (code, xarg, noconvert)
       if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
        ;
       /* Anything not already handled and not a true memory reference
-        is an error.  */
-      else if (typecode != FUNCTION_TYPE
+        or a non-lvalue array is an error.  */
+      else if (typecode != FUNCTION_TYPE && !flag
               && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
        return error_mark_node;
 
@@ -3129,7 +3176,7 @@ build_unary_op (code, xarg, noconvert)
          {
            tree field = TREE_OPERAND (arg, 1);
 
-           addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
+           addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
 
            if (DECL_C_BIT_FIELD (field))
              {
@@ -3248,14 +3295,17 @@ lvalue_or_else (ref, msgid)
 
 /* Apply unary lvalue-demanding operator CODE to the expression ARG
    for certain kinds of expressions which are not really lvalues
-   but which we can accept as lvalues.
+   but which we can accept as lvalues.  If FLAG is nonzero, then
+   non-lvalues are OK since we may be converting a non-lvalue array to
+   a pointer in C99.
 
    If ARG is not a kind of expression we can handle, return zero.  */
    
 static tree
-unary_complex_lvalue (code, arg)
+unary_complex_lvalue (code, arg, flag)
      enum tree_code code;
      tree arg;
+     int flag;
 {
   /* Handle (a, b) used as an "lvalue".  */
   if (TREE_CODE (arg) == COMPOUND_EXPR)
@@ -3264,7 +3314,7 @@ unary_complex_lvalue (code, arg)
 
       /* If this returns a function type, it isn't really being used as
         an lvalue, so don't issue a warning about it.  */
-      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
        pedantic_lvalue_warning (COMPOUND_EXPR);
 
       return build (COMPOUND_EXPR, TREE_TYPE (real_result),
@@ -3274,14 +3324,15 @@ unary_complex_lvalue (code, arg)
   /* Handle (a ? b : c) used as an "lvalue".  */
   if (TREE_CODE (arg) == COND_EXPR)
     {
-      pedantic_lvalue_warning (COND_EXPR);
-      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+      if (!flag)
+       pedantic_lvalue_warning (COND_EXPR);
+      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
        pedantic_lvalue_warning (COMPOUND_EXPR);
 
       return (build_conditional_expr
              (TREE_OPERAND (arg, 0),
-              build_unary_op (code, TREE_OPERAND (arg, 1), 0),
-              build_unary_op (code, TREE_OPERAND (arg, 2), 0)));
+              build_unary_op (code, TREE_OPERAND (arg, 1), flag),
+              build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
     }
 
   return 0;
@@ -3616,9 +3667,11 @@ internal_build_compound_expr (list, first_p)
 
   if (TREE_CHAIN (list) == 0)
     {
-      /* Convert arrays to pointers when there really is a comma operator.  */
-      if (!first_p && TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
-       TREE_VALUE (list) = default_conversion (TREE_VALUE (list));
+      /* Convert arrays and functions to pointers when there
+        really is a comma operator.  */
+      if (!first_p)
+       TREE_VALUE (list)
+         = default_function_array_conversion (TREE_VALUE (list));
 
 #if 0 /* If something inside inhibited lvalueness, we should not override.  */
       /* Consider (x, y+0), which is not an lvalue since y+0 is not.  */
@@ -3705,9 +3758,7 @@ build_c_cast (type, expr)
   else if (TREE_CODE (type) == UNION_TYPE)
     {
       tree field;
-      if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE)
-       value = default_conversion (value);
+      value = default_function_array_conversion (value);
 
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
        if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
@@ -3750,9 +3801,7 @@ build_c_cast (type, expr)
 
       /* Convert functions and arrays to pointers,
         but don't convert any other types.  */
-      if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE)
-       value = default_conversion (value);
+      value = default_function_array_conversion (value);
       otype = TREE_TYPE (value);
 
       /* Optionally warn about potentially worrisome casts.  */
@@ -3952,9 +4001,7 @@ build_modify_expr (lhs, modifycode, rhs)
     case FIX_FLOOR_EXPR:
     case FIX_ROUND_EXPR:
     case FIX_CEIL_EXPR:
-      if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE)
-       newrhs = default_conversion (newrhs);
+      newrhs = default_function_array_conversion (newrhs);
       {
        tree inner_lhs = TREE_OPERAND (lhs, 0);
        tree result;
@@ -4734,10 +4781,8 @@ digest_init (type, init, require_constant, constructor_constant)
              && comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
                            TREE_TYPE (type)))))
     {
-      if (code == POINTER_TYPE
-         && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
-             || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE))
-       inside_init = default_conversion (inside_init);
+      if (code == POINTER_TYPE)
+       inside_init = default_function_array_conversion (inside_init);
       else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
               && TREE_CODE (inside_init) != CONSTRUCTOR)
        {
@@ -6862,9 +6907,7 @@ build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
      Don't do this for other types as it would screw up operands
      expected to be in memory.  */
   for (tail = inputs; tail; tail = TREE_CHAIN (tail))
-    if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE
-       || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
-      TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
+    TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
 
   return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
                               outputs, inputs, clobbers));
index 7d2a28a..5461cae 100644 (file)
@@ -1540,10 +1540,12 @@ removed.
 @cindex arrays, non-lvalue
 
 @cindex subscripting and function values
-Subscripting is allowed on arrays that are not lvalues, even though the
-unary @samp{&} operator is not.  (In ISO C99, both are allowed (though
-the array may not be used after the next sequence point), but this ISO
-C99 feature is not yet fully supported in GCC@.)  For example,
+In ISO C99, arrays that are not lvalues still decay to pointers, and
+may be subscripted, although they may not be modified or used after
+the next sequence point and the unary @samp{&} operator may not be
+applied to them.  As an extension, GCC allows such arrays to be
+subscripted in C89 mode, though otherwise they do not decay to
+pointers outside C99 mode.  For example,
 this is valid in GNU C though not valid in C89:
 
 @example
index 2badf85..d11a53d 100644 (file)
@@ -1,3 +1,14 @@
+2001-11-06  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * gcc.dg/c90-array-lval-1.c, gcc.dg/c90-array-lval-2.c,
+       gcc.dg/c99-array-lval-1.c, gcc.dg/c99-array-lval-2.c: Remove
+       XFAILs.  Adjust expected error texts.
+       * gcc.c-torture/compile/20011106-1.c,
+       gcc.c-torture/compile/20011106-2.c, gcc.dg/c90-array-lval-3.c,
+       gcc.dg/c90-array-lval-4.c, gcc.dg/c90-array-lval-5.c,
+       gcc.dg/c99-array-lval-3.c, gcc.dg/c99-array-lval-4.c,
+       gcc.dg/c99-array-lval-5.c: New tests.
+
 2001-11-05  Neil Booth  <neil@cat.daikokuya.demon.co.uk>
 
        * gcc.dg/cpp/defined.c: Update.
diff --git a/gcc/testsuite/gcc.c-torture/compile/20011106-1.c b/gcc/testsuite/gcc.c-torture/compile/20011106-1.c
new file mode 100644 (file)
index 0000000..9363780
--- /dev/null
@@ -0,0 +1,7 @@
+/* Test that functions passed to the comma operator are correctly converted
+   to pointers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk>.  */
+
+void foo (void);
+void (*fp) (void);
+char x[sizeof (1, foo) == sizeof (fp) ? 1 : -1];
diff --git a/gcc/testsuite/gcc.c-torture/compile/20011106-2.c b/gcc/testsuite/gcc.c-torture/compile/20011106-2.c
new file mode 100644 (file)
index 0000000..358f9d2
--- /dev/null
@@ -0,0 +1,7 @@
+/* Test the the type of a component of a conditional expression between
+   two structures is correct.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk>.  */
+
+struct s { char c; } a, b;
+int c;
+char x[sizeof ((c ? a : b).c) == 1 ? 1 : -1];
index 900dd84..69655c8 100644 (file)
@@ -16,6 +16,6 @@ bar (void)
   (foo ()).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
 }
 /* { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 14 }
-   { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 15 }
-   { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 16 }
+   { dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 15 }
+   { dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 16 }
 */
index b5461e8..9f261e0 100644 (file)
@@ -17,4 +17,4 @@ ASSERT (r, sizeof ((foo ()).c) == 17);
 /* The non-lvalue array does not decay to a pointer, so the comma expression
    has (non-lvalue) array type.
 */
-ASSERT (s, sizeof (0, (foo ()).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" { xfail *-*-* } } */
+ASSERT (s, sizeof (0, (foo ()).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
diff --git a/gcc/testsuite/gcc.dg/c90-array-lval-3.c b/gcc/testsuite/gcc.dg/c90-array-lval-3.c
new file mode 100644 (file)
index 0000000..192a05f
--- /dev/null
@@ -0,0 +1,34 @@
+/* Test for non-lvalue arrays decaying to pointers: in C99 only.
+   Test various ways of producing non-lvalue arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+struct s { char c[1]; };
+struct s a, b, c;
+int d;
+
+void
+bar (void)
+{
+  char *t;
+  (d ? b : c).c[0]; /* { dg-bogus "warning" "warning in place of error" } */
+  (d, b).c[0]; /* { dg-bogus "warning" "warning in place of error" } */
+  (a = b).c[0]; /* { dg-bogus "warning" "warning in place of error" } */
+  t = (d ? b : c).c; /* { dg-bogus "warning" "warning in place of error" } */
+  t = (d, b).c; /* { dg-bogus "warning" "warning in place of error" } */
+  t = (a = b).c; /* { dg-bogus "warning" "warning in place of error" } */
+  (d ? b : c).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
+  (d, b).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
+  (a = b).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
+}
+/* { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 15 }
+   { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 16 }
+   { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 17 }
+   { dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 18 }
+   { dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 19 }
+   { dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 20 }
+   { dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 21 }
+   { dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 22 }
+   { dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 23 }
+*/
diff --git a/gcc/testsuite/gcc.dg/c90-array-lval-4.c b/gcc/testsuite/gcc.dg/c90-array-lval-4.c
new file mode 100644 (file)
index 0000000..1f9cb14
--- /dev/null
@@ -0,0 +1,26 @@
+/* Test for non-lvalue arrays decaying to pointers: in C99 only.
+   Test various ways of producing non-lvalue arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+struct s { char c[17]; };
+
+struct s x;
+
+struct s a, b, c;
+int d;
+
+#define ASSERT(v, a)   char v[((a) ? 1 : -1)]
+
+ASSERT (p, sizeof (x.c) == 17);
+ASSERT (q, sizeof (0, x.c) == sizeof (char *));
+ASSERT (r0, sizeof ((d ? b : c).c) == 17);
+ASSERT (r1, sizeof ((d, b).c) == 17);
+ASSERT (r2, sizeof ((a = b).c) == 17);
+/* The non-lvalue array does not decay to a pointer, so the comma expression
+   has (non-lvalue) array type.
+*/
+ASSERT (s0, sizeof (0, (d ? b : c).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
+ASSERT (s0, sizeof (0, (d, b).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
+ASSERT (s0, sizeof (0, (a = b).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
diff --git a/gcc/testsuite/gcc.dg/c90-array-lval-5.c b/gcc/testsuite/gcc.dg/c90-array-lval-5.c
new file mode 100644 (file)
index 0000000..c218a4d
--- /dev/null
@@ -0,0 +1,26 @@
+/* Test for non-lvalue arrays: test that the unary '&' operator is not
+   allowed on them, for both C90 and C99.  */
+
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+struct s { char c[1]; };
+
+extern struct s foo (void);
+struct s a, b, c;
+int d;
+
+void
+bar (void)
+{
+  &((foo ()).c); /* { dg-bogus "warning" "warning in place of error" } */
+  &((d ? b : c).c); /* { dg-bogus "warning" "warning in place of error" } */
+  &((d, b).c); /* { dg-bogus "warning" "warning in place of error" } */
+  &((a = b).c); /* { dg-bogus "warning" "warning in place of error" } */
+}
+/* { dg-error "lvalue" "bad address-of" { target *-*-* } 17 }
+   { dg-error "lvalue" "bad address-of" { target *-*-* } 18 }
+   { dg-error "lvalue" "bad address-of" { target *-*-* } 19 }
+   { dg-error "lvalue" "bad address-of" { target *-*-* } 20 }
+*/
index 616ddb9..c0fccc8 100644 (file)
@@ -12,6 +12,6 @@ bar (void)
 {
   char *t;
   (foo ()).c[0]; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" } */
-  t = (foo ()).c; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" { xfail *-*-* } } */
-  (foo ()).c + 1; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" { xfail *-*-* } } */
+  t = (foo ()).c; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" } */
+  (foo ()).c + 1; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" } */
 }
index 68d8599..894ff95 100644 (file)
@@ -15,4 +15,4 @@ ASSERT (p, sizeof (x.c) == 17);
 ASSERT (q, sizeof (0, x.c) == sizeof (char *));
 ASSERT (r, sizeof ((foo ()).c) == 17);
 /* The non-lvalue array decays to a pointer in C99.  */
-ASSERT (s, sizeof (0, (foo ()).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" { xfail *-*-* } } */
+ASSERT (s, sizeof (0, (foo ()).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
diff --git a/gcc/testsuite/gcc.dg/c99-array-lval-3.c b/gcc/testsuite/gcc.dg/c99-array-lval-3.c
new file mode 100644 (file)
index 0000000..a12a960
--- /dev/null
@@ -0,0 +1,24 @@
+/* Test for non-lvalue arrays decaying to pointers: in C99 only.
+   Test various ways of producing non-lvalue arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+struct s { char c[1]; };
+struct s a, b, c;
+int d;
+
+void
+bar (void)
+{
+  char *t;
+  (d ? b : c).c[0];
+  (d, b).c[0];
+  (a = b).c[0];
+  t = (d ? b : c).c;
+  t = (d, b).c;
+  t = (a = b).c;
+  (d ? b : c).c + 1;
+  (d, b).c + 1;
+  (a = b).c + 1;
+}
diff --git a/gcc/testsuite/gcc.dg/c99-array-lval-4.c b/gcc/testsuite/gcc.dg/c99-array-lval-4.c
new file mode 100644 (file)
index 0000000..259ce92
--- /dev/null
@@ -0,0 +1,24 @@
+/* Test for non-lvalue arrays decaying to pointers: in C99 only.
+   Test various ways of producing non-lvalue arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+struct s { char c[17]; };
+
+struct s x;
+
+struct s a, b, c;
+int d;
+
+#define ASSERT(v, a)   char v[((a) ? 1 : -1)]
+
+ASSERT (p, sizeof (x.c) == 17);
+ASSERT (q, sizeof (0, x.c) == sizeof (char *));
+ASSERT (r0, sizeof ((d ? b : c).c) == 17);
+ASSERT (r1, sizeof ((d, b).c) == 17);
+ASSERT (r2, sizeof ((a = b).c) == 17);
+/* The non-lvalue array decays to a pointer in C99.  */
+ASSERT (s0, sizeof (0, (d ? b : c).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
+ASSERT (s0, sizeof (0, (d, b).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
+ASSERT (s0, sizeof (0, (a = b).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
diff --git a/gcc/testsuite/gcc.dg/c99-array-lval-5.c b/gcc/testsuite/gcc.dg/c99-array-lval-5.c
new file mode 100644 (file)
index 0000000..57e806d
--- /dev/null
@@ -0,0 +1,26 @@
+/* Test for non-lvalue arrays: test that the unary '&' operator is not
+   allowed on them, for both C90 and C99.  */
+
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+struct s { char c[1]; };
+
+extern struct s foo (void);
+struct s a, b, c;
+int d;
+
+void
+bar (void)
+{
+  &((foo ()).c); /* { dg-bogus "warning" "warning in place of error" } */
+  &((d ? b : c).c); /* { dg-bogus "warning" "warning in place of error" } */
+  &((d, b).c); /* { dg-bogus "warning" "warning in place of error" } */
+  &((a = b).c); /* { dg-bogus "warning" "warning in place of error" } */
+}
+/* { dg-error "lvalue" "bad address-of" { target *-*-* } 17 }
+   { dg-error "lvalue" "bad address-of" { target *-*-* } 18 }
+   { dg-error "lvalue" "bad address-of" { target *-*-* } 19 }
+   { dg-error "lvalue" "bad address-of" { target *-*-* } 20 }
+*/