From 27b8d0cd535f663df34c8264ee48e3034a663c38 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 23 Jul 1999 01:01:16 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 31 ++ gcc/cp/call.c | 464 ++++++++++++++---- gcc/cp/cp-tree.h | 16 +- gcc/cp/error.c | 17 +- gcc/cp/init.c | 4 + gcc/cp/search.c | 6 + gcc/cp/tree.c | 120 +++-- gcc/cp/typeck.c | 3 +- .../g++.old-deja/g++.other/bitfld1.C | 2 - gcc/testsuite/g++.old-deja/g++.robertl/eb76.C | 1 - 10 files changed, 532 insertions(+), 132 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d5d2fa1fd6b..c111a865279 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,34 @@ +1999-07-22 Mark Mitchell + + * 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 * lex.c (real_yylex) : Correct the test for overflow when lexing diff --git a/gcc/cp/call.c b/gcc/cp/call.c index cdfba0441e1..22f30dcc46b 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 55c93ea68b5..50d28ca9f1d 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 544e66e8e3b..60d73de03ea 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 de3491a16f6..8469fe6ab1b 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 f1be6db5fb5..6cde6905c12 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 2795c676355..c32bf8f399e 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 fa54e37e1fb..7add5504459 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 ad21fd7fb85..07f1021e2b5 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 -// excess errors test - XFAIL *-*-* - // declares template operator!= #include diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C index e2817eefd09..f8dba7b4741 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 -- 2.30.2