This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] Fix duplicate_decl bug


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]