aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1998-06-11 00:07:24 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1998-06-11 00:07:24 +0000
commit41efda8f53e4a8edd2bfff6ccc3f2d1ee7b9c22a (patch)
treec1189af495a1437dc230d7b58fe49140aa3d3e1e
parent8358a974b5f51600a204192c91407ac6355c0ca5 (diff)
downloadgcc-41efda8f53e4a8edd2bfff6ccc3f2d1ee7b9c22a.zip
gcc-41efda8f53e4a8edd2bfff6ccc3f2d1ee7b9c22a.tar.gz
gcc-41efda8f53e4a8edd2bfff6ccc3f2d1ee7b9c22a.tar.bz2
call.c (convert_default_arg): Make global, not static.
* 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. From-SVN: r20424
-rw-r--r--gcc/cp/ChangeLog17
-rw-r--r--gcc/cp/call.c80
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/init.c207
-rw-r--r--gcc/cp/typeck.c54
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/crash9.C11
6 files changed, 149 insertions, 223 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0b67eb5..f37a3e4 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,20 @@
+1998-06-10 Mark Mitchell <mark@markmitchell.com>
+
+ * 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 <jason@yorick.cygnus.com>
* search.c (covariant_return_p): Complain about ambiguous base.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 173bdde..429b4cf 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 3e118d9..f0e59fd 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 828729c..59491a7 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)
- {
- /* 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. */
+ my_friendly_assert (init != NULL_TREE, 0);
- if (init == void_type_node)
- init = NULL_TREE;
+ /* 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 (name == NULL_TREE || basetype)
- {
- tree base_init;
+ if (init == void_type_node)
+ init = NULL_TREE;
- if (name == NULL_TREE)
- {
-#if 0
- 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 (name == NULL_TREE || basetype)
+ {
+ tree base_init;
- if (purpose_member (basetype, current_base_init_list))
+ if (name == NULL_TREE)
+ {
+#if 0
+ if (basetype)
+ name = TYPE_IDENTIFIER (basetype);
+ else
{
- cp_error ("base class `%T' already initialized", basetype);
+ error ("no base class to initialize");
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);
+#endif
}
- 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 8c71a24..d417afb 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 0000000..297b8ac
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash9.C
@@ -0,0 +1,11 @@
+// Build don't link:
+
+template <class T>
+void f(T) {} // ERROR - parameter has incomplete type
+
+class C;
+
+void g(const C& c)
+{
+ f(c); // ERROR - invalid use of undefined type
+}