diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0b67eb5db38c..f37a3e481895 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +1998-06-10 Mark Mitchell + + * call.c (convert_default_arg): Make global, not static. + (convert_arg_for_ellipsis): Split out from ... + (build_over_call): Here. + * cp-tree.h (convert_default_arg); Declare. + (convert_arg_to_ellipsis): Likewise. + (do_member_init): Remove. + * init.c (do_member_init): Remove; this code is dead. + (expand_member_init): Remove much of this code; it is dead. + * typeck.c (convert_arguments): Use convert_default_arg and + convert_arg_for_ellipsis, rather than duplicating here. + + * call.c (convert_like): Don't fail silently if + build_user_type_conversion fails. Always return error_mark_node + for failure. + 1998-06-10 Jason Merrill * search.c (covariant_return_p): Complain about ambiguous base. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 173bdde4d9f9..429b4cf4758e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -47,7 +47,6 @@ static struct z_candidate * tourney PROTO((struct z_candidate *)); static int joust PROTO((struct z_candidate *, struct z_candidate *, int)); static int compare_ics PROTO((tree, tree)); static tree build_over_call PROTO((struct z_candidate *, tree, int)); -static tree convert_default_arg PROTO((tree, tree)); static tree convert_like PROTO((tree, tree)); static void op_error PROTO((enum tree_code, enum tree_code, tree, tree, tree, char *)); @@ -3155,8 +3154,32 @@ convert_like (convs, expr) return expr; /* else fall through */ case BASE_CONV: - return build_user_type_conversion - (TREE_TYPE (convs), expr, LOOKUP_NORMAL); + { + tree cvt_expr = build_user_type_conversion + (TREE_TYPE (convs), expr, LOOKUP_NORMAL); + if (!cvt_expr) + { + /* This can occur if, for example, the EXPR has incomplete + type. We can't check for that before attempting the + conversion because the type might be an incomplete + array type, which is OK if some constructor for the + destination type takes a pointer argument. */ + if (TYPE_SIZE (TREE_TYPE (expr)) == 0) + { + if (comptypes (TREE_TYPE (expr), TREE_TYPE (convs), 1)) + incomplete_type_error (expr, TREE_TYPE (expr)); + else + cp_error ("could not convert `%E' (with incomplete type `%T') to `%T'", + expr, TREE_TYPE (expr), TREE_TYPE (convs)); + } + else + cp_error ("could not convert `%E' to `%T'", + expr, TREE_TYPE (convs)); + return error_mark_node; + } + return cvt_expr; + } + case REF_BIND: return convert_to_reference (TREE_TYPE (convs), expr, @@ -3172,7 +3195,34 @@ convert_like (convs, expr) LOOKUP_NORMAL|LOOKUP_NO_CONVERSION); } -static tree +/* ARG is being passed to a varargs function. Perform any conversions + required. Return the converted value. */ + +tree +convert_arg_to_ellipsis (arg) + tree arg; +{ + if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE + && (TYPE_PRECISION (TREE_TYPE (arg)) + < TYPE_PRECISION (double_type_node))) + /* Convert `float' to `double'. */ + arg = cp_convert (double_type_node, arg); + else if (IS_AGGR_TYPE (TREE_TYPE (arg)) + && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (arg))) + cp_warning ("cannot pass objects of type `%T' through `...'", + TREE_TYPE (arg)); + else + /* Convert `short' and `char' to full-size `int'. */ + arg = default_conversion (arg); + + return arg; +} + +/* ARG is a default argument expression being passed to a parameter of + the indicated TYPE. Do any required conversions. Return the + converted value. */ + +tree convert_default_arg (type, arg) tree type, arg; { @@ -3341,24 +3391,10 @@ build_over_call (cand, args, flags) /* Ellipsis */ for (; arg; arg = TREE_CHAIN (arg)) - { - val = TREE_VALUE (arg); - - if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE - && (TYPE_PRECISION (TREE_TYPE (val)) - < TYPE_PRECISION (double_type_node))) - /* Convert `float' to `double'. */ - val = cp_convert (double_type_node, val); - else if (IS_AGGR_TYPE (TREE_TYPE (val)) - && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val))) - cp_warning ("cannot pass objects of type `%T' through `...'", - TREE_TYPE (val)); - else - /* Convert `short' and `char' to full-size `int'. */ - val = default_conversion (val); - - converted_args = expr_tree_cons (NULL_TREE, val, converted_args); - } + converted_args + = expr_tree_cons (NULL_TREE, + convert_arg_to_ellipsis (TREE_VALUE (arg)), + converted_args); converted_args = nreverse (converted_args); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3e118d91a5a5..f0e59fd4322a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2254,6 +2254,8 @@ extern tree build_op_delete_call PROTO((enum tree_code, tree, tree, int)); extern int can_convert PROTO((tree, tree)); extern int can_convert_arg PROTO((tree, tree, tree)); extern void enforce_access PROTO((tree, tree)); +extern tree convert_default_arg PROTO((tree, tree)); +extern tree convert_arg_to_ellipsis PROTO((tree)); /* in class.c */ extern tree build_vbase_path PROTO((enum tree_code, tree, tree, tree, int)); @@ -2532,7 +2534,6 @@ extern void init_init_processing PROTO((void)); extern void expand_direct_vtbls_init PROTO((tree, tree, int, int, tree)); extern void emit_base_init PROTO((tree, int)); extern void check_base_init PROTO((tree)); -extern void do_member_init PROTO((tree, tree, tree)); extern void expand_member_init PROTO((tree, tree, tree)); extern void expand_aggr_init PROTO((tree, tree, int, int)); extern int is_aggr_typedef PROTO((tree, int)); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 828729c3c6c2..59491a718b47 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -832,34 +832,6 @@ expand_aggr_vbase_init (binfo, exp, addr, init_list) } } -/* Subroutine to perform parser actions for member initialization. - S_ID is the scoped identifier. - NAME is the name of the member. - INIT is the initializer, or `void_type_node' if none. */ - -void -do_member_init (s_id, name, init) - tree s_id, name, init; -{ - tree binfo, base; - - if (current_class_type == NULL_TREE - || ! is_aggr_typedef (s_id, 1)) - return; - binfo = get_binfo (IDENTIFIER_TYPE_VALUE (s_id), - current_class_type, 1); - if (binfo == error_mark_node) - return; - if (binfo == 0) - { - error_not_base_type (IDENTIFIER_TYPE_VALUE (s_id), current_class_type); - return; - } - - base = convert_pointer_to (binfo, current_class_ptr); - expand_member_init (build_indirect_ref (base, NULL_PTR), name, init); -} - /* Find the context in which this FIELD can be initialized. */ static tree @@ -958,151 +930,84 @@ expand_member_init (exp, name, init) return; } - if (init) + my_friendly_assert (init != NULL_TREE, 0); + + /* The grammar should not allow fields which have names that are + TYPENAMEs. Therefore, if the field has a non-NULL TREE_TYPE, we + may assume that this is an attempt to initialize a base class + member of the current type. Otherwise, it is an attempt to + initialize a member field. */ + + if (init == void_type_node) + init = NULL_TREE; + + if (name == NULL_TREE || basetype) { - /* The grammar should not allow fields which have names - that are TYPENAMEs. Therefore, if the field has - a non-NULL TREE_TYPE, we may assume that this is an - attempt to initialize a base class member of the current - type. Otherwise, it is an attempt to initialize a - member field. */ + tree base_init; - if (init == void_type_node) - init = NULL_TREE; - - if (name == NULL_TREE || basetype) + if (name == NULL_TREE) { - tree base_init; - - if (name == NULL_TREE) - { #if 0 - if (basetype) - name = TYPE_IDENTIFIER (basetype); - else - { - error ("no base class to initialize"); - return; - } + if (basetype) + name = TYPE_IDENTIFIER (basetype); + else + { + error ("no base class to initialize"); + return; + } #endif - } - else if (basetype != type - && ! current_template_parms - && ! vec_binfo_member (basetype, - TYPE_BINFO_BASETYPES (type)) - && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type))) - { - if (IDENTIFIER_CLASS_VALUE (name)) - goto try_member; - if (TYPE_USES_VIRTUAL_BASECLASSES (type)) - cp_error ("type `%T' is not an immediate or virtual basetype for `%T'", - basetype, type); - else - cp_error ("type `%T' is not an immediate basetype for `%T'", - basetype, type); - return; - } - - if (purpose_member (basetype, current_base_init_list)) - { - cp_error ("base class `%T' already initialized", basetype); - return; - } - - if (warn_reorder && current_member_init_list) - { - cp_warning ("base initializer for `%T'", basetype); - warning (" will be re-ordered to precede member initializations"); - } - - base_init = build_tree_list (basetype, init); - current_base_init_list = chainon (current_base_init_list, base_init); } - else + else if (basetype != type + && ! current_template_parms + && ! vec_binfo_member (basetype, + TYPE_BINFO_BASETYPES (type)) + && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type))) { - tree member_init; - - try_member: - field = lookup_field (type, name, 1, 0); - - if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name))) - return; - - if (purpose_member (name, current_member_init_list)) - { - cp_error ("field `%D' already initialized", field); - return; - } - - member_init = build_tree_list (name, init); - current_member_init_list = chainon (current_member_init_list, member_init); + if (IDENTIFIER_CLASS_VALUE (name)) + goto try_member; + if (TYPE_USES_VIRTUAL_BASECLASSES (type)) + cp_error ("type `%T' is not an immediate or virtual basetype for `%T'", + basetype, type); + else + cp_error ("type `%T' is not an immediate basetype for `%T'", + basetype, type); + return; } - return; - } - else if (name == NULL_TREE) - { - compiler_error ("expand_member_init: name == NULL_TREE"); - return; - } - basetype = type; - field = lookup_field (basetype, name, 0, 0); - - if (! member_init_ok_or_else (field, basetype, IDENTIFIER_POINTER (name))) - return; - - /* now see if there is a constructor for this type - which will take these args. */ - - if (TYPE_HAS_CONSTRUCTOR (TREE_TYPE (field))) - { - tree parmtypes, fndecl; - - if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) + if (purpose_member (basetype, current_base_init_list)) { - /* just know that we've seen something for this node */ - DECL_INITIAL (exp) = error_mark_node; - TREE_USED (exp) = 1; + cp_error ("base class `%T' already initialized", basetype); + return; } - type = TYPE_MAIN_VARIANT (TREE_TYPE (field)); - parm = build_component_ref (exp, name, NULL_TREE, 0); - /* Now get to the constructors. */ - fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0); + if (warn_reorder && current_member_init_list) + { + cp_warning ("base initializer for `%T'", basetype); + warning (" will be re-ordered to precede member initializations"); + } - if (fndecl) - my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 209); + base_init = build_tree_list (basetype, init); + current_base_init_list = chainon (current_base_init_list, base_init); + } + else + { + tree member_init; - parmtypes = NULL_TREE; - fndecl = NULL_TREE; + try_member: + field = lookup_field (type, name, 1, 0); - init = convert_arguments (parm, parmtypes, NULL_TREE, fndecl, LOOKUP_NORMAL); - if (init == NULL_TREE || TREE_TYPE (init) != error_mark_node) - rval = build_method_call (NULL_TREE, ctor_identifier, init, - TYPE_BINFO (type), LOOKUP_NORMAL); - else + if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name))) return; - if (rval != error_mark_node) + if (purpose_member (name, current_member_init_list)) { - /* Now, fill in the first parm with our guy */ - TREE_VALUE (TREE_OPERAND (rval, 1)) - = build_unary_op (ADDR_EXPR, parm, 0); - TREE_TYPE (rval) = ptr_type_node; - TREE_SIDE_EFFECTS (rval) = 1; + cp_error ("field `%D' already initialized", field); + return; } - } - else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field))) - { - parm = build_component_ref (exp, name, NULL_TREE, 0); - expand_aggr_init (parm, NULL_TREE, 0, 0); - rval = error_mark_node; - } - /* Now initialize the member. It does not have to - be of aggregate type to receive initialization. */ - if (rval != error_mark_node) - expand_expr_stmt (rval); + member_init = build_tree_list (name, init); + current_member_init_list = chainon (current_member_init_list, member_init); + } } /* This is like `expand_member_init', only it stores one aggregate diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8c71a2442207..d417afbed6d3 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3037,24 +3037,9 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE) val = convert_from_reference (val); - if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE - && (TYPE_PRECISION (TREE_TYPE (val)) - < TYPE_PRECISION (double_type_node))) - /* Convert `float' to `double'. */ - result = expr_tree_cons (NULL_TREE, - cp_convert (double_type_node, val), - result); - else if (IS_AGGR_TYPE (TREE_TYPE (val)) - && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val))) - { - cp_warning ("cannot pass objects of type `%T' through `...'", - TREE_TYPE (val)); - result = expr_tree_cons (NULL_TREE, val, result); - } - else - /* Convert `short' and `char' to full-size `int'. */ - result = expr_tree_cons (NULL_TREE, default_conversion (val), - result); + result = expr_tree_cons (NULL_TREE, + convert_arg_to_ellipsis (val), + result); } if (typetail) @@ -3069,37 +3054,8 @@ convert_arguments (return_loc, typelist, values, fndecl, flags) for (; typetail != void_list_node; ++i) { tree type = TREE_VALUE (typetail); - tree val = break_out_target_exprs (TREE_PURPOSE (typetail)); - tree parmval; - - if (val == NULL_TREE) - parmval = error_mark_node; - else if (TREE_CODE (val) == CONSTRUCTOR) - { - parmval = digest_init (type, val, (tree *)0); - parmval = convert_for_initialization (return_loc, type, - parmval, flags, - "default constructor", - fndecl, i); - } - else - { - /* This could get clobbered by the following call. */ - if (TREE_HAS_CONSTRUCTOR (val)) - val = copy_node (val); - - parmval = convert_for_initialization (return_loc, type, - val, flags, - "default argument", - fndecl, i); -#ifdef PROMOTE_PROTOTYPES - if ((TREE_CODE (type) == INTEGER_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) - && (TYPE_PRECISION (type) - < TYPE_PRECISION (integer_type_node))) - parmval = default_conversion (parmval); -#endif - } + tree val = TREE_PURPOSE (typetail); + tree parmval = convert_default_arg (type, val); if (parmval == error_mark_node) return error_mark_node; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash9.C b/gcc/testsuite/g++.old-deja/g++.pt/crash9.C new file mode 100644 index 000000000000..297b8accaad8 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash9.C @@ -0,0 +1,11 @@ +// Build don't link: + +template +void f(T) {} // ERROR - parameter has incomplete type + +class C; + +void g(const C& c) +{ + f(c); // ERROR - invalid use of undefined type +}