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]

Re: (c++) enum bitfield + template operator problem



Mumit --

  It turns out that this bug has actually been reported several times
before.  But, now it's fixed, so hopefully we won't see this anymore!

  I took advantage of the fact I was rooting around in the
reference-binding code to clean up some other issues inolving
reference binding as well; we now behave consistently whether there is
only a single function candidate, or several, and generate implicit
conversion sequences that are closer to what the standard requires.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-07-22  Mark Mitchell  <mark@codesourcery.com>

	* call.c (NEED_TEMPORARY_P): New macro.
	(standard_conversion): Set it, for derived-to-base conversions.
	(reference_related_p): New function.
	(reference_compatible_p): Likewise.
	(convert_class_to_reference): Likewise.
	(direct_reference_binding): Likewise.
	(reference_binding): Rework for standards-compliance.
	(convert_like): Adjust accordingly.
	(maybe_handle_ref_bind): Simplify; the right conversion sequences
	are now built up in reference_binding.
	(initialize_reference): New function.
	* cp-tree.h (ICS_USER_FLAG): Document.
	(ICS_THIS_FLAG): Likewise.
	(ICS_BAD_FLAG): Likewise.
	(NEED_TEMPORARY_P): Likewise.
	(cp_lvalue_kind): New type.
	(real_lvalue_p): Return it.
	* error.c (dump_expr): Provide more accurate representation for
	AGGR_INIT_EXPRs.
	* init.c (expand_default_init): Do not try to perform implicit
	conversions for a brace-enclosed initializer.
	* search.c (lookup_conversions): Document.
	* tree.c (lvalue_p_1): Return a cp_lvalue_kind.  Calculate
	appropriately.
	(real_lvalue_p): Adjust accordingly.
	(lvalue_p): Likewise.
	(build_cplus_new): Don't allow the creation of an abstract class.
	* typeck.c (convert_for_initialization): Use initialize_reference.
	
Index: testsuite/g++.old-deja/g++.other/bitfld1.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.other/bitfld1.C,v
retrieving revision 1.3
diff -u -p -r1.3 bitfld1.C
--- bitfld1.C	1998/12/16 21:51:39	1.3
+++ bitfld1.C	1999/07/22 23:15:07
@@ -1,8 +1,6 @@
 // Build don't link:
 // Based on a bug report by Stephen Vavasis <vavasis@CS.Cornell.EDU>
 
-// excess errors test - XFAIL *-*-*
-
 // declares template operator!=
 #include <utility>
 
Index: testsuite/g++.old-deja/g++.robertl/eb76.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C,v
retrieving revision 1.7
diff -u -p -r1.7 eb76.C
--- eb76.C	1998/12/16 22:04:35	1.7
+++ eb76.C	1999/07/22 23:15:08
@@ -1,6 +1,5 @@
 //Build don't link:
 // the template operator!= interferes.  It should be in a namespace.
-// excess errors test - XFAIL *-*-*
 
 #include <utility>
 
Index: cp/call.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/call.c,v
retrieving revision 1.149
diff -u -p -r1.149 call.c
--- call.c	1999/06/16 11:24:08	1.149
+++ call.c	1999/07/22 23:15:23
@@ -92,6 +92,10 @@ static struct z_candidate * add_candidat
 						 tree, tree, int));
 static tree source_type PROTO((tree));
 static void add_warning PROTO((struct z_candidate *, struct z_candidate *));
+static int reference_related_p PROTO ((tree, tree));
+static int reference_compatible_p PROTO ((tree, tree));
+static tree convert_class_to_reference PROTO ((tree, tree, tree));
+static tree direct_reference_binding PROTO ((tree, tree));
 
 tree
 build_vfield_ref (datum, type)
@@ -534,6 +538,10 @@ struct z_candidate {
 #define ICS_THIS_FLAG(NODE) TREE_LANG_FLAG_2 (NODE)
 #define ICS_BAD_FLAG(NODE) TREE_LANG_FLAG_3 (NODE)
 
+/* In a REF_BIND or a BASE_CONV, this indicates that a temporary
+   should be created to hold the result of the conversion.  */
+#define NEED_TEMPORARY_P(NODE) (TREE_LANG_FLAG_4 ((NODE)))
+
 #define USER_CONV_CAND(NODE) \
   ((struct z_candidate *)WRAPPER_PTR (TREE_OPERAND (NODE, 1)))
 #define USER_CONV_FN(NODE) (USER_CONV_CAND (NODE)->fn)
@@ -767,6 +775,11 @@ standard_conversion (to, from, expr)
       if (TREE_CODE (conv) == RVALUE_CONV)
 	conv = TREE_OPERAND (conv, 0);
       conv = build_conv (BASE_CONV, to, conv);
+      /* The derived-to-base conversion indicates the initialization
+	 of a parameter with base type from an object of a derived
+	 type.  A temporary object is created to hold the result of
+	 the conversion.  */
+      NEED_TEMPORARY_P (conv) = 1;
     }
   else
     return 0;
@@ -774,6 +787,197 @@ standard_conversion (to, from, expr)
   return conv;
 }
 
+/* Returns non-zero if T1 is reference-related to T2.  */
+
+static int
+reference_related_p (t1, t2)
+     tree t1;
+     tree t2;
+{
+  t1 = TYPE_MAIN_VARIANT (t1);
+  t2 = TYPE_MAIN_VARIANT (t2);
+
+  /* [dcl.init.ref]
+
+     Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related
+     to "cv2 T2" if T1 is the same type as T2, or T1 is a base class
+     of T2.  */
+  return (same_type_p (t1, t2)
+	  || (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
+	      && DERIVED_FROM_P (t1, t2)));
+}
+
+/* Returns non-zero if T1 is reference-compatible with T2.  */
+
+static int
+reference_compatible_p (t1, t2)
+     tree t1;
+     tree t2;
+{
+  /* [dcl.init.ref]
+
+     "cv1 T1" is reference compatible with "cv2 T2" if T1 is
+     reference-related to T2 and cv1 is the same cv-qualification as,
+     or greater cv-qualification than, cv2.  */
+  return (reference_related_p (t1, t2)
+	  && at_least_as_qualified_p (t1, t2));
+}
+
+/* Determine whether or not the EXPR (of class type S) can be
+   converted to T as in [over.match.ref].  */
+
+static tree
+convert_class_to_reference (t, s, expr)
+     tree t;
+     tree s;
+     tree expr;
+{
+  tree conversions;
+  tree arglist;
+  tree conv;
+  struct z_candidate *candidates;
+  struct z_candidate *cand;
+
+  /* [over.match.ref]
+
+     Assuming that "cv1 T" is the underlying type of the reference
+     being initialized, and "cv S" is the type of the initializer
+     expression, with S a class type, the candidate functions are
+     selected as follows:
+
+     --The conversion functions of S and its base classes are
+       considered.  Those that are not hidden within S and yield type
+       "reference to cv2 T2", where "cv1 T" is reference-compatible
+       (_dcl.init.ref_) with "cv2 T2", are candidate functions.
+
+     The argument list has one argument, which is the initializer
+     expression.  */
+
+  candidates = 0;
+
+  /* Conceptually, we should take the address of EXPR and put it in
+     the argument list.  Unfortunately, however, that can result in
+     error messages, which we should not issue now because we are just
+     trying to find a conversion operator.  Therefore, we use NULL,
+     cast to the appropriate type.  */
+  arglist = build_int_2 (0, 0);
+  TREE_TYPE (arglist) = build_pointer_type (s);
+  arglist = build_scratch_list (NULL_TREE, arglist);
+  
+  for (conversions = lookup_conversions (s);
+       conversions;
+       conversions = TREE_CHAIN (conversions))
+    {
+      tree fns = TREE_VALUE (conversions);
+
+      while (fns)
+	{
+	  tree f = OVL_CURRENT (fns);
+	  tree t2 = TREE_TYPE (TREE_TYPE (f));
+	  struct z_candidate *old_candidates = candidates;
+
+	  /* If this is a template function, try to get an exact
+             match.  */
+	  if (TREE_CODE (f) == TEMPLATE_DECL)
+	    {
+	      candidates 
+		= add_template_candidate (candidates,
+					  f,
+					  NULL_TREE,
+					  arglist,
+					  build_reference_type (t),
+					  LOOKUP_NORMAL,
+					  DEDUCE_CONV);
+	      
+	      if (candidates != old_candidates)
+		{
+		  /* Now, see if the conversion function really returns
+		     an lvalue of the appropriate type.  From the
+		     point of view of unification, simply returning an
+		     rvalue of the right type is good enough.  */
+		  f = candidates->fn;
+		  t2 = TREE_TYPE (TREE_TYPE (f));
+		  if (TREE_CODE (t2) != REFERENCE_TYPE
+		      || !reference_compatible_p (t, TREE_TYPE (t2)))
+		    candidates = candidates->next;
+		}
+	    }
+	  else if (TREE_CODE (t2) == REFERENCE_TYPE
+		   && reference_compatible_p (t, TREE_TYPE (t2)))
+	    candidates 
+	      = add_function_candidate (candidates, f, arglist, 
+					LOOKUP_NORMAL);
+
+	  if (candidates != old_candidates)
+	    candidates->basetype_path = TREE_PURPOSE (conversions);
+
+	  fns = OVL_NEXT (fns);
+	}
+    }
+
+  /* If none of the conversion functions worked out, let our caller
+     know.  */
+  if (!any_viable (candidates))
+    return NULL_TREE;
+  
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates);
+  if (!cand)
+    return NULL_TREE;
+
+  conv = build_conv (IDENTITY_CONV, s, expr);
+  conv = build_conv (USER_CONV,
+		     non_reference (TREE_TYPE (TREE_TYPE (cand->fn))),
+		     expr);
+  TREE_OPERAND (conv, 1) = build_expr_ptr_wrapper (cand);
+  ICS_USER_FLAG (conv) = 1;
+  if (cand->viable == -1)
+    ICS_BAD_FLAG (conv) = 1;
+  cand->second_conv = conv;
+
+  return conv;
+}
+
+/* A reference of the indicated TYPE is being bound directly to the
+   expression represented by the implicit conversion sequence CONV.
+   Return a conversion sequence for this binding.  */
+
+static tree
+direct_reference_binding (type, conv)
+     tree type;
+     tree conv;
+{
+  tree t = TREE_TYPE (type);
+
+  /* [over.ics.rank] 
+     
+     When a parameter of reference type binds directly
+     (_dcl.init.ref_) to an argument expression, the implicit
+     conversion sequence is the identity conversion, unless the
+     argument expression has a type that is a derived class of the
+     parameter type, in which case the implicit conversion sequence is
+     a derived-to-base Conversion.
+	 
+     If the parameter binds directly to the result of applying a
+     conversion function to the argument expression, the implicit
+     conversion sequence is a user-defined conversion sequence
+     (_over.ics.user_), with the second standard conversion sequence
+     either an identity conversion or, if the conversion function
+     returns an entity of a type that is a derived class of the
+     parameter type, a derived-to-base conversion.  */
+  if (!same_type_p (TYPE_MAIN_VARIANT (t),
+		    TYPE_MAIN_VARIANT (TREE_TYPE (conv))))
+    {
+      /* Represent the derived-to-base conversion.  */
+      conv = build_conv (BASE_CONV, t, conv);
+      /* We will actually be binding to the base-class subobject in
+	 the derived class, so we mark this conversion appropriately.
+	 That way, convert_like knows not to generate a temporary.  */
+      NEED_TEMPORARY_P (conv) = 0;
+    }
+  return build_conv (REF_BIND, type, conv);
+}
+
 /* Returns the conversion path from type FROM to reference type TO for
    purposes of reference binding.  For lvalue binding, either pass a
    reference type to FROM or an lvalue expression to EXPR.
@@ -786,11 +990,12 @@ reference_binding (rto, rfrom, expr, fla
      tree rto, rfrom, expr;
      int flags;
 {
-  tree conv;
-  int lvalue = 1;
+  tree conv = NULL_TREE;
   tree to = TREE_TYPE (rto);
   tree from = rfrom;
-  int related;
+  int related_p;
+  int compatible_p;
+  cp_lvalue_kind lvalue_p = clk_none;
 
   if (TREE_CODE (to) == FUNCTION_TYPE && expr && type_unknown_p (expr))
     {
@@ -800,54 +1005,123 @@ reference_binding (rto, rfrom, expr, fla
       from = TREE_TYPE (expr);
     }
 
-  if (TREE_CODE (from) == REFERENCE_TYPE)
-    from = TREE_TYPE (from);
-  else if (! expr || ! real_lvalue_p (expr))
-    lvalue = 0;
-
-  related = (same_type_p (TYPE_MAIN_VARIANT (to),
-			  TYPE_MAIN_VARIANT (from))
-	     || (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
-		 && DERIVED_FROM_P (to, from)));
+  related_p = reference_related_p (to, from);
+  compatible_p = reference_compatible_p (to, from);
 
-  if (lvalue && related && at_least_as_qualified_p (to, from))
+  if (TREE_CODE (from) == REFERENCE_TYPE)
     {
-      conv = build1 (IDENTITY_CONV, from, expr);
-
-      if (same_type_p (TYPE_MAIN_VARIANT (to),
-		       TYPE_MAIN_VARIANT (from)))
-	conv = build_conv (REF_BIND, rto, conv);
-      else
-	{
-	  conv = build_conv (REF_BIND, rto, conv);
-	  ICS_STD_RANK (conv) = STD_RANK;
-	}
+      /* Anything with reference type is an lvalue.  */
+      lvalue_p = clk_ordinary;
+      from = TREE_TYPE (from);
     }
-  else
-    conv = NULL_TREE;
+  else if (expr)
+    lvalue_p = real_lvalue_p (expr);
 
-  if (! conv)
+  if (lvalue_p && compatible_p)
     {
-      conv = standard_conversion (to, rfrom, expr);
+      /* [dcl.init.ref]
+
+	 If the intializer expression 
+	 
+	 -- is an lvalue (but not an lvalue for a bit-field), and "cv1 T1"
+	    is reference-compatible with "cv2 T2,"
+	 
+	 the reference is bound directly to the initializer exprssion
+	 lvalue.  */
+      conv = build1 (IDENTITY_CONV, from, expr);
+      conv = direct_reference_binding (rto, conv);
+      if ((lvalue_p & clk_bitfield) != 0 
+	  && CP_TYPE_CONST_NON_VOLATILE_P (to))
+	/* For the purposes of overload resolution, we ignore the fact
+	   this expression is a bitfield. (In particular,
+	   [over.ics.ref] says specifically that a function with a
+	   non-const reference parameter is viable even if the
+	   argument is a bitfield.)
+
+	   However, when we actually call the function we must create
+	   a temporary to which to bind the reference.  If the
+	   reference is volatile, or isn't const, then we cannot make
+	   a temporary, so we just issue an error when the conversion
+	   actually occurs.  */
+	NEED_TEMPORARY_P (conv) = 1;
+      return conv;
+    }
+  else if (CLASS_TYPE_P (from) && !(flags & LOOKUP_NO_CONVERSION))
+    {
+      /* [dcl.init.ref]
+
+	 If the initializer exprsesion
+
+	 -- has a class type (i.e., T2 is a class type) can be
+	    implicitly converted to an lvalue of type "cv3 T3," where
+	    "cv1 T1" is reference-compatible with "cv3 T3".  (this
+	    conversion is selected by enumerating the applicable
+	    conversion functions (_over.match.ref_) and choosing the
+	    best one through overload resolution.  (_over.match_). 
+
+        the reference is bound to the lvalue result of the conversion
+	in the second case.  */
+      conv = convert_class_to_reference (to, from, expr);
       if (conv)
-	{
-	  conv = build_conv (REF_BIND, rto, conv);
+	return direct_reference_binding (rto, conv);
+    }
 
-	  /* Bind directly to a base subobject of a class rvalue.  Do it
-             after building the conversion for proper handling of ICS_RANK.  */
-	  if (TREE_CODE (TREE_OPERAND (conv, 0)) == BASE_CONV)
-	    TREE_OPERAND (conv, 0) = TREE_OPERAND (TREE_OPERAND (conv, 0), 0);
-	}
-      if (conv
-	  && ((! (CP_TYPE_CONST_NON_VOLATILE_P (to)
-		  && (flags & LOOKUP_NO_TEMP_BIND) == 0))
-	      /* If T1 is reference-related to T2, cv1 must be the same
-		 cv-qualification as, or greater cv-qualification than,
-		 cv2; otherwise, the program is ill-formed.  */
-	      || (related && !at_least_as_qualified_p (to, from))))
-	ICS_BAD_FLAG (conv) = 1;
+  /* [over.ics.rank]
+     
+     When a parameter of reference type is not bound directly to an
+     argument expression, the conversion sequence is the one required
+     to convert the argument expression to the underlying type of the
+     reference according to _over.best.ics_.  Conceptually, this
+     conversion sequence corresponds to copy-initializing a temporary
+     of the underlying type with the argument expression.  Any
+     difference in top-level cv-qualification is subsumed by the
+     initialization itself and does not constitute a conversion.  */
+
+  /* [dcl.init.ref]
+
+     Otherwise, the reference shall be to a non-volatile const type.  */
+  if (!CP_TYPE_CONST_NON_VOLATILE_P (to))
+    return NULL_TREE;
+
+  /* [dcl.init.ref]
+     
+     If the initializer expression is an rvalue, with T2 a class type,
+     and "cv1 T1" is reference-compatible with "cv2 T2", the reference
+     is bound in one of the following ways:
+     
+     -- The reference is bound to the object represented by the rvalue
+        or to a sub-object within that object.  
+
+     In this case, the implicit conversion sequence is supposed to be
+     same as we would obtain by generating a temporary.  Fortunately,
+     if the types are reference compatible, then this is either an
+     identity conversion or the derived-to-base conversion, just as
+     for direct binding.  */
+  if (CLASS_TYPE_P (from) && compatible_p)
+    {
+      conv = build1 (IDENTITY_CONV, from, expr);
+      return direct_reference_binding (rto, conv);
     }
 
+  /* [dcl.init.ref]
+
+     Otherwise, a temporary of type "cv1 T1" is created and
+     initialized from the initializer expression using the rules for a
+     non-reference copy initialization.  If T1 is reference-related to
+     T2, cv1 must be the same cv-qualification as, or greater
+     cv-qualification than, cv2; otherwise, the program is ill-formed.  */
+  if (related_p && !at_least_as_qualified_p (to, from))
+    return NULL_TREE;
+
+  conv = implicit_conversion (to, from, expr, flags);
+  if (!conv)
+    return NULL_TREE;
+
+  conv = build_conv (REF_BIND, rto, conv);
+  /* This reference binding, unlike those above, requires the
+     creation of a temporary.  */
+  NEED_TEMPORARY_P (conv) = 1;
+
   return conv;
 }
 
@@ -2885,7 +3159,8 @@ convert_like (convs, expr)
 {
   if (ICS_BAD_FLAG (convs)
       && TREE_CODE (convs) != USER_CONV
-      && TREE_CODE (convs) != AMBIG_CONV)
+      && TREE_CODE (convs) != AMBIG_CONV
+      && TREE_CODE (convs) != REF_BIND)
     {
       tree t = convs; 
       for (; t; t = TREE_OPERAND (t, 0))
@@ -2938,8 +3213,6 @@ convert_like (convs, expr)
     case IDENTITY_CONV:
       if (type_unknown_p (expr))
 	expr = instantiate_type (TREE_TYPE (convs), expr, 1);
-      if (TREE_READONLY_DECL_P (expr))
-	expr = decl_constant_value (expr);
       return expr;
     case AMBIG_CONV:
       /* Call build_user_type_conversion again for the error.  */
@@ -2954,6 +3227,12 @@ convert_like (convs, expr)
   if (expr == error_mark_node)
     return error_mark_node;
 
+  /* Convert a constant variable to its underlying value, unless we
+     are about to bind it to a reference, in which case we need to
+     leave it as an lvalue.  */
+  if (TREE_READONLY_DECL_P (expr) && TREE_CODE (convs) != REF_BIND)
+    expr = decl_constant_value (expr);
+
   switch (TREE_CODE (convs))
     {
     case RVALUE_CONV:
@@ -2961,6 +3240,12 @@ convert_like (convs, expr)
 	return expr;
       /* else fall through */
     case BASE_CONV:
+      if (TREE_CODE (convs) == BASE_CONV
+	  && !NEED_TEMPORARY_P (convs))
+	/* We are going to bind a reference directly to a base-class
+	   subobject of EXPR.  We don't have to generate any code
+	   here.  */
+	return expr;
       {
 	tree cvt_expr = build_user_type_conversion
 	  (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
@@ -2988,10 +3273,37 @@ convert_like (convs, expr)
       }
 
     case REF_BIND:
-      return convert_to_reference
-	(TREE_TYPE (convs), expr,
-	 CONV_IMPLICIT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
-	 error_mark_node);
+      {
+	tree ref_type = TREE_TYPE (convs);
+
+	/* If necessary, create a temporary.  */
+	if (NEED_TEMPORARY_P (convs))
+	  {
+	    tree type = TREE_TYPE (TREE_OPERAND (convs, 0));
+	    tree slot = build_decl (VAR_DECL, NULL_TREE, type);
+	    DECL_ARTIFICIAL (slot) = 1;
+	    expr = build (TARGET_EXPR, type, slot, expr,
+			  NULL_TREE, NULL_TREE);
+	    TREE_SIDE_EFFECTS (expr) = 1;
+	  }
+
+	/* Take the address of the thing to which we will bind the
+	   reference.  */
+	expr = build_unary_op (ADDR_EXPR, expr, 1);
+	if (expr == error_mark_node)
+	  return error_mark_node;
+
+	/* Convert it to a pointer to the type referred to by the
+	   reference.  This will adjust the pointer if a derived to
+	   base conversion is being performed.  */
+	expr = cp_convert (build_pointer_type (TREE_TYPE (ref_type)), 
+			   expr);
+	/* Convert the pointer to the desired reference type.  */
+	expr = build1 (NOP_EXPR, ref_type, expr);
+
+	return expr;
+      }
+
     case LVALUE_CONV:
       return decay_conversion (expr);
 
@@ -3687,43 +3999,8 @@ maybe_handle_ref_bind (ics, target_type)
 {
   if (TREE_CODE (*ics) == REF_BIND)
     {
-      /* [over.ics.rank] 
-	 
-	 When a parameter of reference type binds directly
-	 (_dcl.init.ref_) to an argument expression, the implicit
-	 conversion sequence is the identity conversion, unless the
-	 argument expression has a type that is a derived class of the
-	 parameter type, in which case the implicit conversion
-	 sequence is a derived-to-base Conversion.
-	 
-	 If the parameter binds directly to the result of applying a
-	 conversion function to the argument expression, the implicit
-	 conversion sequence is a user-defined conversion sequence
-	 (_over.ics.user_), with the second standard conversion
-	 sequence either an identity conversion or, if the conversion
-	 function returns an entity of a type that is a derived class
-	 of the parameter type, a derived-to-base Conversion.
-	 
-	 When a parameter of reference type is not bound directly to
-	 an argument expression, the conversion sequence is the one
-	 required to convert the argument expression to the underlying
-	 type of the reference according to _over.best.ics_.
-	 Conceptually, this conversion sequence corresponds to
-	 copy-initializing a temporary of the underlying type with the
-	 argument expression.  Any difference in top-level
-	 cv-qualification is subsumed by the initialization itself and
-	 does not constitute a conversion.  */
-
-      tree old_ics = *ics;
-
       *target_type = TREE_TYPE (TREE_TYPE (*ics));
       *ics = TREE_OPERAND (*ics, 0);
-      if (TREE_CODE (*ics) == IDENTITY_CONV
-	  && is_properly_derived_from (TREE_TYPE (*ics), *target_type))
-	*ics = build_conv (BASE_CONV, *target_type, *ics);
-      ICS_USER_FLAG (*ics) = ICS_USER_FLAG (old_ics);
-      ICS_BAD_FLAG (*ics) = ICS_BAD_FLAG (old_ics);
-      
       return 1;
     }
   
@@ -4385,4 +4662,25 @@ can_convert_arg (to, from, arg)
 {
   tree t = implicit_conversion (to, from, arg, LOOKUP_NORMAL);
   return (t && ! ICS_BAD_FLAG (t));
+}
+
+/* Convert EXPR to the indicated reference TYPE, in a way suitable for
+   initializing a variable of that TYPE.  Return the converted
+   expression.  */
+
+tree
+initialize_reference (type, expr)
+     tree type;
+     tree expr;
+{
+  tree conv;
+
+  conv = reference_binding (type, TREE_TYPE (expr), expr, LOOKUP_NORMAL);
+  if (!conv || ICS_BAD_FLAG (conv))
+    {
+      cp_error ("could not convert `%E' to `%T'", expr, type);
+      return error_mark_node;
+    }
+
+  return convert_like (conv, expr);
 }
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.245
diff -u -p -r1.245 cp-tree.h
--- cp-tree.h	1999/07/21 08:52:12	1.245
+++ cp-tree.h	1999/07/22 23:15:26
@@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA.  */
       TREE_INDIRECT_USING (in NAMESPACE_DECL).
       IDENTIFIER_MARKED (used by search routines).
       LOCAL_BINDING_P (in CPLUS_BINDING)
+      ICS_USER_FLAG (in _CONV)
    1: IDENTIFIER_VIRTUAL_P.
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -43,17 +44,21 @@ Boston, MA 02111-1307, USA.  */
       C_DECLARED_LABEL_FLAG.
       INHERITED_VALUE_BINDING_P (in CPLUS_BINDING)
       BASELINK_P (in TREE_LIST)
+      ICS_ELLIPSIS_FLAG (in _CONV)
    2: IDENTIFIER_OPNAME_P.
       BINFO_VBASE_MARKED.
       BINFO_FIELDS_MARKED.
       TYPE_VIRTUAL_P.
+      ICS_THIS_FLAG (in _CONV)
    3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE).
       BINFO_VTABLE_PATH_MARKED.
       BINFO_PUSHDECLS_MARKED.
       (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
+      ICS_BAD_FLAG (in _CONV)
    4: BINFO_NEW_VTABLE_MARKED.
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
           or FIELD_DECL).
+      NEED_TEMPORARY_P (in REF_BIND, BASE_CONV)
    5: Not used.
    6: Not used.
 
@@ -2140,6 +2145,14 @@ extern int flag_new_for_scope;
 enum tag_types { record_type, class_type, union_type, enum_type,
 		   signature_type };
 
+/* The various kinds of lvalues we distinguish.  */
+typedef enum cp_lvalue_kind {
+  clk_none = 0,     /* Things that are not an lvalue.  */
+  clk_ordinary = 1, /* An ordinary lvalue.  */
+  clk_class = 2,    /* An rvalue of class-type.  */
+  clk_bitfield = 4, /* An lvalue for a bit-field.  */
+} cp_lvalue_kind;
+
 /* Zero means prototype weakly, as in ANSI C (no args means nothing).
    Each language context defines how this variable should be set.  */
 extern int strict_prototype;
@@ -2753,6 +2766,7 @@ extern int enforce_access               
 extern tree convert_default_arg                 PROTO((tree, tree, tree));
 extern tree convert_arg_to_ellipsis             PROTO((tree));
 extern int is_properly_derived_from             PROTO((tree, tree));
+extern tree initialize_reference                PROTO((tree, tree));
 
 /* in class.c */
 extern tree build_vbase_path			PROTO((enum tree_code, tree, tree, tree, int));
@@ -3363,7 +3377,7 @@ extern tree arbitrate_lookup			PROTO((tr
 extern int pod_type_p				PROTO((tree));
 extern void unshare_base_binfos			PROTO((tree));
 extern int member_p				PROTO((tree));
-extern int real_lvalue_p			PROTO((tree));
+extern cp_lvalue_kind real_lvalue_p		PROTO((tree));
 extern tree build_min				PVPROTO((enum tree_code, tree, ...));
 extern tree build_min_nt			PVPROTO((enum tree_code, ...));
 extern tree min_tree_cons			PROTO((tree, tree, tree));
Index: cp/error.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/error.c,v
retrieving revision 1.78
diff -u -p -r1.78 error.c
--- error.c	1999/06/28 00:13:14	1.78
+++ error.c	1999/07/22 23:15:27
@@ -1409,7 +1409,22 @@ dump_expr (t, nop)
       break;
 
     case AGGR_INIT_EXPR:
-      OB_PUTID (TYPE_IDENTIFIER (TREE_TYPE (t)));
+      {
+	tree fn = NULL_TREE;
+	
+	if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
+	  fn = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+
+	if (fn && TREE_CODE (fn) == FUNCTION_DECL)
+	  {
+	    if (DECL_CONSTRUCTOR_P (fn))
+	      OB_PUTID (TYPE_IDENTIFIER (TREE_TYPE (t)));
+	    else
+	      dump_decl (fn, 0);
+	  }
+	else
+	  dump_expr (TREE_OPERAND (t, 0), 0);
+      }
       OB_PUTC ('(');
       if (TREE_OPERAND (t, 1))
 	dump_expr_list (TREE_CHAIN (TREE_OPERAND (t, 1)));
Index: cp/init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.112
diff -u -p -r1.112 init.c
--- init.c	1999/07/09 11:05:10	1.112
+++ init.c	1999/07/22 23:15:29
@@ -1177,6 +1177,10 @@ expand_default_init (binfo, true_exp, ex
 	   to run a new constructor; and catching an exception, where we
 	   have already built up the constructor call so we could wrap it
 	   in an exception region.  */;
+      else if (TREE_CODE (init) == CONSTRUCTOR)
+	/* A brace-enclosed initializer has whatever type is
+	   required.  There's no need to convert it.  */
+	;
       else
 	init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
Index: cp/search.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/search.c,v
retrieving revision 1.110
diff -u -p -r1.110 search.c
--- search.c	1999/07/20 10:41:07	1.110
+++ search.c	1999/07/22 23:15:36
@@ -3150,6 +3150,12 @@ add_conversions (binfo, data)
   return NULL_TREE;
 }
 
+/* Return a TREE_LIST containing all the non-hidden user-defined
+   conversion functions for TYPE (and its base-classes).  The
+   TREE_VALUE of each node is a FUNCTION_DECL or an OVERLOAD
+   containing the conversion functions.  The TREE_PURPOSE is the BINFO
+   from which the conversion functions in this node were selected.  */
+
 tree
 lookup_conversions (type)
      tree type;
Index: cp/tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/tree.c,v
retrieving revision 1.117
diff -u -p -r1.117 tree.c
--- tree.c	1999/05/31 00:25:56	1.117
+++ tree.c	1999/07/22 23:15:38
@@ -36,27 +36,30 @@ static int list_hash PROTO((tree, tree, 
 static tree list_hash_lookup PROTO((int, tree, tree, tree));
 static void propagate_binfo_offsets PROTO((tree, tree));
 static int avoid_overlap PROTO((tree, tree));
-static int lvalue_p_1 PROTO((tree, int));
+static cp_lvalue_kind lvalue_p_1 PROTO((tree, int));
 static int equal_functions PROTO((tree, tree));
 static tree no_linkage_helper PROTO((tree));
 static tree build_srcloc PROTO((char *, int));
 
 #define CEIL(x,y) (((x) + (y) - 1) / (y))
 
-/* Returns non-zero if REF is an lvalue.  If
-   TREAT_CLASS_RVALUES_AS_LVALUES is non-zero, rvalues of class type
-   are considered lvalues.  */
+/* If REF is an lvalue, returns the kind of lvalue that REF is.
+   Otherwise, returns clk_none.  If TREAT_CLASS_RVALUES_AS_LVALUES is
+   non-zero, rvalues of class type are considered lvalues.  */
 
-static int
+static cp_lvalue_kind
 lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
      tree ref;
      int treat_class_rvalues_as_lvalues;
 {
+  cp_lvalue_kind op1_lvalue_kind = clk_none;
+  cp_lvalue_kind op2_lvalue_kind = clk_none;
+
   if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
-    return 1;
+    return clk_ordinary;
 
   if (ref == current_class_ptr && flag_this_is_variable <= 0)
-    return 0;
+    return clk_none;
 
   switch (TREE_CODE (ref))
     {
@@ -64,7 +67,6 @@ lvalue_p_1 (ref, treat_class_rvalues_as_
 	 what they refer to are valid lvals.  */
     case PREINCREMENT_EXPR:
     case PREDECREMENT_EXPR:
-    case COMPONENT_REF:
     case SAVE_EXPR:
     case UNSAVE_EXPR:
     case TRY_CATCH_EXPR:
@@ -75,20 +77,37 @@ lvalue_p_1 (ref, treat_class_rvalues_as_
       return lvalue_p_1 (TREE_OPERAND (ref, 0),
 			 treat_class_rvalues_as_lvalues);
 
+    case COMPONENT_REF:
+      op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
+				    treat_class_rvalues_as_lvalues);
+      if (op1_lvalue_kind 
+	  /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
+	     situations.  */
+	  && TREE_CODE (TREE_OPERAND (ref, 1)) == FIELD_DECL
+	  && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))
+	{
+	  /* Clear the ordinary bit.  If this object was a class
+	     rvalue we want to preserve that information.  */
+	  op1_lvalue_kind &= ~clk_ordinary;
+	  /* The lvalue is for a btifield.  */
+	  op1_lvalue_kind |= clk_bitfield;
+	}
+      return op1_lvalue_kind;
+
     case STRING_CST:
-      return 1;
+      return clk_ordinary;
 
     case VAR_DECL:
       if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
 	  && DECL_LANG_SPECIFIC (ref)
 	  && DECL_IN_AGGR_P (ref))
-	return 0;
+	return clk_none;
     case INDIRECT_REF:
     case ARRAY_REF:
     case PARM_DECL:
     case RESULT_DECL:
       if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
-	return 1;
+	return clk_ordinary;
       break;
 
       /* A currently unresolved scope ref.  */
@@ -96,72 +115,84 @@ lvalue_p_1 (ref, treat_class_rvalues_as_
       my_friendly_abort (103);
     case OFFSET_REF:
       if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
-	return 1;
-      return (lvalue_p_1 (TREE_OPERAND (ref, 0),
-			  treat_class_rvalues_as_lvalues)
-	      && lvalue_p_1 (TREE_OPERAND (ref, 1),
-			     treat_class_rvalues_as_lvalues));
+	return clk_ordinary;
+      /* Fall through.  */
+    case MAX_EXPR:
+    case MIN_EXPR:
+      op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
+				    treat_class_rvalues_as_lvalues);
+      op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+				    treat_class_rvalues_as_lvalues);
       break;
 
     case COND_EXPR:
-      return (lvalue_p_1 (TREE_OPERAND (ref, 1),
-			  treat_class_rvalues_as_lvalues)
-	      && lvalue_p_1 (TREE_OPERAND (ref, 2),
-			     treat_class_rvalues_as_lvalues));
+      op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+				    treat_class_rvalues_as_lvalues);
+      op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2),
+				    treat_class_rvalues_as_lvalues);
+      break;
 
     case MODIFY_EXPR:
-      return 1;
+      return clk_ordinary;
 
     case COMPOUND_EXPR:
       return lvalue_p_1 (TREE_OPERAND (ref, 1),
-			    treat_class_rvalues_as_lvalues);
-
-    case MAX_EXPR:
-    case MIN_EXPR:
-      return (lvalue_p_1 (TREE_OPERAND (ref, 0),
-			  treat_class_rvalues_as_lvalues)
-	      && lvalue_p_1 (TREE_OPERAND (ref, 1),
-			     treat_class_rvalues_as_lvalues));
+			 treat_class_rvalues_as_lvalues);
 
     case TARGET_EXPR:
-      return treat_class_rvalues_as_lvalues;
+      return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
 
     case CALL_EXPR:
-      return (treat_class_rvalues_as_lvalues
-	      && IS_AGGR_TYPE (TREE_TYPE (ref)));
+      return ((treat_class_rvalues_as_lvalues
+	       && IS_AGGR_TYPE (TREE_TYPE (ref)))
+	      ? clk_class : clk_none);
 
     case FUNCTION_DECL:
       /* All functions (except non-static-member functions) are
 	 lvalues.  */
-      return !DECL_NONSTATIC_MEMBER_FUNCTION_P (ref);
+      return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) 
+	      ? clk_none : clk_ordinary);
 
     default:
       break;
     }
 
-  return 0;
+  /* If one operand is not an lvalue at all, then this expression is
+     not an lvalue.  */
+  if (!op1_lvalue_kind || !op2_lvalue_kind)
+    return clk_none;
+
+  /* Otherwise, it's an lvalue, and it has all the odd properties
+     contributed by either operand.  */
+  op1_lvalue_kind = op1_lvalue_kind | op2_lvalue_kind;
+  /* It's not an ordinary lvalue if it involves either a bit-field or
+     a class rvalue.  */
+  if ((op1_lvalue_kind & ~clk_ordinary) != clk_none)
+    op1_lvalue_kind &= ~clk_ordinary;
+  return op1_lvalue_kind;
 }
 
-/* Return nonzero if REF is an lvalue valid for this language.
-   Lvalues can be assigned, unless they have TREE_READONLY, or unless
-   they are FUNCTION_DECLs.  Lvalues can have their address taken,
-   unless they have DECL_REGISTER.  */
+/* If REF is an lvalue, returns the kind of lvalue that REF is.
+   Otherwise, returns clk_none.  Lvalues can be assigned, unless they
+   have TREE_READONLY, or unless they are FUNCTION_DECLs.  Lvalues can
+   have their address taken, unless they have DECL_REGISTER.  */
 
-int
+cp_lvalue_kind
 real_lvalue_p (ref)
      tree ref;
 {
   return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/0);
 }
 
-/* This differs from real_lvalue_p in that class rvalues are considered
-   lvalues.  */
+/* This differs from real_lvalue_p in that class rvalues are
+   considered lvalues.  */
 
 int
 lvalue_p (ref)
      tree ref;
 {
-  return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1);
+  return 
+    (lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1) != clk_none);
 }
 
 /* Return nonzero if REF is an lvalue valid for this language;
@@ -192,6 +223,11 @@ build_cplus_new (type, init)
 {
   tree slot;
   tree rval;
+
+  /* Make sure that we're not trying to create an instance of an
+     abstract class.  */
+  if (CLASSTYPE_ABSTRACT_VIRTUALS (type))
+    abstract_virtuals_error (NULL_TREE, type);
 
   if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
     return convert (type, init);
Index: cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.173
diff -u -p -r1.173 typeck.c
--- typeck.c	1999/07/09 11:05:21	1.173
+++ typeck.c	1999/07/22 23:15:42
@@ -7122,8 +7122,7 @@ convert_for_initialization (exp, type, r
 
       if (fndecl)
 	savew = warningcount, savee = errorcount;
-      rhs = convert_to_reference (type, rhs, CONV_IMPLICIT, flags,
-				  exp ? exp : error_mark_node);
+      rhs = initialize_reference (type, rhs);
       if (fndecl)
 	{
 	  if (warningcount > savew)


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