OSDN Git Service

(tablejump_internal4+1): Fix typo in condition.
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index 8c5f2cd..06ef493 100644 (file)
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C compiler.
-   Copyright (C) 1987, 88, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91, 92-5, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -42,7 +42,7 @@ static int missing_braces_mentioned;
 extern char *index ();
 extern char *rindex ();
 
-static tree quality_type               PROTO((tree, tree));
+static tree qualify_type               PROTO((tree, tree));
 static int comp_target_types           PROTO((tree, tree));
 static int function_types_compatible_p PROTO((tree, tree));
 static int type_lists_compatible_p     PROTO((tree, tree));
@@ -193,39 +193,7 @@ common_type (t1, t2)
     return t1;
 
   /* Merge the attributes */
-
-  { register tree a1, a2;
-    a1 = TYPE_ATTRIBUTES (t1);
-    a2 = TYPE_ATTRIBUTES (t2);
-
-    /* Either one unset?  Take the set one.  */
-
-    if (!(attributes = a1))
-       attributes = a2;
-
-    /* One that completely contains the other?  Take it.  */
-
-    else if (a2 && !attribute_list_contained (a1, a2))
-       if (attribute_list_contained (a2, a1))
-         attributes = a2;
-       else
-       {
-         /* Pick the longest list, and hang on the other list.  */
-         /* ??? For the moment we punt on the issue of attrs with args.  */
-       
-         if (list_length (a1) < list_length (a2))
-            attributes = a2, a2 = a1;
-
-         for (; a2; a2 = TREE_CHAIN (a2))
-           if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
-                                 attributes) == NULL_TREE)
-             {
-               a1 = copy_node (a2);
-               TREE_CHAIN (a1) = attributes;
-               attributes = a1;
-             }
-       }
-  }
+  attributes = merge_attributes (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2));
 
   /* Treat an enum type as the unsigned integer type of the same width.  */
 
@@ -759,6 +727,14 @@ unsigned_type (type)
     return long_unsigned_type_node;
   if (type1 == long_long_integer_type_node)
     return long_long_unsigned_type_node;
+  if (type1 == intDI_type_node)
+    return unsigned_intDI_type_node;
+  if (type1 == intSI_type_node)
+    return unsigned_intSI_type_node;
+  if (type1 == intHI_type_node)
+    return unsigned_intHI_type_node;
+  if (type1 == intQI_type_node)
+    return unsigned_intQI_type_node;
   return type;
 }
 
@@ -779,6 +755,14 @@ signed_type (type)
     return long_integer_type_node;
   if (type1 == long_long_unsigned_type_node)
     return long_long_integer_type_node;
+  if (type1 == unsigned_intDI_type_node)
+    return intDI_type_node;
+  if (type1 == unsigned_intSI_type_node)
+    return intSI_type_node;
+  if (type1 == unsigned_intHI_type_node)
+    return intHI_type_node;
+  if (type1 == unsigned_intQI_type_node)
+    return intQI_type_node;
   return type;
 }
 
@@ -924,7 +908,7 @@ c_alignof_expr (expr)
     return size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
  
   if (TREE_CODE (expr) == COMPONENT_REF
-      && DECL_BIT_FIELD (TREE_OPERAND (expr, 1)))
+      && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
     {
       error ("`__alignof' applied to a bit-field");
       return size_int (1);
@@ -1460,7 +1444,8 @@ build_array_ref (array, index)
     if (ar == error_mark_node)
       return ar;
 
-    if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE)
+    if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE
+       || TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) == FUNCTION_TYPE)
       {
        error ("subscripted value is neither array nor pointer");
        return error_mark_node;
@@ -1807,6 +1792,9 @@ parser_build_binary_op (code, arg1, arg2)
              || code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
              || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
            warning ("suggest parentheses around arithmetic in operand of |");
+         /* Check cases like x|y==z */
+         if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+           warning ("suggest parentheses around comparison in operand of |");
        }
 
       if (code == BIT_XOR_EXPR)
@@ -1816,6 +1804,9 @@ parser_build_binary_op (code, arg1, arg2)
              || code2 == BIT_AND_EXPR
              || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
            warning ("suggest parentheses around arithmetic in operand of ^");
+         /* Check cases like x^y==z */
+         if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+           warning ("suggest parentheses around comparison in operand of ^");
        }
 
       if (code == BIT_AND_EXPR)
@@ -1823,6 +1814,9 @@ parser_build_binary_op (code, arg1, arg2)
          if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
              || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
            warning ("suggest parentheses around + or - in operand of &");
+         /* Check cases like x&y==z */
+         if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
+           warning ("suggest parentheses around comparison in operand of &");
        }
     }
 
@@ -2446,7 +2440,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
          converted = 1;
          resultcode = xresultcode;
 
-         if (extra_warnings)
+         if (warn_sign_compare)
            {
              int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
              int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
@@ -2488,9 +2482,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
                  not use the most significant bit of result_type.  */
              else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
                       && ((op0_signed && TREE_CODE (xop1) == INTEGER_CST
-                           && int_fits_type_p (xop1, signed_type (result_type))
+                           && int_fits_type_p (xop1, signed_type (result_type)))
                           || (op1_signed && TREE_CODE (xop0) == INTEGER_CST
-                              && int_fits_type_p (xop0, signed_type (result_type))))))
+                              && int_fits_type_p (xop0, signed_type (result_type)))))
                /* OK */;
              else
                warning ("comparison between signed and unsigned");
@@ -2632,7 +2626,13 @@ pointer_int_sum (resultcode, ptrop, intop)
       && TREE_CONSTANT (size_exp)
       /* If the constant comes from pointer subtraction,
         skip this optimization--it would cause an error.  */
-      && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE)
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE
+      /* If the constant is unsigned, and smaller than the pointer size,
+        then we must skip this optimization.  This is because it could cause
+        an overflow error if the constant is negative but INTOP is not.  */
+      && (! TREE_UNSIGNED (TREE_TYPE (intop))
+         || (TYPE_PRECISION (TREE_TYPE (intop))
+             == TYPE_PRECISION (TREE_TYPE (ptrop)))))
     {
       enum tree_code subcode = resultcode;
       tree int_type = TREE_TYPE (intop);
@@ -2646,11 +2646,11 @@ pointer_int_sum (resultcode, ptrop, intop)
       intop = convert (int_type, TREE_OPERAND (intop, 0));
     }
 
-  /* Convert the integer argument to a type the same size as a pointer
+  /* Convert the integer argument to a type the same size as sizetype
      so the multiply won't overflow spuriously.  */
 
-  if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
-    intop = convert (type_for_size (POINTER_SIZE, 0), intop);
+  if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
+    intop = convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
 
   /* Replace the integer argument with a suitable product by the object size.
      Do this multiplication as signed, then convert to the appropriate
@@ -3039,7 +3039,7 @@ build_unary_op (code, xarg, noconvert)
 
            addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
 
-           if (DECL_BIT_FIELD (field))
+           if (DECL_C_BIT_FIELD (field))
              {
                error ("attempt to take address of bit-field structure member `%s'",
                       IDENTIFIER_POINTER (DECL_NAME (field)));
@@ -3256,8 +3256,17 @@ mark_addressable (exp)
   while (1)
     switch (TREE_CODE (x))
       {
-      case ADDR_EXPR:
       case COMPONENT_REF:
+       if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
+         {
+           error ("cannot take address of bitfield `%s'",
+                  IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1))));
+           return 0;
+         }
+
+       /* ... fall through ... */
+
+      case ADDR_EXPR:
       case ARRAY_REF:
       case REALPART_EXPR:
       case IMAGPART_EXPR:
@@ -3341,7 +3350,7 @@ build_conditional_expr (ifexp, op1, op2)
     {
       if (pedantic)
        pedwarn ("ANSI C forbids omitting the middle term of a ?: expression");
-      ifexp = op1 = save_expr (ifexp);
+      ifexp = orig_op1 = op1 = save_expr (ifexp);
     }
 
   ifexp = truthvalue_conversion (default_conversion (ifexp));
@@ -3704,6 +3713,11 @@ build_c_cast (type, expr)
          && TREE_CODE (otype) == POINTER_TYPE
          && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
          && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
+         /* Don't warn about opaque types, where the actual alignment
+            restriction is unknown.  */
+         && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE
+               || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
+              && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
          && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
        warning ("cast increases required alignment of target type");
 
@@ -3983,26 +3997,27 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
          || coder == COMPLEX_TYPE))
     return convert_and_check (type, rhs);
 
-  /* Conversion to a union from its member types.  */
-  else if (codel == UNION_TYPE)
+  /* Conversion to a transparent union from its member types.
+     This applies only to function arguments.  */
+  else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype)
     {
       tree memb_types;
+      tree marginal_memb_type = 0;
 
       for (memb_types = TYPE_FIELDS (type); memb_types;
           memb_types = TREE_CHAIN (memb_types))
        {
-         if (comptypes (TREE_TYPE (memb_types), TREE_TYPE (rhs)))
-           {
-             if (pedantic
-                 && !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
-               pedwarn ("ANSI C prohibits argument conversion to union type");
-             return build1 (NOP_EXPR, type, rhs);
-           }
+         tree memb_type = TREE_TYPE (memb_types);
 
-         else if (coder == POINTER_TYPE
-                  && TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE)
+         if (comptypes (TYPE_MAIN_VARIANT (memb_type),
+                        TYPE_MAIN_VARIANT (rhstype)))
+           break;
+
+         if (TREE_CODE (memb_type) != POINTER_TYPE)
+           continue;
+
+         if (coder == POINTER_TYPE)
            {
-             tree memb_type = TREE_TYPE (memb_types);
              register tree ttl = TREE_TYPE (memb_type);
              register tree ttr = TREE_TYPE (rhstype);
 
@@ -4014,50 +4029,76 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
                  || TYPE_MAIN_VARIANT (ttr) == void_type_node
                  || comp_target_types (memb_type, rhstype))
                {
-                 /* Const and volatile mean something different for function
-                    types, so the usual warnings are not appropriate.  */
-                 if (TREE_CODE (ttr) != FUNCTION_TYPE
-                     || TREE_CODE (ttl) != FUNCTION_TYPE)
-                   {
-                     if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
-                       warn_for_assignment ("%s discards `const' from pointer target type",
-                                            get_spelling (errtype), funname,
-                                            parmnum);
-                     if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
-                       warn_for_assignment ("%s discards `volatile' from pointer target type",
-                                            get_spelling (errtype), funname,
-                                            parmnum);
-                   }
-                 else
-                   {
-                     /* Because const and volatile on functions are
-                        restrictions that say the function will not do
-                        certain things, it is okay to use a const or volatile
-                        function where an ordinary one is wanted, but not
-                        vice-versa.  */
-                     if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
-                       warn_for_assignment ("%s makes `const *' function pointer from non-const",
-                                            get_spelling (errtype), funname,
-                                            parmnum);
-                     if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
-                       warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
-                                            get_spelling (errtype), funname,
-                                            parmnum);
-                   }
-
-                 if (pedantic
-                     && !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
-                   pedwarn ("ANSI C prohibits argument conversion to union type");
-                 return build1 (NOP_EXPR, type, rhs);
+                 /* If this type won't generate any warnings, use it.  */
+                 if ((TREE_CODE (ttr) == FUNCTION_TYPE
+                      && TREE_CODE (ttl) == FUNCTION_TYPE)
+                     ? ((! TYPE_READONLY (ttl) | TYPE_READONLY (ttr))
+                        & (! TYPE_VOLATILE (ttl) | TYPE_VOLATILE (ttr)))
+                     : ((TYPE_READONLY (ttl) | ! TYPE_READONLY (ttr))
+                        & (TYPE_VOLATILE (ttl) | ! TYPE_VOLATILE (ttr))))
+                   break;
+
+                 /* Keep looking for a better type, but remember this one.  */
+                 if (! marginal_memb_type)
+                   marginal_memb_type = memb_type;
                }
            }
 
          /* Can convert integer zero to any pointer type.  */
-         else if (TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE
-                  && (integer_zerop (rhs)
-                      || (TREE_CODE (rhs) == NOP_EXPR
-                          && integer_zerop (TREE_OPERAND (rhs, 0)))))
-           return build1 (NOP_EXPR, type, null_pointer_node);
+         if (integer_zerop (rhs)
+             || (TREE_CODE (rhs) == NOP_EXPR
+                 && integer_zerop (TREE_OPERAND (rhs, 0))))
+           {
+             rhs = null_pointer_node;
+             break;
+           }
+       }
+
+      if (memb_types || marginal_memb_type)
+       {
+         if (! memb_types)
+           {
+             /* We have only a marginally acceptable member type;
+                it needs a warning. */
+             register tree ttl = TREE_TYPE (marginal_memb_type);
+             register tree ttr = TREE_TYPE (rhstype);
+
+             /* Const and volatile mean something different for function
+                types, so the usual warnings are not appropriate.  */
+             if (TREE_CODE (ttr) == FUNCTION_TYPE
+                 && TREE_CODE (ttl) == FUNCTION_TYPE)
+               {
+                 /* Because const and volatile on functions are
+                    restrictions that say the function will not do
+                    certain things, it is okay to use a const or volatile
+                    function where an ordinary one is wanted, but not
+                    vice-versa.  */
+                 if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
+                   warn_for_assignment ("%s makes `const *' function pointer from non-const",
+                                        get_spelling (errtype), funname,
+                                        parmnum);
+                 if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
+                   warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
+                                        get_spelling (errtype), funname,
+                                        parmnum);
+               }
+             else
+               {
+                 if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
+                   warn_for_assignment ("%s discards `const' from pointer target type",
+                                        get_spelling (errtype), funname,
+                                        parmnum);
+                 if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
+                   warn_for_assignment ("%s discards `volatile' from pointer target type",
+                                        get_spelling (errtype), funname,
+                                        parmnum);
+               }
+           }
+         
+         if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl))
+           pedwarn ("ANSI C prohibits argument conversion to union type");
+
+         return build1 (NOP_EXPR, type, rhs);
        }
     }
 
@@ -4239,7 +4280,8 @@ initializer_constant_valid_p (value, endtype)
     case CONSTRUCTOR:
       if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
           || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
-         && TREE_CONSTANT (value))
+         && TREE_CONSTANT (value)
+         && CONSTRUCTOR_ELTS (value))
        return
          initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
                                        endtype);
@@ -4872,7 +4914,7 @@ digest_init (type, init, require_constant, constructor_constant)
      and it initializes the first element of x to 0.  */
   if (flag_traditional)
     {
-      tree top = 0, prev = 0;
+      tree top = 0, prev = 0, otype = type;
       while (TREE_CODE (type) == RECORD_TYPE
             || TREE_CODE (type) == ARRAY_TYPE
             || TREE_CODE (type) == QUAL_UNION_TYPE
@@ -4894,11 +4936,17 @@ digest_init (type, init, require_constant, constructor_constant)
              return error_mark_node;
            }
        }
-      TREE_OPERAND (prev, 1)
-       = build_tree_list (NULL_TREE,
-                          digest_init (type, init, require_constant,
-                                       constructor_constant));
-      return top;
+
+      if (otype != type)
+       {
+         TREE_OPERAND (prev, 1)
+           = build_tree_list (NULL_TREE,
+                              digest_init (type, init, require_constant,
+                                           constructor_constant));
+         return top;
+       }
+      else
+       return error_mark_node;
     }
   error_init ("invalid initializer%s", " for `%s'", NULL);
   return error_mark_node;
@@ -5209,8 +5257,8 @@ really_start_incremental_init (type)
       || TREE_CODE (constructor_type) == UNION_TYPE)
     {
       constructor_fields = TYPE_FIELDS (constructor_type);
-      /* Skip any nameless bit fields atthe beginning.  */
-      while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+      /* Skip any nameless bit fields at the beginning.  */
+      while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
             && DECL_NAME (constructor_fields) == 0)
        constructor_fields = TREE_CHAIN (constructor_fields);
       constructor_unfilled_fields = constructor_fields;
@@ -5283,10 +5331,12 @@ push_init_level (implicit)
        break;
     }
 
-  /* Structure elements may require alignment.  Do this now
-     if necessary for the subaggregate.  */
+  /* Structure elements may require alignment.  Do this now if necessary
+     for the subaggregate, and if it comes next in sequence.  Don't do
+     this for subaggregates that will go on the pending list.  */
   if (constructor_incremental && constructor_type != 0
-      && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields)
+      && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields
+      && constructor_fields == constructor_unfilled_fields)
     {
       /* Advance to offset of this element.  */
       if (! tree_int_cst_equal (constructor_bit_index,
@@ -5300,6 +5350,9 @@ push_init_level (implicit)
 
          assemble_zeros (next - here);
        }
+      /* Indicate that we have now filled the structure up to the current
+        field.  */
+      constructor_unfilled_fields = constructor_fields;
     }
 
   p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
@@ -5381,8 +5434,8 @@ push_init_level (implicit)
           || TREE_CODE (constructor_type) == UNION_TYPE)
     {
       constructor_fields = TYPE_FIELDS (constructor_type);
-      /* Skip any nameless bit fields atthe beginning.  */
-      while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+      /* Skip any nameless bit fields at the beginning.  */
+      while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
             && DECL_NAME (constructor_fields) == 0)
        constructor_fields = TREE_CHAIN (constructor_fields);
       constructor_unfilled_fields = constructor_fields;
@@ -5424,7 +5477,7 @@ check_init_type_bitfields (type)
       for (tail = TYPE_FIELDS (type); tail;
           tail = TREE_CHAIN (tail))
        {
-         if (DECL_BIT_FIELD (tail)
+         if (DECL_C_BIT_FIELD (tail)
              /* This catches cases like `int foo : 8;'.  */
              || DECL_MODE (tail) != TYPE_MODE (TREE_TYPE (tail)))
            {
@@ -5686,6 +5739,8 @@ set_init_index (first, last)
     error_init ("nonconstant array index in initializer%s", " for `%s'", NULL);
   else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
     error_init ("nonconstant array index in initializer%s", " for `%s'", NULL);
+  else if (! constructor_unfilled_index)
+    error_init ("array index in non-array initializer%s", " for `%s'", NULL);
   else if (tree_int_cst_lt (first, constructor_unfilled_index))
     error_init ("duplicate array index in initializer%s", " for `%s'", NULL);
   else
@@ -5715,6 +5770,11 @@ set_init_label (fieldname)
   tree tail;
   int passed = 0;
 
+  /* Don't die if an entire brace-pair level is superfluous
+     in the containing level.  */
+  if (constructor_type == 0)
+    return;
+
   for (tail = TYPE_FIELDS (constructor_type); tail;
        tail = TREE_CHAIN (tail))
     {
@@ -5771,7 +5831,8 @@ output_init_element (value, type, field, pending)
   else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0
           || ((TREE_CODE (constructor_type) == RECORD_TYPE
                || TREE_CODE (constructor_type) == UNION_TYPE)
-              && DECL_BIT_FIELD (field) && TREE_CODE (value) != INTEGER_CST))
+              && DECL_C_BIT_FIELD (field)
+              && TREE_CODE (value) != INTEGER_CST))
     constructor_simple = 0;
 
   if (require_constant_value && ! TREE_CONSTANT (value))
@@ -6194,8 +6255,9 @@ process_init_element (value)
            }
 
          constructor_fields = TREE_CHAIN (constructor_fields);
-         /* Skip any nameless bit fields atthe beginning.  */
-         while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+         /* Skip any nameless bit fields at the beginning.  */
+         while (constructor_fields != 0
+                && DECL_C_BIT_FIELD (constructor_fields)
                 && DECL_NAME (constructor_fields) == 0)
            constructor_fields = TREE_CHAIN (constructor_fields);
          break;
@@ -6410,7 +6472,8 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       else
        {
          tree type = TREE_TYPE (o[i]);
-         if (TYPE_READONLY (type)
+         if (TREE_READONLY (o[i])
+             || TYPE_READONLY (type)
              || ((TREE_CODE (type) == RECORD_TYPE
                   || TREE_CODE (type) == UNION_TYPE)
                  && C_TYPE_FIELDS_READONLY (type)))