This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix duplicate_decl bug
- From: Jakub Jelinek <jakub at redhat dot com>
- To: jason at redhat dot com
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 25 Jan 2002 12:01:34 +0100
- Subject: [C++ PATCH] Fix duplicate_decl bug
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
The following testcase causes an error on valid code.
It started appearing after
http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01393.html
which stopped using TYPE_MAIN_VARIANT for array elements.
Now, duplicate_decls uses common_type when the types aren't identical
(in this case one is <array_type <char>> and one <array_type <baz>>),
which unfortunately means that integer promotions are done and thus
finally foo array has int type.
E.g.
typedef char baz;
extern const char foo[];
const baz foo[] = { 1, 2, 3, '\0' };
is int array now too, not char array.
> "Jason" == Jason Merrill <jason@redhat.com> writes:
>
> > "Jakub" == Jakub Jelinek <jakub@redhat.com> writes:
>
> > ATM I'm thinking of renaming common_type to say common_type_1,
> > add it a boolean argument whether integer promotions should be done or not
> > and make common_type a macro which will be common_type_1 (x, y, 0).
>
> Rather, it should be two separate functions. One to be used for converting
> expression operands to a common type, and another for merging function
> declarations. It makes no sense for these to be done by the same function.
Here is a patch which uses a separate function (merge_types) which doesn't
promote the types (dunno if there are other differences in type merging for
redeclaration against common_type).
Bootstrapped on i386-redhat-linux, no regressions.
2002-01-25 Jakub Jelinek <jakub@redhat.com>
* typeck.c (merge_arithmetic_types): Copied from
type_after_usual_arithmetic_conversions.
(type_after_usual_arithmetic_conversions): Call
merge_arithmetic_types.
(merge_types): New.
* cp-tree.h (merge_types): New prototype.
* decl.c (duplicate_types): Call merge_types instead of common_type.
* g++.dg/other/redecl1.C: New test.
--- gcc/cp/typeck.c.jj Thu Jan 24 23:37:32 2002
+++ gcc/cp/typeck.c Fri Jan 25 13:13:27 2002
@@ -51,6 +51,7 @@ static int comp_target_parms PARAMS ((tr
static int comp_ptr_ttypes_real PARAMS ((tree, tree, int));
static int comp_ptr_ttypes_const PARAMS ((tree, tree));
static int comp_ptr_ttypes_reinterpret PARAMS ((tree, tree));
+static tree merge_arithmetic_types PARAMS ((tree, tree, tree));
static int comp_except_types PARAMS ((tree, tree, int));
static int comp_array_types PARAMS ((int (*) (tree, tree, int), tree,
tree, int));
@@ -315,43 +316,15 @@ original_type (t)
return t;
}
-/* T1 and T2 are arithmetic or enumeration types. Return the type
- that will result from the "usual arithmetic conversions" on T1 and
- T2 as described in [expr]. */
+/* T1 and T2 are arithmetic or enumeration types. Return the common
+ type without doing any arithmetic promotions. */
-tree
-type_after_usual_arithmetic_conversions (t1, t2)
- tree t1;
- tree t2;
+static tree
+merge_arithmetic_types (t1, t2, attributes)
+ tree t1, t2, attributes;
{
enum tree_code code1 = TREE_CODE (t1);
enum tree_code code2 = TREE_CODE (t2);
- tree attributes;
-
- /* FIXME: Attributes. */
- my_friendly_assert (ARITHMETIC_TYPE_P (t1)
- || TREE_CODE (t1) == ENUMERAL_TYPE,
- 19990725);
- my_friendly_assert (ARITHMETIC_TYPE_P (t2)
- || TREE_CODE (t2) == ENUMERAL_TYPE,
- 19990725);
-
- /* In what follows, we slightly generalize the rules given in [expr]
- so as to deal with `long long'. First, merge the attributes. */
- attributes = (*targetm.merge_type_attributes) (t1, t2);
-
- /* 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);
-
- /* Perform the integral promotions. */
- if (code1 != REAL_TYPE)
- {
- t1 = type_promotes_to (t1);
- t2 = type_promotes_to (t2);
- }
/* Both real or both integers; use the one with greater precision. */
if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
@@ -426,6 +399,47 @@ type_after_usual_arithmetic_conversions
}
}
+/* T1 and T2 are arithmetic or enumeration types. Return the type
+ that will result from the "usual arithmetic conversions" on T1 and
+ T2 as described in [expr]. */
+
+tree
+type_after_usual_arithmetic_conversions (t1, t2)
+ tree t1;
+ tree t2;
+{
+ enum tree_code code1 = TREE_CODE (t1);
+ enum tree_code code2 = TREE_CODE (t2);
+ tree attributes;
+
+ /* FIXME: Attributes. */
+ my_friendly_assert (ARITHMETIC_TYPE_P (t1)
+ || TREE_CODE (t1) == ENUMERAL_TYPE,
+ 19990725);
+ my_friendly_assert (ARITHMETIC_TYPE_P (t2)
+ || TREE_CODE (t2) == ENUMERAL_TYPE,
+ 19990725);
+
+ /* In what follows, we slightly generalize the rules given in [expr]
+ so as to deal with `long long'. First, merge the attributes. */
+ attributes = (*targetm.merge_type_attributes) (t1, t2);
+
+ /* 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);
+
+ /* Perform the integral promotions. */
+ if (code1 != REAL_TYPE)
+ {
+ t1 = type_promotes_to (t1);
+ t2 = type_promotes_to (t2);
+ }
+
+ return merge_arithmetic_types (t1, t2, attributes);
+}
+
/* Return the composite pointer type (see [expr.rel]) for T1 and T2.
ARG1 and ARG2 are the values with those types. The LOCATION is a
string describing the current location, in case an error occurs. */
@@ -756,6 +770,264 @@ common_type (t1, t2)
return build_type_attribute_variant (t1, attributes);
+ case OFFSET_TYPE:
+ /* Pointers to members should now be handled by the POINTER_TYPE
+ case above. */
+ abort ();
+
+ default:
+ return build_type_attribute_variant (t1, attributes);
+ }
+}
+
+/* Return the resulting type for redeclaration.
+ We assume that comptypes has already been done and returned 1;
+ if that isn't so, this may crash. */
+
+tree
+merge_types (t1, t2)
+ tree t1, t2;
+{
+ register enum tree_code code1;
+ register enum tree_code code2;
+ tree attributes;
+
+ /* Save time if the two types are the same. */
+ if (t1 == t2)
+ return t1;
+ t1 = original_type (t1);
+ t2 = original_type (t2);
+ 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;
+
+ /* Merge the attributes. */
+ attributes = (*targetm.merge_type_attributes) (t1, t2);
+
+ if ((ARITHMETIC_TYPE_P (t1) || TREE_CODE (t1) == ENUMERAL_TYPE)
+ && (ARITHMETIC_TYPE_P (t2) || TREE_CODE (t2) == ENUMERAL_TYPE))
+ {
+ if (TREE_CODE (t1) == REAL_TYPE && TREE_CODE (t2) != REAL_TYPE)
+ abort ();
+ if (TREE_CODE (t2) == REAL_TYPE && TREE_CODE (t1) != REAL_TYPE)
+ abort ();
+ return merge_arithmetic_types (t1, t2, attributes);
+ }
+
+ /* Treat an enum type as the unsigned integer type of the same width. */
+
+ if (TREE_CODE (t1) == ENUMERAL_TYPE)
+ t1 = type_for_size (TYPE_PRECISION (t1), 1);
+ if (TREE_CODE (t2) == ENUMERAL_TYPE)
+ t2 = type_for_size (TYPE_PRECISION (t2), 1);
+
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
+ code1 = TREE_CODE (t1);
+ code2 = TREE_CODE (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 = merge_types (subtype1, subtype2);
+
+ 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);
+ }
+
+ switch (code1)
+ {
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ /* We should have called merge_arithmetic_types above. */
+ abort ();
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_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 ISO C++ specifies doing this with the qualifiers.
+ So I turned it on again. */
+ {
+ tree tt1 = TREE_TYPE (t1);
+ tree tt2 = TREE_TYPE (t2);
+ tree b1, b2;
+ int type_quals;
+ tree target;
+
+ if (TREE_CODE (tt1) == OFFSET_TYPE)
+ {
+ b1 = TYPE_OFFSET_BASETYPE (tt1);
+ b2 = TYPE_OFFSET_BASETYPE (tt2);
+ tt1 = TREE_TYPE (tt1);
+ tt2 = TREE_TYPE (tt2);
+ }
+ else
+ b1 = b2 = NULL_TREE;
+
+ type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
+ tt1 = TYPE_MAIN_VARIANT (tt1);
+ tt2 = TYPE_MAIN_VARIANT (tt2);
+
+ if (tt1 == tt2)
+ target = tt1;
+ else if (VOID_TYPE_P (tt1) || VOID_TYPE_P (tt2))
+ target = void_type_node;
+ else if (tt1 == unknown_type_node)
+ target = tt2;
+ else if (tt2 == unknown_type_node)
+ target = tt1;
+ else
+ target = merge_types (tt1, tt2);
+
+ target = cp_build_qualified_type (target, type_quals);
+
+ if (b1)
+ {
+ if (same_type_p (b1, b2)
+ || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
+ target = build_offset_type (b2, target);
+ else if (binfo_or_else (b2, b1))
+ target = build_offset_type (b1, target);
+ }
+
+ if (code1 == POINTER_TYPE)
+ t1 = build_pointer_type (target);
+ else
+ t1 = build_reference_type (target);
+ t1 = build_type_attribute_variant (t1, attributes);
+
+ if (TREE_CODE (target) == METHOD_TYPE)
+ t1 = build_ptrmemfunc_type (t1);
+
+ return t1;
+ }
+
+ case ARRAY_TYPE:
+ {
+ tree elt = merge_types (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);
+ if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
+ return build_type_attribute_variant (t2, attributes);
+ /* Merge the element types, and have a size if either arg has one. */
+ t1 = build_cplus_array_type
+ (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ return build_type_attribute_variant (t1, attributes);
+ }
+
+ case FUNCTION_TYPE:
+ /* Function types: prefer the one that specified arg types.
+ If both do, merge the arg types. Also merge the return types. */
+ {
+ tree valtype = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
+ tree p1 = TYPE_ARG_TYPES (t1);
+ tree p2 = TYPE_ARG_TYPES (t2);
+ tree rval, raises;
+
+ /* Save space: see if the result is identical to one of the args. */
+ if (valtype == TREE_TYPE (t1) && ! p2)
+ return build_type_attribute_variant (t1, attributes);
+ if (valtype == TREE_TYPE (t2) && ! p1)
+ return build_type_attribute_variant (t2, attributes);
+
+ /* Simple way if one arg fails to specify argument types. */
+ if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node)
+ {
+ rval = build_function_type (valtype, p2);
+ if ((raises = TYPE_RAISES_EXCEPTIONS (t2)))
+ rval = build_exception_variant (rval, raises);
+ return build_type_attribute_variant (rval, attributes);
+ }
+ raises = TYPE_RAISES_EXCEPTIONS (t1);
+ if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
+ {
+ rval = build_function_type (valtype, p1);
+ if (raises)
+ rval = build_exception_variant (rval, raises);
+ return build_type_attribute_variant (rval, attributes);
+ }
+
+ rval = build_function_type (valtype, commonparms (p1, p2));
+ rval = build_exception_variant (rval, raises);
+ return build_type_attribute_variant (rval, attributes);
+ }
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ t1 = TYPE_MAIN_VARIANT (t1);
+ t2 = TYPE_MAIN_VARIANT (t2);
+
+ if (DERIVED_FROM_P (t1, t2) && binfo_or_else (t1, t2))
+ return build_type_attribute_variant (t1, attributes);
+ else if (binfo_or_else (t2, t1))
+ return build_type_attribute_variant (t2, attributes);
+ else
+ {
+ compiler_error ("merge_types called with uncommon aggregate types");
+ return error_mark_node;
+ }
+
+ case METHOD_TYPE:
+ if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+ {
+ /* Get this value the long way, since TYPE_METHOD_BASETYPE
+ is just the main variant of this. */
+ tree basetype;
+ tree raises, t3;
+
+ tree b1 = TYPE_OFFSET_BASETYPE (t1);
+ tree b2 = TYPE_OFFSET_BASETYPE (t2);
+
+ if (same_type_p (b1, b2)
+ || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
+ basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
+ else
+ {
+ if (binfo_or_else (b2, b1) == NULL_TREE)
+ compiler_error ("merge_types called with uncommon method types");
+ basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
+ }
+
+ raises = TYPE_RAISES_EXCEPTIONS (t1);
+
+ /* If this was a member function type, get back to the
+ original type of type member function (i.e., without
+ the class instance variable up front. */
+ t1 = build_function_type (TREE_TYPE (t1),
+ TREE_CHAIN (TYPE_ARG_TYPES (t1)));
+ t2 = build_function_type (TREE_TYPE (t2),
+ TREE_CHAIN (TYPE_ARG_TYPES (t2)));
+ t3 = merge_types (t1, t2);
+ t3 = build_cplus_method_type (basetype, TREE_TYPE (t3),
+ TYPE_ARG_TYPES (t3));
+ t1 = build_exception_variant (t3, raises);
+ }
+ else
+ compiler_error ("merge_types called with uncommon method types");
+
+ return build_type_attribute_variant (t1, attributes);
+
case OFFSET_TYPE:
/* Pointers to members should now be handled by the POINTER_TYPE
case above. */
--- gcc/cp/cp-tree.h.jj Thu Jan 24 23:37:31 2002
+++ gcc/cp/cp-tree.h Fri Jan 25 00:01:57 2002
@@ -4289,6 +4289,7 @@ extern tree require_complete_type PARAM
extern tree complete_type PARAMS ((tree));
extern tree complete_type_or_else PARAMS ((tree, tree));
extern int type_unknown_p PARAMS ((tree));
+extern tree merge_types PARAMS ((tree, tree));
extern tree commonparms PARAMS ((tree, tree));
extern tree original_type PARAMS ((tree));
extern int comp_except_specs PARAMS ((tree, tree, int));
--- gcc/cp/decl.c.jj Thu Jan 24 23:37:31 2002
+++ gcc/cp/decl.c Fri Jan 25 00:02:25 2002
@@ -3526,7 +3526,7 @@ duplicate_decls (newdecl, olddecl)
tree newtype;
/* Merge the data types specified in the two decls. */
- newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+ newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
/* If common_type produces a non-typedef type, just use the old type. */
if (TREE_CODE (newdecl) == TYPE_DECL
--- gcc/testsuite/g++.dg/other/redecl1.C.jj Fri Jan 25 00:19:22 2002
+++ gcc/testsuite/g++.dg/other/redecl1.C Fri Jan 25 00:23:33 2002
@@ -0,0 +1,7 @@
+// This testcase failed because during duplicate_decls the type was promoted
+// to int.
+// { dg-do compile }
+typedef char baz;
+extern const char foo[];
+const baz foo[] = "xyz";
+const char bar[] = "abc";
Jakub