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]

Problems with PR 21210


PR 21210 is a complaint that G++ 4.0 has stopped allowing conversions
from integers to "__complex__ float".  This is a perfectly reasonable
complaint, as in C99 such conversions are permitted, so if we are
going to support __complex__ in C++ we should have the same semantics.
Besides the breakage noted in the PR, other things that do not work --
but should -- are pseudo-destrutors for __complex__ types and implicit
conversions from __complex__ types to their real-subparts, as these
conversions are permitted in C99.
  
The right fix, from a C++ language point of view, is to treat
conversions to __complex__ types from other types as standard
conversions, if the conversion could be made to the type used for the
components of the complex type.  Furthermore, __complex__ types should
be treated as "arithmetic" types.

All that works just fine -- except that we run into problems with:

  complex<double> d(3);

The libstdc++ std::complex templates contain a non-standard
constructor:

      complex(__complex__ double);

in addition to the standard:

      complex(double = 0.0, double = 0.0);

So, we get an overload ambiguity; converting to double is no better
than converting to __complex__ double.

I really don't like the idea of creating a new class of conversions
that is worse than a standard conversion, but better than a
user-defined conversion, for interactions with complex types.  From a
language-design point of view, we really should be treating
__complex__ types as an "arithmetic" type.

Removing the extra libstdc++ constructor is not ideal, because then
__complex__ double can still be converted to complex<double> -- but
the conversion happens via the implicit conversion from __complex__
double to double, so the imaginary part of the value is lost.

So, I think that what we should do is add constructors.  For example,
for double, we would add:

  complex(int);
  complex(long);
  complex(long long):
  complex(unsigned int);
  complex(unsigned long);
  complex(unsigned long long);
  complex(long double);

(We don't need bool, char, short, or float because they will promote
to one of the other types, and promotions are better conversions than
standard conversions, so there's no ambiguity.)

I can't see how adding these constructors will break anything,
relative to the standard, in that all of these conversions were
already permitted, but it's definitely possible I'm overlooking
something.

I've attached the draft patch I've been using for the front end, but
before I start making library changes I'd like to get some buy-in from
the V3 deveopers.

Thoughts?

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

Index: gcc/cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.537
diff -c -5 -p -r1.537 call.c
*** gcc/cp/call.c	27 May 2005 23:17:05 -0000	1.537
--- gcc/cp/call.c	29 May 2005 19:24:02 -0000
*************** standard_conversion (tree to, tree from,
*** 628,648 ****
    if (tcode == COMPLEX_TYPE && fcode == COMPLEX_TYPE)
      {
        /* The standard conversion sequence to convert FROM to TO is
           the standard conversion sequence to perform componentwise
           conversion.  */
!       conversion *part_conv = standard_conversion
!         (TREE_TYPE (to), TREE_TYPE (from), NULL_TREE, flags);
!       
!       if (part_conv)
!         {
! 	  conv = build_conv (part_conv->kind, to, conv);
! 	  conv->rank = part_conv->rank;
!         }
!       else
!         conv = NULL;
! 
        return conv;
      }
  
    if (same_type_p (from, to))
      return conv;
--- 628,641 ----
    if (tcode == COMPLEX_TYPE && fcode == COMPLEX_TYPE)
      {
        /* The standard conversion sequence to convert FROM to TO is
           the standard conversion sequence to perform componentwise
           conversion.  */
!       conv = standard_conversion (TREE_TYPE (to), TREE_TYPE (from), 
! 				  NULL_TREE, flags);
!       if (conv)
! 	conv->type = to;
        return conv;
      }
  
    if (same_type_p (from, to))
      return conv;
*************** standard_conversion (tree to, tree from,
*** 799,817 ****
    /* We don't check for ENUMERAL_TYPE here because there are no standard
       conversions to enum type.  */
    else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
  	   || tcode == REAL_TYPE)
      {
!       if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
! 	return 0;
        conv = build_conv (ck_std, to, conv);
  
        /* Give this a better rank if it's a promotion.  */
        if (same_type_p (to, type_promotes_to (from))
  	  && conv->u.next->rank <= cr_promotion)
  	conv->rank = cr_promotion;
      }
    else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
  	   && vector_types_convertible_p (from, to))
      return build_conv (ck_std, to, conv);
    else if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE)
  	   && IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
--- 792,832 ----
    /* We don't check for ENUMERAL_TYPE here because there are no standard
       conversions to enum type.  */
    else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
  	   || tcode == REAL_TYPE)
      {
!       if (!ARITHMETIC_TYPE_P (from) && fcode != ENUMERAL_TYPE)
! 	return NULL;
        conv = build_conv (ck_std, to, conv);
  
        /* Give this a better rank if it's a promotion.  */
        if (same_type_p (to, type_promotes_to (from))
  	  && conv->u.next->rank <= cr_promotion)
  	conv->rank = cr_promotion;
      }
+   else if (tcode == COMPLEX_TYPE)
+     {
+       /* Complex types are a GNU extension.  Permit conversions to
+ 	 complex types iff conversions to the corresponding scalar
+ 	 type are permitted.  The semantics of such a conversion is
+ 	 that the imaginary type of the result is implicitly zero.  */
+       conv = standard_conversion (TREE_TYPE (to), from, expr, flags);
+       if (conv)
+ 	{
+ 	  /* The conversion is never better than a standard
+ 	     conversion.  */
+ 	  if (!conv->bad_p)
+ 	    {
+ 	      if (conv->kind == ck_identity)
+ 		conv->kind = ck_std;
+ 	      if (conv->rank < cr_std)
+ 		conv->rank = cr_std;
+ 	    }
+ 	  conv->type = to;
+ 	}
+       return conv;
+     }
    else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
  	   && vector_types_convertible_p (from, to))
      return build_conv (ck_std, to, conv);
    else if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE)
  	   && IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1139
diff -c -5 -p -r1.1139 cp-tree.h
*** gcc/cp/cp-tree.h	28 May 2005 01:38:10 -0000	1.1139
--- gcc/cp/cp-tree.h	29 May 2005 19:24:02 -0000
*************** struct lang_decl GTY(())
*** 2344,2356 ****
     (TREE_CODE (TYPE) == ENUMERAL_TYPE || CP_INTEGRAL_TYPE_P (TYPE))
  
  /* [basic.fundamental]
  
     Integral and floating types are collectively called arithmetic
!    types.  Keep these checks in ascending code order.  */
! #define ARITHMETIC_TYPE_P(TYPE) \
!   (CP_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == REAL_TYPE)
  
  /* [basic.types]
  
     Arithmetic types, enumeration types, pointer types, and
     pointer-to-member types, are collectively called scalar types.
--- 2344,2362 ----
     (TREE_CODE (TYPE) == ENUMERAL_TYPE || CP_INTEGRAL_TYPE_P (TYPE))
  
  /* [basic.fundamental]
  
     Integral and floating types are collectively called arithmetic
!    types.  
! 
!    As a GNU extension, we also include COMPLEX_TYPEs.
! 
!    Keep these checks in ascending code order.  */
! #define ARITHMETIC_TYPE_P(TYPE)			\
!   (CP_INTEGRAL_TYPE_P (TYPE)			\
!    || TREE_CODE (TYPE) == REAL_TYPE		\
!    || TREE_CODE (TYPE) == COMPLEX_TYPE)
  
  /* [basic.types]
  
     Arithmetic types, enumeration types, pointer types, and
     pointer-to-member types, are collectively called scalar types.
Index: gcc/cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.632
diff -c -5 -p -r1.632 typeck.c
*** gcc/cp/typeck.c	28 May 2005 02:21:29 -0000	1.632
--- gcc/cp/typeck.c	29 May 2005 19:24:02 -0000
*************** common_type (tree t1, tree t2)
*** 732,745 ****
      return error_mark_node;
  
    code1 = TREE_CODE (t1);
    code2 = TREE_CODE (t2);
  
!   if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE
!        || code1 == COMPLEX_TYPE)
!       && (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE
! 	  || code2 == COMPLEX_TYPE))
      return type_after_usual_arithmetic_conversions (t1, t2);
  
    else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
  	   || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
  	   || (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)))
--- 732,743 ----
      return error_mark_node;
  
    code1 = TREE_CODE (t1);
    code2 = TREE_CODE (t2);
  
!   if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE)
!       && (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE))
      return type_after_usual_arithmetic_conversions (t1, t2);
  
    else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
  	   || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
  	   || (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)))
Index: gcc/testsuite/g++.dg/ext/complex1.C
===================================================================
RCS file: gcc/testsuite/g++.dg/ext/complex1.C
diff -N gcc/testsuite/g++.dg/ext/complex1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/ext/complex1.C	29 May 2005 19:24:02 -0000
***************
*** 0 ****
--- 1,4 ----
+ // PR c++/21210
+ 
+ typedef float __complex__ fcomplex;
+ fcomplex cplx = fcomplex();


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