aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>1999-07-23 01:01:16 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1999-07-23 01:01:16 +0000
commit27b8d0cd535f663df34c8264ee48e3034a663c38 (patch)
tree7ab5ead2d1ccd9e6e12bd7904bc7fecc99b3fe43
parentac1d97ceb67feea6e4e37e14a8bc86c5851574c3 (diff)
downloadgcc-27b8d0cd535f663df34c8264ee48e3034a663c38.zip
gcc-27b8d0cd535f663df34c8264ee48e3034a663c38.tar.gz
gcc-27b8d0cd535f663df34c8264ee48e3034a663c38.tar.bz2
call.c (NEED_TEMPORARY_P): New macro.
* 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. From-SVN: r28221
-rw-r--r--gcc/cp/ChangeLog31
-rw-r--r--gcc/cp/call.c464
-rw-r--r--gcc/cp/cp-tree.h16
-rw-r--r--gcc/cp/error.c17
-rw-r--r--gcc/cp/init.c4
-rw-r--r--gcc/cp/search.c6
-rw-r--r--gcc/cp/tree.c120
-rw-r--r--gcc/cp/typeck.c3
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/bitfld1.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.robertl/eb76.C1
10 files changed, 532 insertions, 132 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d5d2fa1..c111a86 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,34 @@
+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.
+
1999-07-21 Gavin Romig-Koch <gavin@cygnus.com>
* lex.c (real_yylex) : Correct the test for overflow when lexing
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index cdfba04..22f30dc 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -92,6 +92,10 @@ static struct z_candidate * add_candidate PROTO((struct z_candidate *,
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, flags)
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, flags)
from = TREE_TYPE (expr);
}
- if (TREE_CODE (from) == REFERENCE_TYPE)
- from = TREE_TYPE (from);
- else if (! expr || ! real_lvalue_p (expr))
- lvalue = 0;
+ related_p = reference_related_p (to, from);
+ compatible_p = reference_compatible_p (to, from);
- 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)));
+ if (TREE_CODE (from) == REFERENCE_TYPE)
+ {
+ /* Anything with reference type is an lvalue. */
+ lvalue_p = clk_ordinary;
+ from = TREE_TYPE (from);
+ }
+ else if (expr)
+ lvalue_p = real_lvalue_p (expr);
- if (lvalue && related && at_least_as_qualified_p (to, from))
+ if (lvalue_p && compatible_p)
{
- conv = build1 (IDENTITY_CONV, from, expr);
+ /* [dcl.init.ref]
- 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;
- }
+ 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
- conv = NULL_TREE;
-
- if (! conv)
+ else if (CLASS_TYPE_P (from) && !(flags & LOOKUP_NO_CONVERSION))
{
- conv = standard_conversion (to, rfrom, expr);
+ /* [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;
}
@@ -4386,3 +4663,24 @@ 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);
+}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 55c93ea..50d28ca 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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 PROTO((tree, tree));
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((tree, tree, tree));
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));
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 544e66e..60d73de 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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)));
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index de3491a..8469fe6 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1177,6 +1177,10 @@ expand_default_init (binfo, true_exp, exp, init, flags)
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);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index f1be6db..6cde690 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -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;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2795c67..c32bf8f 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -36,27 +36,30 @@ static int list_hash PROTO((tree, 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_lvalues)
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_lvalues)
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_lvalues)
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;
@@ -193,6 +224,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);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index fa54e37..7add550 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -7122,8 +7122,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
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)
diff --git a/gcc/testsuite/g++.old-deja/g++.other/bitfld1.C b/gcc/testsuite/g++.old-deja/g++.other/bitfld1.C
index ad21fd7..07f1021 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/bitfld1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/bitfld1.C
@@ -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>
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C
index e2817ee..f8dba7b 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C
@@ -1,6 +1,5 @@
//Build don't link:
// the template operator!= interferes. It should be in a namespace.
-// excess errors test - XFAIL *-*-*
#include <utility>