re PR c/13519 (typeof(nonconst+const) is const)
authorJoseph Myers <jsm@polyomino.org.uk>
Sun, 6 Jun 2004 15:21:59 +0000 (16:21 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Sun, 6 Jun 2004 15:21:59 +0000 (16:21 +0100)
PR c/13519
* c-typeck.c (composite_type, common_pointer_type): New functions.
(common_type): Split parts into composite_type and
common_pointer_type.  Ensure that arithmetic operations return
unqualified types without attributes.  Don't make composite type
of signed enum and compatible integer be unsigned.
(build_conditional_expr, build_binary_op): Use
common_pointer_type.
* c-decl.c (merge_decls): Use composite_type.
* c-tree.h (composite_type): Declare.

testsuite:
* gcc.c-torture/enum-3.c, gcc.dg/pr13519-1.c: New tests.

From-SVN: r82671

gcc/ChangeLog
gcc/c-decl.c
gcc/c-tree.h
gcc/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/enum-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr13519-1.c [new file with mode: 0644]

index cca009b..f3f622e 100644 (file)
@@ -1,3 +1,16 @@
+2004-06-06  Joseph S. Myers  <jsm@polyomino.org.uk>
+
+       PR c/13519
+       * c-typeck.c (composite_type, common_pointer_type): New functions.
+       (common_type): Split parts into composite_type and
+       common_pointer_type.  Ensure that arithmetic operations return
+       unqualified types without attributes.  Don't make composite type
+       of signed enum and compatible integer be unsigned.
+       (build_conditional_expr, build_binary_op): Use
+       common_pointer_type.
+       * c-decl.c (merge_decls): Use composite_type.
+       * c-tree.h (composite_type): Declare.
+
 2004-06-06  Stephane Carrez  <stcarrez@nerim.fr>
 
        PR target/14457
index 3a13664..ee09afa 100644 (file)
@@ -1452,7 +1452,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
   /* Merge the data types specified in the two decls.  */
   TREE_TYPE (newdecl)
     = TREE_TYPE (olddecl)
-    = common_type (newtype, oldtype);
+    = composite_type (newtype, oldtype);
 
   /* Lay the type out, unless already done.  */
   if (oldtype != TREE_TYPE (newdecl))
index 9e21b4f..e698c87 100644 (file)
@@ -226,6 +226,7 @@ extern tree c_size_in_bytes (tree);
 extern bool c_mark_addressable (tree);
 extern void c_incomplete_type_error (tree, tree);
 extern tree c_type_promotes_to (tree);
+extern tree composite_type (tree, tree);
 extern tree build_component_ref (tree, tree);
 extern tree build_indirect_ref (tree, const char *);
 extern tree build_array_ref (tree, tree);
index cf01aa5..bdbb58b 100644 (file)
@@ -199,19 +199,14 @@ qualify_type (tree type, tree like)
                                 TYPE_QUALS (type) | TYPE_QUALS (like));
 }
 \f
-/* Return the composite type of two compatible types, or the common
-   type for two arithmetic types under the usual arithmetic
-   conversions.
+/* Return the composite type of two compatible types.
 
-   Unless both types are arithmetic types, we assume that comptypes
-   has already been done and returned 1; if that isn't so, this may
-   crash.  In particular, we assume that qualifiers match.
-
-   This is the type for the result of most arithmetic operations
-   if the operands have the given two types.  */
+   We assume that comptypes has already been done and returned
+   nonzero; if that isn't so, this may crash.  In particular, we
+   assume that qualifiers match.  */
 
 tree
-common_type (tree t1, tree t2)
+composite_type (tree t1, tree t2)
 {
   enum tree_code code1;
   enum tree_code code2;
@@ -227,145 +222,40 @@ common_type (tree t1, tree t2)
   if (t2 == error_mark_node)
     return t1;
 
+  code1 = TREE_CODE (t1);
+  code2 = TREE_CODE (t2);
+
   /* Merge the attributes.  */
   attributes = targetm.merge_type_attributes (t1, t2);
 
-  /* Treat an enum type as the unsigned integer type of the same width.  */
-
-  if (TREE_CODE (t1) == ENUMERAL_TYPE)
-    t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
-  if (TREE_CODE (t2) == ENUMERAL_TYPE)
-    t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
-
-  code1 = TREE_CODE (t1);
-  code2 = TREE_CODE (t2);
+  /* If one is an enumerated type and the other is the compatible
+     integer type, the composite type might be either of the two
+     (DR#013 question 3).  For consistency, use the enumerated type as
+     the composite type.  */
 
-  /* If one type is complex, form the common type of the non-complex
-     components, then make that complex.  Use T1 or T2 if it is the
-     required type.  */
-  if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
-    {
-      tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
-      tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
-      tree subtype = common_type (subtype1, subtype2);
+  if (code1 == ENUMERAL_TYPE && code2 == INTEGER_TYPE)
+    return t1;
+  if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE)
+    return t2;
 
-      if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
-       return build_type_attribute_variant (t1, attributes);
-      else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
-       return build_type_attribute_variant (t2, attributes);
-      else
-       return build_type_attribute_variant (build_complex_type (subtype),
-                                            attributes);
-    }
+  if (code1 != code2)
+    abort ();
 
   switch (code1)
     {
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-      /* If only one is real, use it as the result.  */
-
-      if (code1 == REAL_TYPE && code2 != REAL_TYPE)
-       return build_type_attribute_variant (t1, attributes);
-
-      if (code2 == REAL_TYPE && code1 != REAL_TYPE)
-       return build_type_attribute_variant (t2, attributes);
-
-      /* Both real or both integers; use the one with greater precision.  */
-
-      if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
-       return build_type_attribute_variant (t1, attributes);
-      else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
-       return build_type_attribute_variant (t2, attributes);
-
-      /* Same precision.  Prefer long longs to longs to ints when the
-        same precision, following the C99 rules on integer type rank
-        (which are equivalent to the C90 rules for C90 types).
-        Make sure that we don't lose the type qualifications when
-        creating the new variant.  */
-
-      if (TYPE_MAIN_VARIANT (t1) == long_long_unsigned_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_long_unsigned_type_node)
-       {
-         t1 = build_qualified_type (long_long_unsigned_type_node,
-                                    TYPE_QUALS (t1));
-         return build_type_attribute_variant (t1, attributes);
-       }
-
-      if (TYPE_MAIN_VARIANT (t1) == long_long_integer_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_long_integer_type_node)
-       {
-         tree ntype;
-
-         if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
-            ntype = long_long_unsigned_type_node;
-         else
-            ntype = long_long_integer_type_node;
-
-         ntype = build_qualified_type (ntype, TYPE_QUALS (t1));
-         return build_type_attribute_variant (ntype, attributes);
-       }
-
-      if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
-       {
-         t1 = build_qualified_type (long_unsigned_type_node,
-                                    TYPE_QUALS (t1));
-         return build_type_attribute_variant (t1, attributes);
-       }
-
-      if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
-       {
-         tree ntype;
-
-         /* But preserve unsignedness from the other type,
-            since long cannot hold all the values of an unsigned int.  */
-         if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
-            ntype = long_unsigned_type_node;
-         else
-            ntype = long_integer_type_node;
-
-         ntype = build_qualified_type (ntype, TYPE_QUALS (t1));
-         return build_type_attribute_variant (ntype, attributes);
-       }
-
-      /* Likewise, prefer long double to double even if same size.  */
-      if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
-       {
-         t1 = build_qualified_type (long_double_type_node,
-                                    TYPE_QUALS (t1));
-         return build_type_attribute_variant (t1, attributes);
-       }
-
-      /* Otherwise prefer the unsigned one.  */
-
-      if (TYPE_UNSIGNED (t1))
-       return build_type_attribute_variant (t1, attributes);
-      else
-       return build_type_attribute_variant (t2, attributes);
-
     case POINTER_TYPE:
-      /* For two pointers, do this recursively on the target type,
-        and combine the qualifiers of the two types' targets.  */
-      /* This code was turned off; I don't know why.
-        But ANSI C specifies doing this with the qualifiers.
-        So I turned it on again.  */
+      /* For two pointers, do this recursively on the target type.  */
       {
        tree pointed_to_1 = TREE_TYPE (t1);
        tree pointed_to_2 = TREE_TYPE (t2);
-       tree target = common_type (TYPE_MAIN_VARIANT (pointed_to_1),
-                                  TYPE_MAIN_VARIANT (pointed_to_2));
-       t1 = build_pointer_type (c_build_qualified_type
-                                (target,
-                                 TYPE_QUALS (pointed_to_1) |
-                                 TYPE_QUALS (pointed_to_2)));
+       tree target = composite_type (pointed_to_1, pointed_to_2);
+       t1 = build_pointer_type (target);
        return build_type_attribute_variant (t1, attributes);
       }
 
     case ARRAY_TYPE:
       {
-       tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
+       tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
        /* Save space: see if the result is identical to one of the args.  */
        if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
          return build_type_attribute_variant (t1, attributes);
@@ -380,7 +270,7 @@ common_type (tree t1, tree t2)
       /* Function types: prefer the one that specified arg types.
         If both do, merge the arg types.  Also merge the return types.  */
       {
-       tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
+       tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
        tree p1 = TYPE_ARG_TYPES (t1);
        tree p2 = TYPE_ARG_TYPES (t2);
        int len;
@@ -468,7 +358,7 @@ common_type (tree t1, tree t2)
                      goto parm_done;
                    }
              }
-           TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2));
+           TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
          parm_done: ;
          }
 
@@ -482,6 +372,182 @@ common_type (tree t1, tree t2)
     }
 
 }
+
+/* Return the type of a conditional expression between pointers to
+   possibly differently qualified versions of compatible types.
+
+   We assume that comp_target_types has already been done and returned
+   nonzero; if that isn't so, this may crash.  */
+
+static tree
+common_pointer_type (tree t1, tree t2)
+{
+  tree attributes;
+  tree pointed_to_1;
+  tree pointed_to_2;
+  tree target;
+
+  /* Save time if the two types are the same.  */
+
+  if (t1 == t2) return t1;
+
+  /* If one type is nonsense, use the other.  */
+  if (t1 == error_mark_node)
+    return t2;
+  if (t2 == error_mark_node)
+    return t1;
+
+  if (TREE_CODE (t1) != POINTER_TYPE || TREE_CODE (t2) != POINTER_TYPE)
+    abort ();
+
+  /* Merge the attributes.  */
+  attributes = targetm.merge_type_attributes (t1, t2);
+
+  /* Find the composite type of the target types, and combine the
+     qualifiers of the two types' targets.  */
+  pointed_to_1 = TREE_TYPE (t1);
+  pointed_to_2 = TREE_TYPE (t2);
+  target = composite_type (TYPE_MAIN_VARIANT (pointed_to_1),
+                          TYPE_MAIN_VARIANT (pointed_to_2));
+  t1 = build_pointer_type (c_build_qualified_type
+                          (target,
+                           TYPE_QUALS (pointed_to_1) |
+                           TYPE_QUALS (pointed_to_2)));
+  return build_type_attribute_variant (t1, attributes);
+}
+
+/* Return the common type for two arithmetic types under the usual
+   arithmetic conversions.  The default conversions have already been
+   applied, and enumerated types converted to their compatible integer
+   types.  The resulting type is unqualified and has no attributes.
+
+   This is the type for the result of most arithmetic operations
+   if the operands have the given two types.  */
+
+tree
+common_type (tree t1, tree t2)
+{
+  enum tree_code code1;
+  enum tree_code code2;
+
+  /* If one type is nonsense, use the other.  */
+  if (t1 == error_mark_node)
+    return t2;
+  if (t2 == error_mark_node)
+    return t1;
+
+  if (TYPE_QUALS (t1) != TYPE_UNQUALIFIED)
+    t1 = TYPE_MAIN_VARIANT (t1);
+
+  if (TYPE_QUALS (t2) != TYPE_UNQUALIFIED)
+    t2 = TYPE_MAIN_VARIANT (t2);
+
+  if (TYPE_ATTRIBUTES (t1) != NULL_TREE)
+    t1 = build_type_attribute_variant (t1, NULL_TREE);
+
+  if (TYPE_ATTRIBUTES (t2) != NULL_TREE)
+    t2 = build_type_attribute_variant (t2, NULL_TREE);
+
+  /* Save time if the two types are the same.  */
+
+  if (t1 == t2) return t1;
+
+  code1 = TREE_CODE (t1);
+  code2 = TREE_CODE (t2);
+
+  if (code1 != VECTOR_TYPE && code1 != COMPLEX_TYPE
+      && code1 != REAL_TYPE && code1 != INTEGER_TYPE)
+    abort ();
+
+  if (code2 != VECTOR_TYPE && code2 != COMPLEX_TYPE
+      && code2 != REAL_TYPE && code2 != INTEGER_TYPE)
+    abort ();
+
+  /* If one type is a vector type, return that type.  (How the usual
+     arithmetic conversions apply to the vector types extension is not
+     precisely specified.)  */
+  if (code1 == VECTOR_TYPE)
+    return t1;
+
+  if (code2 == VECTOR_TYPE)
+    return t2;
+
+  /* If one type is complex, form the common type of the non-complex
+     components, then make that complex.  Use T1 or T2 if it is the
+     required type.  */
+  if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+    {
+      tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
+      tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+      tree subtype = common_type (subtype1, subtype2);
+
+      if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+       return t1;
+      else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+       return t2;
+      else
+       return build_complex_type (subtype);
+    }
+
+  /* If only one is real, use it as the result.  */
+
+  if (code1 == REAL_TYPE && code2 != REAL_TYPE)
+    return t1;
+
+  if (code2 == REAL_TYPE && code1 != REAL_TYPE)
+    return t2;
+
+  /* Both real or both integers; use the one with greater precision.  */
+
+  if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
+    return t1;
+  else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
+    return t2;
+
+  /* Same precision.  Prefer long longs to longs to ints when the
+     same precision, following the C99 rules on integer type rank
+     (which are equivalent to the C90 rules for C90 types).  */
+
+  if (TYPE_MAIN_VARIANT (t1) == long_long_unsigned_type_node
+      || TYPE_MAIN_VARIANT (t2) == long_long_unsigned_type_node)
+    return long_long_unsigned_type_node;
+
+  if (TYPE_MAIN_VARIANT (t1) == long_long_integer_type_node
+      || TYPE_MAIN_VARIANT (t2) == long_long_integer_type_node)
+    {
+      if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
+       return long_long_unsigned_type_node;
+      else
+        return long_long_integer_type_node;
+    }
+
+  if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
+      || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
+    return long_unsigned_type_node;
+
+  if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
+      || TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
+    {
+      /* But preserve unsignedness from the other type,
+        since long cannot hold all the values of an unsigned int.  */
+      if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
+       return long_unsigned_type_node;
+      else
+       return long_integer_type_node;
+    }
+
+  /* Likewise, prefer long double to double even if same size.  */
+  if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
+      || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
+    return long_double_type_node;
+
+  /* Otherwise prefer the unsigned one.  */
+
+  if (TYPE_UNSIGNED (t1))
+    return t1;
+  else
+    return t2;
+}
 \f
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
    or various other operations.  Return 2 if they are compatible
@@ -2760,7 +2826,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
   else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
     {
       if (comp_target_types (type1, type2, 1))
-       result_type = common_type (type1, type2);
+       result_type = common_pointer_type (type1, type2);
       else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
               && TREE_CODE (orig_op1) != NOP_EXPR)
        result_type = qualify_type (type2, type1);
@@ -6704,7 +6770,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
             Otherwise, the targets must be compatible
             and both must be object or both incomplete.  */
          if (comp_target_types (type0, type1, 1))
-           result_type = common_type (type0, type1);
+           result_type = common_pointer_type (type0, type1);
          else if (VOID_TYPE_P (tt0))
            {
              /* op0 != orig_op0 detects the case of something
@@ -6752,7 +6818,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        {
          if (comp_target_types (type0, type1, 1))
            {
-             result_type = common_type (type0, type1);
+             result_type = common_pointer_type (type0, type1);
              if (pedantic
                  && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
                pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
@@ -6777,7 +6843,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        {
          if (comp_target_types (type0, type1, 1))
            {
-             result_type = common_type (type0, type1);
+             result_type = common_pointer_type (type0, type1);
              if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
                  != !COMPLETE_TYPE_P (TREE_TYPE (type1)))
                pedwarn ("comparison of complete and incomplete pointers");
index 197242d..17871dd 100644 (file)
@@ -1,3 +1,8 @@
+2004-06-06  Joseph S. Myers  <jsm@polyomino.org.uk>
+
+       PR c/13519
+       * gcc.c-torture/enum-3.c, gcc.dg/pr13519-1.c: New tests.
+
 2004-06-06  Giovanni Bajo  <giovannibajo@gcc.gnu.org>
 
        PR c++/15503
diff --git a/gcc/testsuite/gcc.c-torture/execute/enum-3.c b/gcc/testsuite/gcc.c-torture/execute/enum-3.c
new file mode 100644 (file)
index 0000000..f57bc7f
--- /dev/null
@@ -0,0 +1,24 @@
+/* The composite type of int and an enum compatible with int might be
+   either of the two types, but it isn't an unsigned type.  */
+/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
+
+#include <limits.h>
+
+#include <stdio.h>
+
+extern void abort (void);
+extern void exit (int);
+
+enum e { a = INT_MIN };
+
+int *p;
+enum e *q;
+int
+main (void)
+{
+  enum e x = a;
+  q = &x;
+  if (*(1 ? q : p) > 0)
+    abort ();
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/pr13519-1.c b/gcc/testsuite/gcc.dg/pr13519-1.c
new file mode 100644 (file)
index 0000000..907165f
--- /dev/null
@@ -0,0 +1,47 @@
+/* typeof applied to const+nonconst should be nonconst, as should
+   typeof applied to other arithmetic expressions.  Bug 13519.  */
+/* Origin: Debian bug report 208981
+   from Kalle Olavi Niemitalo <kon@iki.fi>, adapted to a testcase by
+   Joseph Myers <jsm@polyomino.org.uk>.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void fn(void)
+{
+  int n;
+  const int c;
+
+  { __typeof__(n) a1; a1=0; }
+  { __typeof__(c) a2; a2=0; } /* { dg-error "read-only" "correct error" } */
+  { __typeof__((int)n) a3; a3=0; }
+  { __typeof__((int)c) a4; a4=0; } /* { dg-bogus "read-only" "bogus error" { xfail *-*-* } } */
+  { __typeof__((const int)n) a5; a5=0; } /* { dg-error "read-only" "correct error" { xfail *-*-* } } */
+  { __typeof__((const int)c) a6; a6=0; } /* { dg-error "read-only" "correct error" } */
+  { __typeof__(0) a7; a7=0; }
+  { __typeof__(1) a8; a8=0; }
+
+  { __typeof__(n+n) b0; b0=0; }
+  { __typeof__(n+c) b1; b1=0; }
+  { __typeof__(c+n) b2; b2=0; }
+  { __typeof__(c+c) b3; b3=0; }
+
+  { __typeof__(0+n) c0; c0=0; }
+  { __typeof__(0+c) c1; c1=0; }
+  { __typeof__(n+0) c2; c2=0; }
+  { __typeof__(c+0) c3; c3=0; }
+
+  { __typeof__(1+n) d0; d0=0; }
+  { __typeof__(1+c) d1; d1=0; }
+  { __typeof__(n+1) d2; d2=0; }
+  { __typeof__(c+1) d3; d3=0; }
+
+  { __typeof__(((int)n)+((int)n)) e0; e0=0; }
+  { __typeof__(((int)n)+((int)c)) e1; e1=0; }
+  { __typeof__(((int)c)+((int)n)) e2; e2=0; }
+  { __typeof__(((int)c)+((int)c)) e3; e3=0; }
+
+  { __typeof__(((const int)n)+((const int)n)) f0; f0=0; }
+  { __typeof__(((const int)n)+((const int)c)) f1; f1=0; }
+  { __typeof__(((const int)c)+((const int)n)) f2; f2=0; }
+  { __typeof__(((const int)c)+((const int)c)) f3; f3=0; }
+}