aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/c-decl.c2
-rw-r--r--gcc/c-tree.h1
-rw-r--r--gcc/c-typeck.c342
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/enum-3.c24
-rw-r--r--gcc/testsuite/gcc.dg/pr13519-1.c47
7 files changed, 295 insertions, 139 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cca009ba..f3f622e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 3a13664..ee09afa 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -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))
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index 9e21b4f..e698c87 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -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);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index cf01aa5..bdbb58b 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -199,19 +199,14 @@ qualify_type (tree type, tree like)
TYPE_QUALS (type) | TYPE_QUALS (like));
}
-/* 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;
+}
/* 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");
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 197242d2..17871dd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..f57bc7f
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/enum-3.c
@@ -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
index 0000000..907165f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr13519-1.c
@@ -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; }
+}