aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authormrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>1996-08-08 22:08:30 +0000
committermrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>1996-08-08 22:08:30 +0000
commit596c0ae6118a3054ae58bd59c77dce66a296e8d0 (patch)
tree5f812ca193a1c6b6f60d64c3bd5ac1566d65c73a /gcc
parentcef3f5da953628b997019cb40dec114afa4256e0 (diff)
*** empty log message ***
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@12602 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/Makefile.in2
-rw-r--r--gcc/cp/call.c2
-rw-r--r--gcc/cp/class.c12
-rw-r--r--gcc/cp/cp-tree.def3
-rw-r--r--gcc/cp/cp-tree.h21
-rw-r--r--gcc/cp/cvt.c1468
-rw-r--r--gcc/cp/decl.c74
-rw-r--r--gcc/cp/decl2.c19
-rw-r--r--gcc/cp/error.c15
-rw-r--r--gcc/cp/except.c946
-rw-r--r--gcc/cp/init.c10
-rw-r--r--gcc/cp/lang-options.h2
-rw-r--r--gcc/cp/lex.c14
-rw-r--r--gcc/cp/method.c11
-rw-r--r--gcc/cp/pt.c132
-rw-r--r--gcc/cp/search.c90
-rw-r--r--gcc/cp/typeck.c76
-rw-r--r--gcc/cp/typeck2.c5
18 files changed, 1764 insertions, 1138 deletions
diff --git a/gcc/cp/Makefile.in b/gcc/cp/Makefile.in
index b7d94a41177..28b15cfce22 100644
--- a/gcc/cp/Makefile.in
+++ b/gcc/cp/Makefile.in
@@ -238,7 +238,7 @@ search.o : search.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h $(srcdir)/../
tree.o : tree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
ptree.o : ptree.c $(CONFIG_H) $(CXX_TREE_H)
rtti.o : rtti.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
-except.o : except.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H)
+except.o : except.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) $(srcdir)/../except.h
expr.o : expr.c $(CONFIG_H) $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
$(srcdir)/../expr.h ../insn-codes.h
xref.o : xref.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../input.h
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index dc8d2997656..741e703c1bb 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2792,7 +2792,7 @@ build_overload_call_real (fnname, parms, flags, final_cp, require_complete)
i = type_unification (DECL_TEMPLATE_PARMS (function), targs,
TYPE_ARG_TYPES (TREE_TYPE (function)),
- parms, &template_cost, 0);
+ parms, &template_cost, 0, 0);
if (i == 0)
{
function = instantiate_template (function, targs);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b631b967968..01d59247b8c 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3017,8 +3017,8 @@ extern int interface_only, interface_unknown;
or otherwise in a type-consistent manner. */
tree
-finish_struct_1 (t, attributes, warn_anon)
- tree t, attributes;
+finish_struct_1 (t, warn_anon)
+ tree t;
int warn_anon;
{
int old;
@@ -3073,8 +3073,6 @@ finish_struct_1 (t, attributes, warn_anon)
TYPE_SIZE (t) = NULL_TREE;
CLASSTYPE_GOT_SEMICOLON (t) = 0;
- cplus_decl_attributes (t, attributes, NULL_TREE);
-
#if 0
/* This is in general too late to do this. I moved the main case up to
left_curly, what else needs to move? */
@@ -4371,6 +4369,8 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
*tail = NULL_TREE;
TYPE_FIELDS (t) = fields;
+ cplus_decl_attributes (t, attributes, NULL_TREE);
+
if (processing_template_decl)
{
tree d = getdecls ();
@@ -4395,7 +4395,7 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
TYPE_SIZE (t) = integer_zero_node;
}
else
- t = finish_struct_1 (t, attributes, warn_anon);
+ t = finish_struct_1 (t, warn_anon);
TYPE_BEING_DEFINED (t) = 0;
@@ -4997,7 +4997,7 @@ instantiate_type (lhstype, rhs, complain)
int i, d = 0;
i = type_unification (DECL_TEMPLATE_PARMS (elem), t,
TYPE_ARG_TYPES (TREE_TYPE (elem)),
- TYPE_ARG_TYPES (lhstype), &d, 0);
+ TYPE_ARG_TYPES (lhstype), &d, 0, 1);
if (i == 0)
{
if (save_elem)
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 6301973cf13..d8342041704 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -138,7 +138,7 @@ DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", "e", 2)
DEFTREECODE (CASE_LABEL, "case_label", "e", 2)
DEFTREECODE (RETURN_INIT, "return_init", "e", 2)
-DEFTREECODE (EXACT_CONV, "exact_conv", "e", 1)
+DEFTREECODE (IDENTITY_CONV, "identity_conv", "e", 1)
DEFTREECODE (LVALUE_CONV, "lvalue_conv", "e", 1)
DEFTREECODE (QUAL_CONV, "qual_conv", "e", 1)
DEFTREECODE (STD_CONV, "std_conv", "e", 1)
@@ -148,3 +148,4 @@ DEFTREECODE (BASE_CONV, "base_conv", "e", 1)
DEFTREECODE (REF_BIND, "ref_bind", "e", 1)
DEFTREECODE (USER_CONV, "user_conv", "e", 4)
DEFTREECODE (AMBIG_CONV, "ambig_conv", "e", 1)
+DEFTREECODE (RVALUE_CONV, "rvalue_conv", "e", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 00c0fcdfab9..7f6fd805006 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -295,11 +295,6 @@ extern int flag_elide_constructors;
extern int flag_ansi;
-/* Nonzero means recognize and handle ansi-style exception handling
- constructs. */
-
-extern int flag_handle_exceptions;
-
/* Nonzero means recognize and handle signature language constructs. */
extern int flag_handle_signatures;
@@ -336,8 +331,8 @@ enum languages { lang_c, lang_cplusplus };
#define IS_AGGR_TYPE_2(TYPE1,TYPE2) \
(TREE_CODE (TYPE1) == TREE_CODE (TYPE2) \
&& IS_AGGR_TYPE (TYPE1)&IS_AGGR_TYPE (TYPE2))
-#define IS_OVERLOAD_TYPE_CODE(t) (IS_AGGR_TYPE_CODE (t) || t == ENUMERAL_TYPE)
-#define IS_OVERLOAD_TYPE(t) (IS_OVERLOAD_TYPE_CODE (TREE_CODE (t)))
+#define IS_OVERLOAD_TYPE(t) \
+ (IS_AGGR_TYPE (t) || TREE_CODE (t) == ENUMERAL_TYPE)
/* In a *_TYPE, nonzero means a built-in type. */
#define TYPE_BUILT_IN(NODE) TYPE_LANG_FLAG_6(NODE)
@@ -1951,7 +1946,7 @@ extern void add_method PROTO((tree, tree *, tree));
extern tree get_vfield_offset PROTO((tree));
extern void duplicate_tag_error PROTO((tree));
extern tree finish_struct PROTO((tree, tree, tree, int));
-extern tree finish_struct_1 PROTO((tree, tree, int));
+extern tree finish_struct_1 PROTO((tree, int));
extern tree finish_struct_methods PROTO((tree, tree, int));
extern int resolves_to_fixed_type_p PROTO((tree, int *));
extern void init_class_processing PROTO((void));
@@ -2122,9 +2117,9 @@ extern void mark_used PROTO((tree));
/* in except.c */
extern tree protect_list;
-extern void start_protect PROTO((void));
-extern void end_protect PROTO((tree));
-extern void end_protect_partials ();
+extern void expand_eh_region_start PROTO((void));
+extern void expand_eh_region_end PROTO((tree));
+extern void end_protect_partials PROTO((void));
extern void expand_exception_blocks PROTO((void));
extern void expand_start_try_stmts PROTO((void));
extern void expand_end_try_stmts PROTO((void));
@@ -2133,8 +2128,6 @@ extern void expand_end_all_catch PROTO((void));
extern void start_catch_block PROTO((tree, tree));
extern void end_catch_block PROTO((void));
extern void expand_throw PROTO((tree));
-extern int might_have_exceptions_p PROTO((void));
-extern void emit_exception_table PROTO((void));
extern tree build_throw PROTO((tree));
extern void init_exception_processing PROTO((void));
extern void expand_builtin_throw PROTO((void));
@@ -2292,7 +2285,7 @@ extern int uses_template_parms PROTO((tree));
extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree *));
extern void overload_template_name PROTO((tree));
-extern int type_unification PROTO((tree, tree *, tree, tree, int *, int));
+extern int type_unification PROTO((tree, tree *, tree, tree, int *, int, int));
struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int));
extern void mark_class_instantiated PROTO((tree, int));
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index e0a0b1976a8..a4c68e2180b 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -719,8 +719,6 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
#ifdef NEW_OVER
rval_as_conversion
= build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
- if (rval_as_conversion)
- rval_as_conversion = convert_from_reference (rval_as_conversion);
#else
rval_as_conversion = build_type_conversion (CONVERT_EXPR, type, expr, 1);
#endif
@@ -1344,6 +1342,9 @@ cp_convert (type, expr, convtype, flags)
#ifndef NEW_OVER
if (TYPE_HAS_CONSTRUCTOR (complete_type (type)))
+#else
+ if (TYPE_HAS_CONSTRUCTOR (complete_type (type)) && ! conversion)
+#endif
ctor = build_method_call (NULL_TREE, ctor_identifier,
build_tree_list (NULL_TREE, e),
TYPE_BINFO (type),
@@ -1369,14 +1370,13 @@ cp_convert (type, expr, convtype, flags)
return NULL_TREE;
return error_mark_node;
}
+ else if (conversion)
+ return conversion;
else if (ctor)
{
ctor = build_cplus_new (type, ctor);
return ctor;
}
-#endif
- else if (conversion)
- return conversion;
}
/* If TYPE or TREE_TYPE (E) is not on the permanent_obstack,
@@ -1853,7 +1853,6 @@ type_promotes_to (type)
return cp_build_type_variant (type, constp, volatilep);
}
-#ifdef NEW_OVER
/* Work in progress. Ask jason before removing. */
struct z_candidate {
@@ -1866,12 +1865,13 @@ struct z_candidate {
struct z_candidate *next;
};
-#define EXACT_RANK 0
-#define PROMO_RANK 1
-#define STD_RANK 2
-#define PBOOL_RANK 3
-#define USER_RANK 4
-#define ELLIPSIS_RANK 5
+#define IDENTITY_RANK 0
+#define EXACT_RANK 1
+#define PROMO_RANK 2
+#define STD_RANK 3
+#define PBOOL_RANK 4
+#define USER_RANK 5
+#define ELLIPSIS_RANK 6
#define ICS_RANK(NODE) \
(ICS_ELLIPSIS_FLAG (NODE) ? ELLIPSIS_RANK \
@@ -1885,10 +1885,11 @@ struct z_candidate {
#define USER_CONV_FN(NODE) TREE_OPERAND (NODE, 1)
-struct z_candidate * build_user_type_conversion_1 ();
-tree convert_like ();
-tree build_over_call ();
-struct z_candidate * tourney ();
+static struct z_candidate * build_user_type_conversion_1 ();
+static tree convert_like ();
+static tree build_over_call ();
+static struct z_candidate * tourney ();
+static void enforce_access ();
int
null_ptr_cst (t)
@@ -1914,6 +1915,12 @@ build_conv (code, type, from)
rank = STD_RANK;
break;
+ case LVALUE_CONV:
+ case QUAL_CONV:
+ case RVALUE_CONV:
+ if (rank < EXACT_RANK)
+ rank = EXACT_RANK;
+
default:
break;
}
@@ -1931,6 +1938,10 @@ non_reference (t)
return t;
}
+/* Returns the standard conversion path (see [conv]) from type FROM to type
+ TO, if any. For proper handling of null pointer constants, you must
+ also pass the expression EXPR to convert from. */
+
tree
standard_conversion (to, from, expr)
tree to, from, expr;
@@ -1941,7 +1952,7 @@ standard_conversion (to, from, expr)
fcode = TREE_CODE (from);
tcode = TREE_CODE (to);
- conv = build1 (EXACT_CONV, from, expr);
+ conv = build1 (IDENTITY_CONV, from, expr);
if (from == to)
return conv;
@@ -1986,7 +1997,7 @@ standard_conversion (to, from, expr)
tree fbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (from));
tree tbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (to));
- if (DERIVED_FROM_P (tbase, fbase)
+ if (DERIVED_FROM_P (fbase, tbase)
&& (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (from))),
TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (to))),
1)))
@@ -2031,7 +2042,7 @@ standard_conversion (to, from, expr)
tree fbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fromfn)));
tree tbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (tofn)));
- if (! DERIVED_FROM_P (tbase, fbase)
+ if (! DERIVED_FROM_P (fbase, tbase)
|| ! comptypes (TREE_TYPE (fromfn), TREE_TYPE (tofn), 1)
|| ! compparms (TREE_CHAIN (TYPE_ARG_TYPES (fromfn)),
TREE_CHAIN (TYPE_ARG_TYPES (tofn)), 1)
@@ -2056,7 +2067,10 @@ standard_conversion (to, from, expr)
&& ICS_STD_RANK (conv) < PBOOL_RANK)
ICS_STD_RANK (conv) = PBOOL_RANK;
}
- else if (INTEGRAL_CODE_P (tcode) || tcode == REAL_TYPE)
+ /* We don't check for ENUMERAL_TYPE here because there are no standard
+ conversions to enum type. */
+ else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
+ || tcode == REAL_TYPE)
{
if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
return 0;
@@ -2076,32 +2090,38 @@ standard_conversion (to, from, expr)
return 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.
+
+ Currently does not distinguish in the generated trees between binding to
+ an lvalue and a temporary. Should it? */
+
tree
-reference_binding (to, from, expr)
- tree to, from, expr;
+reference_binding (rto, from, expr)
+ tree rto, from, expr;
{
tree conv;
int lvalue = 1;
-
- to = TREE_TYPE (to);
+ tree to = TREE_TYPE (rto);
if (TREE_CODE (from) == REFERENCE_TYPE)
from = TREE_TYPE (from);
- else if (! expr || ! lvalue_p (expr))
+ else if (! expr || ! real_lvalue_p (expr))
lvalue = 0;
if (lvalue
&& TYPE_READONLY (to) >= TYPE_READONLY (from)
&& TYPE_VOLATILE (to) >= TYPE_VOLATILE (from))
{
- conv = build1 (EXACT_CONV, from, expr);
+ conv = build1 (IDENTITY_CONV, from, expr);
if (TYPE_MAIN_VARIANT (to) == TYPE_MAIN_VARIANT (from))
- conv = build_conv (REF_BIND, to, conv);
+ conv = build_conv (REF_BIND, rto, conv);
else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
&& DERIVED_FROM_P (to, from))
{
- conv = build_conv (REF_BIND, to, conv);
+ conv = build_conv (REF_BIND, rto, conv);
ICS_STD_RANK (conv) = STD_RANK;
}
else
@@ -2115,12 +2135,23 @@ reference_binding (to, from, expr)
conv = standard_conversion
(TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), expr);
if (conv)
- conv = build_conv (REF_BIND, to, conv);
+ {
+ conv = build_conv (REF_BIND, rto, conv);
+
+ /* Bind directly to a base subobject of a class rvalue. */
+ if (TREE_CODE (TREE_OPERAND (conv, 0)) == BASE_CONV)
+ TREE_OPERAND (conv, 0) = TREE_OPERAND (TREE_OPERAND (conv, 0), 0);
+ }
}
return conv;
}
+/* Returns the implicit conversion sequence (see [over.ics]) from type FROM
+ to type TO. The optional expression EXPR may affect the conversion.
+ FLAGS are the usual overloading flags. Only LOOKUP_NO_CONVERSION is
+ significant. */
+
tree
implicit_conversion (to, from, expr, flags)
tree to, from, expr;
@@ -2145,29 +2176,41 @@ implicit_conversion (to, from, expr, flags)
TYPE_MAIN_VARIANT (non_reference (from)), expr);
if (conv)
- ;
+ {
+ if (TREE_CODE (conv) == IDENTITY_CONV && IS_AGGR_TYPE (to)
+ && (TREE_CODE (from) == REFERENCE_TYPE || (expr && real_lvalue_p (expr))))
+ conv = build_conv (RVALUE_CONV, to, conv);
+ }
else if ((IS_AGGR_TYPE (non_reference (from))
|| IS_AGGR_TYPE (non_reference (to)))
&& (flags & LOOKUP_NO_CONVERSION) == 0)
{
- cand = build_user_type_conversion_1 (to, expr, LOOKUP_ONLYCONVERTING);
- if (cand)
- conv = cand->second_conv;
- else if (TREE_CODE (to) == REFERENCE_TYPE
- && TYPE_READONLY (TREE_TYPE (to))
- && ! TYPE_VOLATILE (TREE_TYPE (to)))
+ if (TREE_CODE (to) == REFERENCE_TYPE
+ && TYPE_READONLY (TREE_TYPE (to))
+ && ! TYPE_VOLATILE (TREE_TYPE (to)))
{
cand = build_user_type_conversion_1
(TYPE_MAIN_VARIANT (TREE_TYPE (to)), expr, LOOKUP_ONLYCONVERTING);
if (cand)
- conv = build_conv (REF_BIND, TREE_TYPE (to), cand->second_conv);
+ conv = build_conv (REF_BIND, to, cand->second_conv);
+ }
+ else
+ {
+ cand = build_user_type_conversion_1
+ (to, expr, LOOKUP_ONLYCONVERTING);
+ if (cand)
+ conv = cand->second_conv;
}
}
return conv;
}
-struct z_candidate *
+/* Create an overload candidate for the function or method FN called with
+ the argument list ARGLIST and add it to CANDIDATES. FLAGS is passed on
+ to implicit_conversion. */
+
+static struct z_candidate *
add_function_candidate (candidates, fn, arglist, flags)
struct z_candidate *candidates;
tree fn, arglist;
@@ -2181,6 +2224,8 @@ add_function_candidate (candidates, fn, arglist, flags)
int viable = 1;
struct z_candidate *cand;
+ /* The `this' and `in_chrg' arguments to constructors are not considered
+ in overload resolution. */
if (DECL_CONSTRUCTOR_P (fn))
{
parmnode = TREE_CHAIN (parmnode);
@@ -2203,7 +2248,82 @@ add_function_candidate (candidates, fn, arglist, flags)
t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg, flags);
else
{
- t = build1 (EXACT_CONV, argtype, arg);
+ t = build1 (IDENTITY_CONV, argtype, arg);
+ ICS_ELLIPSIS_FLAG (t) = 1;
+ }
+
+ TREE_VEC_ELT (convs, i) = t;
+ if (! t)
+ break;
+
+ if (parmnode)
+ parmnode = TREE_CHAIN (parmnode);
+ argnode = TREE_CHAIN (argnode);
+ }
+
+ if (i < len)
+ viable = 0;
+
+ /* Make sure there are default args for the rest of the parms. */
+ for (; parmnode && parmnode != void_list_node;
+ parmnode = TREE_CHAIN (parmnode))
+ if (! TREE_PURPOSE (parmnode))
+ {
+ viable = 0;
+ break;
+ }
+
+ cand = (struct z_candidate *) oballoc (sizeof (struct z_candidate));
+
+ cand->fn = fn;
+ cand->convs = convs;
+ cand->second_conv = NULL_TREE;
+ cand->viable = viable;
+ cand->basetype_path = NULL_TREE;
+ cand->template = NULL_TREE;
+ cand->next = candidates;
+
+ return cand;
+}
+
+/* Create an overload candidate for the conversion function FN which will
+ be invoked for expression OBJ, producing a pointer-to-function which
+ will in turn be called with the argument list ARGLIST, and add it to
+ CANDIDATES. FLAGS is passed on to implicit_conversion. */
+
+static struct z_candidate *
+add_conv_candidate (candidates, fn, obj, arglist)
+ struct z_candidate *candidates;
+ tree fn, obj, arglist;
+{
+ tree totype = TREE_TYPE (TREE_TYPE (fn));
+ tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (totype));
+ int i, len = list_length (arglist) + 1;
+ tree convs = make_tree_vec (len);
+ tree parmnode = parmlist;
+ tree argnode = arglist;
+ int viable = 1;
+ struct z_candidate *cand;
+ int flags = LOOKUP_NORMAL;
+
+ for (i = 0; i < len; ++i)
+ {
+ tree arg = i == 0 ? obj : TREE_VALUE (argnode);
+ tree argtype = TREE_TYPE (arg);
+ tree t;
+
+ argtype = cp_build_type_variant
+ (argtype, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
+
+ if (i == 0)
+ t = implicit_conversion (totype, argtype, arg, flags);
+ else if (parmnode == void_list_node)
+ break;
+ else if (parmnode)
+ t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg, flags);
+ else
+ {
+ t = build1 (IDENTITY_CONV, argtype, arg);
ICS_ELLIPSIS_FLAG (t) = 1;
}
@@ -2211,6 +2331,9 @@ add_function_candidate (candidates, fn, arglist, flags)
if (! t)
break;
+ if (i == 0)
+ continue;
+
if (parmnode)
parmnode = TREE_CHAIN (parmnode);
argnode = TREE_CHAIN (argnode);
@@ -2240,7 +2363,643 @@ add_function_candidate (candidates, fn, arglist, flags)
return cand;
}
-struct z_candidate *
+int
+ptr_complete_ob (t)
+ tree t;
+{
+ return (TREE_CODE (t) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (t)) != OFFSET_TYPE
+ && TREE_CODE (TREE_TYPE (t)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (t)) != VOID_TYPE
+ && TYPE_SIZE (complete_type (TREE_TYPE (t))) != NULL_TREE);
+}
+
+#define TYPE_PTRMEM_P(NODE) \
+ (TREE_CODE (NODE) == POINTER_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) == OFFSET_TYPE)
+#define TYPE_PTR_P(NODE) \
+ (TREE_CODE (NODE) == POINTER_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) != OFFSET_TYPE)
+#define TYPE_PTROB_P(NODE) \
+ (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) != VOID_TYPE)
+
+static struct z_candidate *
+build_builtin_candidate (candidates, fnname, type1, type2,
+ args, argtypes, flags)
+ struct z_candidate *candidates;
+ tree fnname, type1, type2, *args, *argtypes;
+ int flags;
+
+{
+ tree t, convs;
+ int viable = 1, i;
+ struct z_candidate *cand;
+ tree types[2];
+
+ types[0] = type1;
+ types[1] = type2;
+
+ convs = make_tree_vec (args[2] ? 3 : (args[1] ? 2 : 1));
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (! args[i])
+ break;
+
+ t = implicit_conversion (types[i], argtypes[i], args[i], flags);
+ if (! t)
+ {
+ viable = 0;
+ /* We need something for printing the candidate. */
+ t = build1 (IDENTITY_CONV, types[i], NULL_TREE);
+ }
+ TREE_VEC_ELT (convs, i) = t;
+ }
+
+ /* For COND_EXPR we rearranged the arguments; undo that now. */
+ if (args[2])
+ {
+ TREE_VEC_ELT (convs, 2) = TREE_VEC_ELT (convs, 1);
+ TREE_VEC_ELT (convs, 1) = TREE_VEC_ELT (convs, 0);
+ t = implicit_conversion (boolean_type_node, argtypes[2], args[2], flags);
+ if (t)
+ TREE_VEC_ELT (convs, 0) = t;
+ else
+ viable = 0;
+ }
+
+ cand = (struct z_candidate *) oballoc (sizeof (struct z_candidate));
+
+ cand->fn = fnname;
+ cand->convs = convs;
+ cand->second_conv = NULL_TREE;
+ cand->viable = viable;
+ cand->basetype_path = NULL_TREE;
+ cand->template = NULL_TREE;
+ cand->next = candidates;
+
+ return cand;
+}
+
+int
+is_complete (t)
+ tree t;
+{
+ return TYPE_SIZE (complete_type (t)) != NULL_TREE;
+}
+
+/* Create any builtin operator overload candidates for the operator in
+ question given the converted operand types TYPE1 and TYPE2. The other
+ args are passed through from add_builtin_candidates to
+ build_builtin_candidate. */
+
+static struct z_candidate *
+add_builtin_candidate (candidates, code, code2, fnname, type1, type2,
+ args, argtypes, flags)
+ struct z_candidate *candidates;
+ enum tree_code code, code2;
+ tree fnname, type1, type2, *args, *argtypes;
+ int flags;
+{
+ switch (code)
+ {
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ args[1] = integer_zero_node;
+ type2 = integer_type_node;
+ }
+
+ switch (code)
+ {
+
+/* 4 For every pair T, VQ), where T is an arithmetic or enumeration type,
+ and VQ is either volatile or empty, there exist candidate operator
+ functions of the form
+ VQ T& operator++(VQ T&);
+ T operator++(VQ T&, int);
+ 5 For every pair T, VQ), where T is an enumeration type or an arithmetic
+ type other than bool, and VQ is either volatile or empty, there exist
+ candidate operator functions of the form
+ VQ T& operator--(VQ T&);
+ T operator--(VQ T&, int);
+ 6 For every pair T, VQ), where T is a cv-qualified or cv-unqualified
+ complete object type, and VQ is either volatile or empty, there exist
+ candidate operator functions of the form
+ T*VQ& operator++(T*VQ&);
+ T*VQ& operator--(T*VQ&);
+ T* operator++(T*VQ&, int);
+ T* operator--(T*VQ&, int); */
+
+ case POSTDECREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ if (TREE_CODE (type1) == BOOLEAN_TYPE)
+ return candidates;
+ case POSTINCREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) || ptr_complete_ob (type1))
+ {
+ type1 = build_reference_type (type1);
+ break;
+ }
+ return candidates;
+
+/* 7 For every cv-qualified or cv-unqualified complete object type T, there
+ exist candidate operator functions of the form
+
+ T& operator*(T*);
+
+ 8 For every function type T, there exist candidate operator functions of
+ the form
+ T& operator*(T*); */
+
+ case INDIRECT_REF:
+ if (TREE_CODE (type1) == POINTER_TYPE
+ && (ptr_complete_ob (type1)
+ || TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE))
+ break;
+ return candidates;
+
+/* 9 For every type T, there exist candidate operator functions of the form
+ T* operator+(T*);
+
+ 10For every promoted arithmetic type T, there exist candidate operator
+ functions of the form
+ T operator+(T);
+ T operator-(T); */
+
+ case CONVERT_EXPR: /* unary + */
+ if (TREE_CODE (type1) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) != OFFSET_TYPE)
+ break;
+ case NEGATE_EXPR:
+ if (ARITHMETIC_TYPE_P (type1))
+ break;
+ return candidates;
+
+/* 11For every promoted integral type T, there exist candidate operator
+ functions of the form
+ T operator~(T); */
+
+ case BIT_NOT_EXPR:
+ if (INTEGRAL_TYPE_P (type1))
+ break;
+ return candidates;
+
+/* 12For every quintuple C1, C2, T, CV1, CV2), where C2 is a class type, C1
+ is the same type as C2 or is a derived class of C2, T is a complete
+ object type or a function type, and CV1 and CV2 are cv-qualifier-seqs,
+ there exist candidate operator functions of the form
+ CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
+ where CV12 is the union of CV1 and CV2. */
+
+ case MEMBER_REF:
+ if (TREE_CODE (type1) == POINTER_TYPE
+ && (TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2)))
+ {
+ tree c1 = TREE_TYPE (type1);
+ tree c2 = (TYPE_PTRMEMFUNC_P (type2)
+ ? TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (type2))
+ : TYPE_OFFSET_BASETYPE (TREE_TYPE (type2)));
+
+ if (IS_AGGR_TYPE (c1) && DERIVED_FROM_P (c2, c1)
+ && (TYPE_PTRMEMFUNC_P (type2)
+ || is_complete (TREE_TYPE (TREE_TYPE (type2)))))
+ break;
+ }
+ return candidates;
+
+/* 13For every pair of promoted arithmetic types L and R, there exist can-
+ didate operator functions of the form
+ LR operator*(L, R);
+ LR operator/(L, R);
+ LR operator+(L, R);
+ LR operator-(L, R);
+ bool operator<(L, R);
+ bool operator>(L, R);
+ bool operator<=(L, R);
+ bool operator>=(L, R);
+ bool operator==(L, R);
+ bool operator!=(L, R);
+ where LR is the result of the usual arithmetic conversions between
+ types L and R.
+
+ 14For every pair of types T and I, where T is a cv-qualified or cv-
+ unqualified complete object type and I is a promoted integral type,
+ there exist candidate operator functions of the form
+ T* operator+(T*, I);
+ T& operator[](T*, I);
+ T* operator-(T*, I);
+ T* operator+(I, T*);
+ T& operator[](I, T*);
+
+ 15For every T, where T is a pointer to complete object type, there exist
+ candidate operator functions of the form112)
+ ptrdiff_t operator-(T, T);
+
+ 16For every pointer type T, there exist candidate operator functions of
+ the form
+ bool operator<(T, T);
+ bool operator>(T, T);
+ bool operator<=(T, T);
+ bool operator>=(T, T);
+ bool operator==(T, T);
+ bool operator!=(T, T);
+
+ 17For every pointer to member type T, there exist candidate operator
+ functions of the form
+ bool operator==(T, T);
+ bool operator!=(T, T); */
+
+ case MINUS_EXPR:
+ if (ptr_complete_ob (type1) && ptr_complete_ob (type2))
+ break;
+ if (ptr_complete_ob (type1) && INTEGRAL_TYPE_P (type2))
+ {
+ type2 = ptrdiff_type_node;
+ break;
+ }
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ return candidates;
+
+ case EQ_EXPR:
+ case NE_EXPR:
+ if (TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2)
+ || TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
+ break;
+ if ((TYPE_PTRMEMFUNC_P (type1) || TYPE_PTRMEM_P (type1))
+ && null_ptr_cst (args[1]))
+ {
+ type2 = type1;
+ break;
+ }
+ if ((TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2))
+ && null_ptr_cst (args[0]))
+ {
+ type1 = type2;
+ break;
+ }
+ case LT_EXPR:
+ case GT_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2)
+ || TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
+ break;
+ if (TYPE_PTR_P (type1) && null_ptr_cst (args[1]))
+ {
+ type2 = type1;
+ break;
+ }
+ if (null_ptr_cst (args[0]) && TYPE_PTR_P (type2))
+ {
+ type1 = type2;
+ break;
+ }
+ return candidates;
+
+ case PLUS_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ case ARRAY_REF:
+ if (INTEGRAL_TYPE_P (type1) && ptr_complete_ob (type2))
+ {
+ type1 = ptrdiff_type_node;
+ break;
+ }
+ if (ptr_complete_ob (type1) && INTEGRAL_TYPE_P (type2))
+ {
+ type2 = ptrdiff_type_node;
+ break;
+ }
+ return candidates;
+
+/* 18For every pair of promoted integral types L and R, there exist candi-
+ date operator functions of the form
+ LR operator%(L, R);
+ LR operator&(L, R);
+ LR operator^(L, R);
+ LR operator|(L, R);
+ L operator<<(L, R);
+ L operator>>(L, R);
+ where LR is the result of the usual arithmetic conversions between
+ types L and R. */
+
+ case TRUNC_MOD_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
+ break;
+ return candidates;
+
+/* 19For every triple L, VQ, R), where L is an arithmetic or enumeration
+ type, VQ is either volatile or empty, and R is a promoted arithmetic
+ type, there exist candidate operator functions of the form
+ VQ L& operator=(VQ L&, R);
+ VQ L& operator*=(VQ L&, R);
+ VQ L& operator/=(VQ L&, R);
+ VQ L& operator+=(VQ L&, R);
+ VQ L& operator-=(VQ L&, R);
+
+ 20For every pair T, VQ), where T is any type and VQ is either volatile
+ or empty, there exist candidate operator functions of the form
+ T*VQ& operator=(T*VQ&, T*);
+
+ 21For every pair T, VQ), where T is a pointer to member type and VQ is
+ either volatile or empty, there exist candidate operator functions of
+ the form
+ VQ T& operator=(VQ T&, T);
+
+ 22For every triple T, VQ, I), where T is a cv-qualified or cv-
+ unqualified complete object type, VQ is either volatile or empty, and
+ I is a promoted integral type, there exist candidate operator func-
+ tions of the form
+ T*VQ& operator+=(T*VQ&, I);
+ T*VQ& operator-=(T*VQ&, I);
+
+ 23For every triple L, VQ, R), where L is an integral or enumeration
+ type, VQ is either volatile or empty, and R is a promoted integral
+ type, there exist candidate operator functions of the form
+
+ VQ L& operator%=(VQ L&, R);
+ VQ L& operator<<=(VQ L&, R);
+ VQ L& operator>>=(VQ L&, R);
+ VQ L& operator&=(VQ L&, R);
+ VQ L& operator^=(VQ L&, R);
+ VQ L& operator|=(VQ L&, R); */
+
+ case MODIFY_EXPR:
+ switch (code2)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ if (ptr_complete_ob (type1) && INTEGRAL_TYPE_P (type2))
+ {
+ type2 = ptrdiff_type_node;
+ break;
+ }
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ return candidates;
+
+ case TRUNC_MOD_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
+ break;
+ return candidates;
+
+ case NOP_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
+ || (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
+ || (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
+ || ((TYPE_PTRMEMFUNC_P (type1)
+ || TREE_CODE (type1) == POINTER_TYPE)
+ && null_ptr_cst (args[1])))
+ {
+ type2 = type1;
+ break;
+ }
+ return candidates;
+
+ default:
+ my_friendly_abort (367);
+ }
+ type1 = build_reference_type (type1);
+ break;
+
+ case COND_EXPR:
+ if (TREE_CODE (type1) == ENUMERAL_TYPE && type1 == type2)
+ break;
+ else if (TREE_CODE (type1) == ENUMERAL_TYPE
+ || TREE_CODE (type2) == ENUMERAL_TYPE)
+ return candidates;
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ if (TREE_CODE (type1) == TREE_CODE (type2)
+ && (TREE_CODE (type1) == REFERENCE_TYPE
+ || TREE_CODE (type1) == POINTER_TYPE
+ || TYPE_PTRMEMFUNC_P (type1)
+ || IS_AGGR_TYPE (type1)))
+ break;
+ if (TREE_CODE (type1) == REFERENCE_TYPE
+ || TREE_CODE (type2) == REFERENCE_TYPE)
+ return candidates;
+ if (((TYPE_PTRMEMFUNC_P (type1) || TREE_CODE (type1) == POINTER_TYPE)
+ && null_ptr_cst (args[1]))
+ || IS_AGGR_TYPE (type1))
+ {
+ type2 = type1;
+ break;
+ }
+ if (((TYPE_PTRMEMFUNC_P (type2) || TREE_CODE (type2) == POINTER_TYPE)
+ && null_ptr_cst (args[0]))
+ || IS_AGGR_TYPE (type2))
+ {
+ type1 = type2;
+ break;
+ }
+ return candidates;
+
+ default:
+ my_friendly_abort (367);
+ }
+
+ /* If we're dealing with two pointer types, we need candidates
+ for both of them. */
+ if (type2 && type1 != type2
+ && TREE_CODE (type1) == TREE_CODE (type2)
+ && (TREE_CODE (type1) == REFERENCE_TYPE
+ || TREE_CODE (type1) == POINTER_TYPE
+ || TYPE_PTRMEMFUNC_P (type1)
+ || IS_AGGR_TYPE (type1)))
+ {
+ candidates = build_builtin_candidate
+ (candidates, fnname, type1, type1, args, argtypes, flags);
+ return build_builtin_candidate
+ (candidates, fnname, type2, type2, args, argtypes, flags);
+ }
+
+ return build_builtin_candidate
+ (candidates, fnname, type1, type2, args, argtypes, flags);
+}
+
+tree
+type_decays_to (type)
+ tree type;
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return build_pointer_type (TREE_TYPE (type));
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ return build_pointer_type (type);
+ return type;
+}
+
+/* There are three conditions of builtin candidates:
+
+ 1) bool-taking candidates. These are the same regardless of the input.
+ 2) pointer-pair taking candidates. These are generated for each type
+ one of the input types converts to.
+ 3) arithmetic candidates. According to the WP, we should generate
+ all of these, but I'm trying not to... */
+
+static struct z_candidate *
+add_builtin_candidates (candidates, code, code2, fnname, args, flags)
+ struct z_candidate *candidates;
+ enum tree_code code, code2;
+ tree fnname, *args;
+ int flags;
+{
+ int ref1, i;
+ tree type, argtypes[3], types[2];
+
+ for (i = 0; i < 3; ++i)
+ {
+ if (args[i])
+ argtypes[i] = cp_build_type_variant
+ (TREE_TYPE (args[i]), TREE_READONLY (args[i]),
+ TREE_THIS_VOLATILE (args[i]));
+ else
+ argtypes[i] = NULL_TREE;
+ }
+
+ switch (code)
+ {
+/* 4 For every pair T, VQ), where T is an arithmetic or enumeration type,
+ and VQ is either volatile or empty, there exist candidate operator
+ functions of the form
+ VQ T& operator++(VQ T&); */
+
+ case POSTINCREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case MODIFY_EXPR:
+ ref1 = 1;
+ break;
+
+/* 24There also exist candidate operator functions of the form
+ bool operator!(bool);
+ bool operator&&(bool, bool);
+ bool operator||(bool, bool); */
+
+ case TRUTH_NOT_EXPR:
+ return build_builtin_candidate
+ (candidates, fnname, boolean_type_node,
+ NULL_TREE, args, argtypes, flags);
+
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ return build_builtin_candidate
+ (candidates, fnname, boolean_type_node,
+ boolean_type_node, args, argtypes, flags);
+
+ case ADDR_EXPR:
+ case COMPOUND_EXPR:
+ case COMPONENT_REF:
+ return candidates;
+
+ default:
+ ref1 = 0;
+ }
+
+ types[0] = types[1] = NULL_TREE;
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (! args[i])
+ ;
+ else if (IS_AGGR_TYPE (argtypes[i]))
+ {
+ tree convs = lookup_conversions (argtypes[i]);
+
+ if (code == COND_EXPR)
+ {
+ if (real_lvalue_p (args[i]))
+ types[i] = tree_cons
+ (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+
+ types[i] = tree_cons
+ (NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
+ }
+
+ else if (! convs || (i == 0 && code == MODIFY_EXPR))
+ return candidates;
+
+ for (; convs; convs = TREE_CHAIN (convs))
+ {
+ type = TREE_TYPE (TREE_TYPE (TREE_VALUE (convs)));
+
+ if (i == 0 && ref1
+ && (TREE_CODE (type) != REFERENCE_TYPE
+ || TYPE_READONLY (TREE_TYPE (type))))
+ continue;
+
+ if (code == COND_EXPR && TREE_CODE (type) == REFERENCE_TYPE)
+ types[i] = tree_cons (NULL_TREE, type, types[i]);
+
+ type = non_reference (type);
+ if (i != 0 || ! ref1)
+ {
+ type = type_decays_to (TYPE_MAIN_VARIANT (type));
+ if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+ types[i] = tree_cons (NULL_TREE, type, types[i]);
+ type = type_promotes_to (type);
+ }
+
+ if (! value_member (type, types[i]))
+ types[i] = tree_cons (NULL_TREE, type, types[i]);
+ }
+ }
+ else
+ {
+ if (code == COND_EXPR && real_lvalue_p (args[i]))
+ types[i] = tree_cons
+ (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+ type = non_reference (argtypes[i]);
+ if (i != 0 || ! ref1)
+ {
+ type = type_decays_to (TYPE_MAIN_VARIANT (type));
+ if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+ types[i] = tree_cons (NULL_TREE, type, types[i]);
+ type = type_promotes_to (type);
+ }
+ types[i] = tree_cons (NULL_TREE, type, types[i]);
+ }
+ }
+
+ for (; types[0]; types[0] = TREE_CHAIN (types[0]))
+ {
+ if (types[1])
+ for (type = types[1]; type; type = TREE_CHAIN (type))
+ candidates = add_builtin_candidate
+ (candidates, code, code2, fnname, TREE_VALUE (types[0]),
+ TREE_VALUE (type), args, argtypes, flags);
+ else
+ candidates = add_builtin_candidate
+ (candidates, code, code2, fnname, TREE_VALUE (types[0]),
+ NULL_TREE, args, argtypes, flags);
+ }
+
+ return candidates;
+}
+
+static struct z_candidate *
add_template_candidate (candidates, tmpl, arglist, flags)
struct z_candidate *candidates;
tree tmpl, arglist;
@@ -2254,7 +3013,7 @@ add_template_candidate (candidates, tmpl, arglist, flags)
i = type_unification (DECL_TEMPLATE_PARMS (tmpl), targs,
TYPE_ARG_TYPES (TREE_TYPE (tmpl)),
- arglist, &dummy, 0);
+ arglist, &dummy, 0, 0);
if (i != 0)
return candidates;
@@ -2267,7 +3026,7 @@ add_template_candidate (candidates, tmpl, arglist, flags)
return cand;
}
-int
+static int
any_viable (cands)
struct z_candidate *cands;
{
@@ -2277,7 +3036,7 @@ any_viable (cands)
return 0;
}
-struct z_candidate *
+static struct z_candidate *
splice_viable (cands)
struct z_candidate *cands;
{
@@ -2302,21 +3061,59 @@ build_this (obj)
return build_unary_op (ADDR_EXPR, obj, 0);
}
-void
+static void
print_z_candidates (candidates)
struct z_candidate *candidates;
{
- cp_error_at ("candidates are: %D", candidates->fn);
+ if (! candidates)
+ return;
+
+ if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
+ {
+ if (candidates->fn == ansi_opname [COND_EXPR])
+ cp_error ("candidates are: %D(%T, %T, %T) <builtin>", candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 2)));
+ else if (TREE_VEC_LENGTH (candidates->convs) == 2)
+ cp_error ("candidates are: %D(%T, %T) <builtin>", candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
+ else
+ cp_error ("candidates are: %D(%T) <builtin>", candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
+ }
+ else
+ cp_error_at ("candidates are: %D", candidates->fn);
candidates = candidates->next;
for (; candidates; candidates = candidates->next)
- cp_error_at (" %D", candidates->fn);
+ {
+ if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
+ {
+ if (candidates->fn == ansi_opname [COND_EXPR])
+ cp_error (" %D(%T, %T, %T) <builtin>",
+ candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 2)));
+ else if (TREE_VEC_LENGTH (candidates->convs) == 2)
+ cp_error (" %D(%T, %T) <builtin>", candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
+ else
+ cp_error (" %D(%T) <builtin>", candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
+ }
+ else
+ cp_error_at (" %D", candidates->fn);
+ }
}
/* Returns the best overload candidate to perform the requested
conversion. */
-struct z_candidate *
+static struct z_candidate *
build_user_type_conversion_1 (totype, expr, flags)
tree totype, expr;
int flags;
@@ -2328,7 +3125,8 @@ build_user_type_conversion_1 (totype, expr, flags)
if (IS_AGGR_TYPE (totype))
ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0);
- if (IS_AGGR_TYPE (fromtype))
+ if (IS_AGGR_TYPE (fromtype)
+ && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
convs = lookup_conversions (fromtype);
candidates = 0;
@@ -2345,7 +3143,7 @@ build_user_type_conversion_1 (totype, expr, flags)
continue;
candidates = add_function_candidate (candidates, ctors, args, flags);
- candidates->second_conv = build1 (EXACT_CONV, totype, NULL_TREE);
+ candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
candidates->basetype_path = TYPE_BINFO (totype);
}
@@ -2358,11 +3156,12 @@ build_user_type_conversion_1 (totype, expr, flags)
tree ics = implicit_conversion
(totype, TREE_TYPE (TREE_TYPE (fn)), 0, LOOKUP_NO_CONVERSION);
if (ics)
- {
- candidates = add_function_candidate (candidates, fn, args, flags);
- candidates->second_conv = ics;
- candidates->basetype_path = TREE_PURPOSE (convs);
- }
+ for (; fn; fn = DECL_CHAIN (fn))
+ {
+ candidates = add_function_candidate (candidates, fn, args, flags);
+ candidates->second_conv = ics;
+ candidates->basetype_path = TREE_PURPOSE (convs);
+ }
}
if (! any_viable (candidates))
@@ -2393,11 +3192,12 @@ build_user_type_conversion_1 (totype, expr, flags)
cand = candidates; /* any one will do */
cand->second_conv = build1 (AMBIG_CONV, totype, expr);
+ ICS_USER_FLAG (cand->second_conv) = 1;
return cand;
}
- for (p = &(cand->second_conv); TREE_CODE (*p) != EXACT_CONV; )
+ for (p = &(cand->second_conv); TREE_CODE (*p) != IDENTITY_CONV; )
p = &(TREE_OPERAND (*p, 0));
*p = build
@@ -2421,7 +3221,7 @@ build_user_type_conversion (totype, expr, flags)
{
if (TREE_CODE (cand->second_conv) == AMBIG_CONV)
return error_mark_node;
- return convert_like (cand->second_conv, expr);
+ return convert_from_reference (convert_like (cand->second_conv, expr));
}
return NULL_TREE;
}
@@ -2470,6 +3270,420 @@ build_new_function_call (fn, args, obj)
return build_function_call (fn, args);
}
+tree
+build_object_call (obj, args)
+ tree obj, args;
+{
+ struct z_candidate *candidates = 0, *cand;
+ tree fns, convs, mem_args, *p;
+ enum tree_code code2 = NOP_EXPR;
+ tree type = TREE_TYPE (obj);
+
+ fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname [CALL_EXPR], 0);
+
+ if (fns)
+ {
+ tree fn = TREE_VALUE (fns);
+ mem_args = tree_cons (NULL_TREE, build_this (obj), args);
+
+ for (; fn; fn = DECL_CHAIN (fn))
+ {
+ candidates = add_function_candidate
+ (candidates, fn, mem_args, LOOKUP_NORMAL);
+ candidates->basetype_path = TREE_PURPOSE (fns);
+ }
+ }
+
+ convs = lookup_conversions (type);
+
+ for (; convs; convs = TREE_CHAIN (convs))
+ {
+ tree fn = TREE_VALUE (convs);
+ tree totype = TREE_TYPE (TREE_TYPE (fn));
+
+ if (TREE_CODE (totype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
+ {
+ candidates = add_conv_candidate (candidates, fn, obj, args);
+ candidates->basetype_path = TREE_PURPOSE (convs);
+ }
+ }
+
+ if (! any_viable (candidates))
+ {
+ cp_error ("no viable candidates");
+ print_z_candidates (candidates);
+ return error_mark_node;
+ }
+
+ candidates = splice_viable (candidates);
+ cand = tourney (candidates, NULL_TREE);
+
+ if (cand == 0)
+ {
+ cp_error ("ambiguous object call");
+ print_z_candidates (candidates);
+ return error_mark_node;
+ }
+
+ if (DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR])
+ return build_over_call (cand->fn, cand->convs, mem_args, LOOKUP_NORMAL);
+
+ obj = convert_like (TREE_VEC_ELT (cand->convs, 0), obj);
+
+ /* FIXME */
+ return build_function_call (obj, args);
+}
+
+static void
+op_error (code, code2, arg1, arg2, arg3, problem)
+ enum tree_code code, code2;
+ tree arg1, arg2, arg3;
+ char *problem;
+{
+ char * opname
+ = (code == MODIFY_EXPR ? assignop_tab [code2] : opname_tab [code]);
+
+ switch (code)
+ {
+ case COND_EXPR:
+ cp_error ("%s for `%T ? %T : %T'", problem,
+ TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
+ break;
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ cp_error ("%s for `%T%s'", problem, TREE_TYPE (arg1), opname);
+ break;
+ case ARRAY_REF:
+ cp_error ("%s for `%T[%T]'", problem,
+ TREE_TYPE (arg1), TREE_TYPE (arg2));
+ break;
+ default:
+ if (arg2)
+ cp_error ("%s for `%T %s %T'", problem,
+ TREE_TYPE (arg1), opname, TREE_TYPE (arg2));
+ else
+ cp_error ("%s for `%s%T'", problem, opname, TREE_TYPE (arg1));
+ }
+}
+
+tree
+build_new_op (code, flags, arg1, arg2, arg3)
+ enum tree_code code;
+ int flags;
+ tree arg1, arg2, arg3;
+{
+ struct z_candidate *candidates = 0, *cand;
+ tree fns, mem_arglist, arglist, fnname, *p;
+ enum tree_code code2 = NOP_EXPR;
+
+ if (arg1 == error_mark_node)
+ return error_mark_node;
+
+ if (code == MODIFY_EXPR)
+ {
+ code2 = TREE_CODE (arg3);
+ arg3 = NULL_TREE;
+ fnname = ansi_assopname[code2];
+ }
+ else
+ fnname = ansi_opname[code];
+
+ switch (code)
+ {
+ case NEW_EXPR:
+ case VEC_NEW_EXPR:
+ {
+ tree rval;
+
+ arglist = tree_cons (NULL_TREE, arg2, arg3);
+ if (flags & LOOKUP_GLOBAL)
+ return build_new_function_call
+ (lookup_name_nonclass (fnname), arglist, NULL_TREE);
+
+ /* FIXME */
+ rval = build_method_call
+ (build_indirect_ref (build1 (NOP_EXPR, arg1, error_mark_node),
+ "new"),
+ fnname, arglist, NULL_TREE, flags);
+ if (rval == error_mark_node)
+ /* User might declare fancy operator new, but invoke it
+ like standard one. */
+ return rval;
+
+ TREE_TYPE (rval) = arg1;
+ TREE_CALLS_NEW (rval) = 1;
+ return rval;
+ }
+
+ case VEC_DELETE_EXPR:
+ case DELETE_EXPR:
+ {
+ tree rval;
+
+ if (flags & LOOKUP_GLOBAL)
+ return build_new_function_call
+ (lookup_name_nonclass (fnname),
+ build_tree_list (NULL_TREE, arg1), NULL_TREE);
+
+ arglist = tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
+
+ arg1 = TREE_TYPE (arg1);
+
+ /* This handles the case where we're trying to delete
+ X (*a)[10];
+ a=new X[5][10];
+ delete[] a; */
+
+ if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)
+ {
+ /* Strip off the pointer and the array. */
+ arg1 = TREE_TYPE (TREE_TYPE (arg1));
+
+ while (TREE_CODE (arg1) == ARRAY_TYPE)
+ arg1 = (TREE_TYPE (arg1));
+
+ arg1 = build_pointer_type (arg1);
+ }
+
+ /* FIXME */
+ rval = build_method_call
+ (build_indirect_ref (build1 (NOP_EXPR, arg1,
+ error_mark_node),
+ NULL_PTR),
+ fnname, arglist, NULL_TREE, flags);
+#if 0
+ /* This can happen when operator delete is protected. */
+ my_friendly_assert (rval != error_mark_node, 250);
+ TREE_TYPE (rval) = void_type_node;
+#endif
+ return rval;
+ }
+
+ case CALL_EXPR:
+ return build_object_call (arg1, arg2);
+ }
+
+ /* The comma operator can have void args. */
+ if (TREE_CODE (arg1) == OFFSET_REF)
+ arg1 = resolve_offset_ref (arg1);
+ if (arg2 && TREE_CODE (arg2) == OFFSET_REF)
+ arg2 = resolve_offset_ref (arg2);
+ if (arg3 && TREE_CODE (arg3) == OFFSET_REF)
+ arg3 = resolve_offset_ref (arg3);
+
+ if (! IS_OVERLOAD_TYPE (TREE_TYPE (arg1))
+ && (! arg2 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg2)))
+ && (! arg3 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg3))))
+ return NULL_TREE;
+
+ if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+ arg2 = integer_zero_node;
+
+ fns = lookup_name_nonclass (fnname);
+ /* + Koenig lookup */
+
+ if (arg2 && arg3)
+ arglist = tree_cons (NULL_TREE, arg1, tree_cons
+ (NULL_TREE, arg2, build_tree_list (NULL_TREE, arg3)));
+ else if (arg2)
+ arglist = tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
+ else
+ arglist = build_tree_list (NULL_TREE, arg1);
+
+ if (fns && TREE_CODE (fns) == TREE_LIST)
+ fns = TREE_VALUE (fns);
+ for (; fns; fns = DECL_CHAIN (fns))
+ {
+ if (TREE_CODE (fns) == TEMPLATE_DECL)
+ candidates = add_template_candidate (candidates, fns, arglist, flags);
+ else
+ candidates = add_function_candidate (candidates, fns, arglist, flags);
+ }
+
+ if (IS_AGGR_TYPE (TREE_TYPE (arg1)))
+ fns = lookup_fnfields (TYPE_BINFO (TREE_TYPE (arg1)), fnname, 0);
+ else
+ fns = NULL_TREE;
+
+ if (fns)
+ {
+ tree fn = TREE_VALUE (fns);
+ mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
+ for (; fn; fn = DECL_CHAIN (fn))
+ {
+ if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+ candidates = add_function_candidate
+ (candidates, fn, mem_arglist, flags);
+ else
+ candidates = add_function_candidate (candidates, fn, arglist, flags);
+
+ candidates->basetype_path = TREE_PURPOSE (fns);
+ }
+ }
+
+#if 0 /* Don't handle builtin COND_EXPR for now */
+ if (code != COND_EXPR)
+#endif
+ {
+ tree args[3];
+
+ /* Rearrange the arguments for ?: so that add_builtin_candidate only has
+ to know about two args; a builtin candidate will always have a first
+ parameter of type bool. We'll handle that in
+ build_builtin_candidate. */
+ if (code == COND_EXPR)
+ {
+ args[0] = arg2;
+ args[1] = arg3;
+ args[2] = arg1;
+ }
+ else
+ {
+ args[0] = arg1;
+ args[1] = arg2;
+ args[2] = NULL_TREE;
+ }
+
+ candidates = add_builtin_candidates
+ (candidates, code, code2, fnname, args, flags);
+ }
+
+ if (! any_viable (candidates))
+ {
+ switch (code)
+ {
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ /* Look for an `operator++ (int)'. If they didn't have
+ one, then we fall back to the old way of doing things. */
+ if (flags & LOOKUP_COMPLAIN)
+ cp_pedwarn ("no `%D (int)' declared for postfix `%s', trying prefix operator instead",
+ fnname, opname_tab [code]);
+ if (code == POSTINCREMENT_EXPR)
+ code = PREINCREMENT_EXPR;
+ else
+ code = PREDECREMENT_EXPR;
+ return build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE);
+
+ /* FIXME */
+ case ADDR_EXPR:
+ /*return build_unary_op (code, arg1, 1);*/
+ case COMPOUND_EXPR:
+ /*return build (COMPOUND_EXPR, TREE_TYPE (arg2),
+ break_out_cleanups (arg1), arg2);*/
+ case COMPONENT_REF:
+ /*return build_x_arrow (arg1);*/
+#if 0 /* Don't handle builtin COND_EXPR for now */
+ case COND_EXPR:
+#endif
+ return NULL_TREE;
+ }
+ if (flags & LOOKUP_COMPLAIN)
+ {
+ op_error (code, code2, arg1, arg2, arg3, "no match");
+ print_z_candidates (candidates);
+ }
+ return error_mark_node;
+ }
+ candidates = splice_viable (candidates);
+ cand = tourney (candidates, NULL_TREE);
+
+ if (cand == 0)
+ {
+ if (flags & LOOKUP_COMPLAIN)
+ {
+ op_error (code, code2, arg1, arg2, arg3, "ambiguous overload");
+ print_z_candidates (candidates);
+ }
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (cand->fn) == FUNCTION_DECL)
+ {
+ extern int warn_synth;
+ if (warn_synth
+ && fnname == ansi_opname[MODIFY_EXPR]
+ && DECL_ARTIFICIAL (cand->fn)
+ && candidates->next
+ && ! candidates->next->next)
+ {
+ cp_warning ("using synthesized `%#D' for copy assignment",
+ cand->fn);
+ cp_warning_at (" where cfront would use `%#D'",
+ cand == candidates
+ ? candidates->next->fn
+ : candidates->fn);
+ }
+
+ if (DECL_FUNCTION_MEMBER_P (cand->fn))
+ enforce_access (cand->basetype_path, cand->fn);
+
+ return build_over_call
+ (cand->fn, cand->convs,
+ TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
+ ? mem_arglist : arglist,
+ LOOKUP_NORMAL);
+ }
+
+ arg1 = convert_from_reference
+ (convert_like (TREE_VEC_ELT (cand->convs, 0), arg1));
+ if (arg2)
+ arg2 = convert_like (TREE_VEC_ELT (cand->convs, 1), arg2);
+ if (arg3)
+ arg3 = convert_like (TREE_VEC_ELT (cand->convs, 2), arg3);
+
+ switch (code)
+ {
+ case MODIFY_EXPR:
+ return build_modify_expr (arg1, code2, arg2);
+
+ case INDIRECT_REF:
+ return build_indirect_ref (arg1, "unary *");
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case GT_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case LE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case TRUNC_MOD_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ return build_binary_op_nodefault (code, arg1, arg2, code);
+
+ case CONVERT_EXPR:
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ return build_unary_op (code, arg1, 1);
+
+ case ARRAY_REF:
+ return build_array_ref (arg1, arg2);
+
+ case COND_EXPR:
+ return build_conditional_expr (arg1, arg2, arg3);
+
+ default:
+ my_friendly_abort (367);
+ }
+}
+
void
enforce_access (basetype_path, function)
tree basetype_path, function;
@@ -2492,7 +3706,9 @@ enforce_access (basetype_path, function)
}
}
-tree
+/* Perform the conversions in CONVS on the expression EXPR. */
+
+static tree
convert_like (convs, expr)
tree convs, expr;
{
@@ -2514,7 +3730,7 @@ convert_like (convs, expr)
return expr;
}
- case EXACT_CONV:
+ case IDENTITY_CONV:
if (type_unknown_p (expr))
expr = instantiate_type (TREE_TYPE (convs), expr, 1);
return expr;
@@ -2525,12 +3741,20 @@ convert_like (convs, expr)
};
expr = convert_like (TREE_OPERAND (convs, 0), expr);
+ if (expr == error_mark_node)
+ return error_mark_node;
+
switch (TREE_CODE (convs))
{
+ case BASE_CONV:
+ case RVALUE_CONV:
+ return build_user_type_conversion
+ (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
case REF_BIND:
return convert_to_reference
- (build_reference_type (TREE_TYPE (convs)), expr,
- CONV_IMPLICIT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION, error_mark_node);
+ (TREE_TYPE (convs), expr,
+ CONV_IMPLICIT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION|INDIRECT_BIND,
+ error_mark_node);
case LVALUE_CONV:
return decay_conversion (expr);
}
@@ -2538,7 +3762,7 @@ convert_like (convs, expr)
LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
}
-tree
+static tree
convert_default_arg (type, arg)
tree type, arg;
{
@@ -2569,15 +3793,15 @@ convert_default_arg (type, arg)
return arg;
}
-tree
+static tree
build_over_call (fn, convs, args, flags)
tree fn, convs, args;
int flags;
{
tree converted_args = NULL_TREE;
tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
- tree conv, arg;
- int i;
+ tree conv, arg, val;
+ int i = 0;
if (args && TREE_CODE (args) != TREE_LIST)
args = build_tree_list (NULL_TREE, args);
@@ -2605,14 +3829,23 @@ build_over_call (fn, convs, args, flags)
converted_args);
parm = TREE_CHAIN (parm);
arg = TREE_CHAIN (arg);
- conv = TREE_CHAIN (conv);
+ ++i;
}
- for (i = 0; conv = TREE_VEC_ELT (convs, i), arg && parm;
+ for (; conv = TREE_VEC_ELT (convs, i), arg && parm;
parm = TREE_CHAIN (parm), arg = TREE_CHAIN (arg), ++i)
- converted_args = tree_cons
- (NULL_TREE, convert_like (conv, TREE_VALUE (arg)),
- converted_args);
+ {
+ tree type = TREE_VALUE (parm);
+ val = convert_like (conv, TREE_VALUE (arg));
+
+#ifdef PROMOTE_PROTOTYPES
+ if ((TREE_CODE (type) == INTEGER_TYPE
+ || TREE_CODE (type) == ENUMERAL_TYPE)
+ && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ val = default_conversion (val);
+#endif
+ converted_args = tree_cons (NULL_TREE, val, converted_args);
+ }
/* Default arguments */
for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm))
@@ -2623,8 +3856,24 @@ build_over_call (fn, convs, args, flags)
/* Ellipsis */
for (; arg; arg = TREE_CHAIN (arg))
- converted_args = tree_cons
- (NULL_TREE, default_conversion (TREE_VALUE (arg)), converted_args);
+ {
+ 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 = convert (double_type_node, val);
+ else if (TYPE_LANG_SPECIFIC (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 = tree_cons (NULL_TREE, val, converted_args);
+ }
converted_args = nreverse (converted_args);
@@ -2648,8 +3897,10 @@ build_over_call (fn, convs, args, flags)
else
fn = build_addr_func (fn);
- return convert_from_reference
- (build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args));
+ fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args);
+ if (TREE_TYPE (fn) == void_type_node)
+ return fn;
+ return convert_from_reference (require_complete_type (fn));
}
/* Compare two implicit conversion sequences that differ only in their
@@ -2662,16 +3913,13 @@ compare_qual (ics1, ics2)
tree to1 = TREE_TYPE (ics1);
tree to2 = TREE_TYPE (ics2);
- if (TREE_CODE (ics1) != REF_BIND)
+ to1 = TREE_TYPE (to1);
+ to2 = TREE_TYPE (to2);
+
+ if (TREE_CODE (to1) == OFFSET_TYPE)
{
to1 = TREE_TYPE (to1);
to2 = TREE_TYPE (to2);
-
- if (TREE_CODE (to1) == OFFSET_TYPE)
- {
- to1 = TREE_TYPE (to1);
- to2 = TREE_TYPE (to2);
- }
}
if (TYPE_READONLY (to1) >= TYPE_READONLY (to2)
@@ -2696,7 +3944,7 @@ compare_qual (ics1, ics2)
-1: ics2 is better than ics1
0: ics1 and ics2 are indistinguishable */
-int
+static int
compare_ics (ics1, ics2)
tree ics1, ics2;
{
@@ -2718,9 +3966,11 @@ compare_ics (ics1, ics2)
tree t1, t2;
for (t1 = ics1; TREE_CODE (t1) != USER_CONV; t1 = TREE_OPERAND (t1, 0))
- ;
+ if (TREE_CODE (t1) == AMBIG_CONV)
+ return 0;
for (t2 = ics2; TREE_CODE (t2) != USER_CONV; t2 = TREE_OPERAND (t2, 0))
- ;
+ if (TREE_CODE (t2) == AMBIG_CONV)
+ return 0;
if (USER_CONV_FN (t1) != USER_CONV_FN (t2))
return 0;
@@ -2751,21 +4001,23 @@ compare_ics (ics1, ics2)
if (TREE_CODE (main1) != TREE_CODE (main2))
return 0;
- if (TREE_CODE (main1) == EXACT_CONV
+ if (TREE_CODE (main1) == IDENTITY_CONV
&& (TREE_CODE (TREE_TYPE (main1)) == POINTER_TYPE
|| TYPE_PTRMEMFUNC_P (TREE_TYPE (main1))))
{
if (TREE_TYPE (main1) == TREE_TYPE (main2))
return compare_qual (ics1, ics2);
+#if 0 /* This is now handled by making identity better than anything else. */
/* existing practice, not WP-endorsed: const char * -> const char *
is better than char * -> const char *. (jason 6/29/96) */
if (TREE_TYPE (ics1) == TREE_TYPE (ics2))
return -compare_qual (main1, main2);
+#endif
}
if (TREE_CODE (main1) == PTR_CONV || TREE_CODE (main1) == PMEM_CONV
- || TREE_CODE (main1) == REF_BIND)
+ || TREE_CODE (main1) == REF_BIND || TREE_CODE (main1) == BASE_CONV)
{
tree to1 = TREE_TYPE (main1);
tree from1 = TREE_TYPE (TREE_OPERAND (main1, 0));
@@ -2783,10 +4035,11 @@ compare_ics (ics1, ics2)
binding15). */
if (TREE_CODE (main1) == REF_BIND)
{
- if (TYPE_MAIN_VARIANT (to1) == TYPE_MAIN_VARIANT (to2))
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (to1))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (to2)))
return compare_qual (ics1, ics2);
}
- else if (from1 == from2 && to1 == to2)
+ else if (TREE_CODE (main1) != BASE_CONV && from1 == from2 && to1 == to2)
return compare_qual (ics1, ics2);
if (TYPE_PTRMEMFUNC_P (to1))
@@ -2794,10 +4047,11 @@ compare_ics (ics1, ics2)
to1 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (to1));
from1 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (from1));
}
- else if (TREE_CODE (main1) != REF_BIND)
+ else if (TREE_CODE (main1) != BASE_CONV)
{
to1 = TREE_TYPE (to1);
- from1 = TREE_TYPE (from1);
+ if (TREE_CODE (main1) != REF_BIND)
+ from1 = TREE_TYPE (from1);
if (TREE_CODE (to1) == OFFSET_TYPE)
{
@@ -2811,10 +4065,11 @@ compare_ics (ics1, ics2)
to2 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (to2));
from2 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (from2));
}
- else if (TREE_CODE (main2) != REF_BIND)
+ else if (TREE_CODE (main1) != BASE_CONV)
{
to2 = TREE_TYPE (to2);
- from2 = TREE_TYPE (from2);
+ if (TREE_CODE (main1) != REF_BIND)
+ from2 = TREE_TYPE (from2);
if (TREE_CODE (to2) == OFFSET_TYPE)
{
@@ -2826,6 +4081,14 @@ compare_ics (ics1, ics2)
if (! (IS_AGGR_TYPE (from1) && IS_AGGR_TYPE (from2)))
return 0;
+ /* The sense of pmem conversions is reversed from that of the other
+ conversions. */
+ if (TREE_CODE (main1) == PMEM_CONV)
+ {
+ tree t = from1; from1 = from2; from2 = t;
+ t = to1; to1 = to2; to2 = t;
+ }
+
distf = get_base_distance (from1, from2, 0, 0);
if (distf == -1)
{
@@ -2894,7 +4157,8 @@ compare_ics (ics1, ics2)
-1: cand2 is better than cand1
0: cand1 and cand2 are indistinguishable */
-int joust (cand1, cand2)
+static int
+joust (cand1, cand2)
struct z_candidate *cand1, *cand2;
{
int winner = 0;
@@ -2931,6 +4195,9 @@ int joust (cand1, cand2)
return 1;
else if (cand1->template && ! cand2->template)
return -1;
+ else if (cand1->template && cand2->template)
+ winner = more_specialized
+ (TI_TEMPLATE (cand1->template), TI_TEMPLATE (cand2->template));
/* or, if not that,
the context is an initialization by user-defined conversion (see
@@ -2940,9 +4207,21 @@ int joust (cand1, cand2)
sequence than the standard conversion sequence from the return type
of F2 to the destination type. */
- if (cand1->second_conv)
+ if (! winner && cand1->second_conv)
winner = compare_ics (cand1->second_conv, cand2->second_conv);
+ /* If the built-in candidates are the same, arbitrarily pick one. */
+ if (! winner && cand1->fn == cand2->fn
+ && TREE_CODE (cand1->fn) == IDENTIFIER_NODE)
+ {
+ for (i = 0; i < TREE_VEC_LENGTH (cand1->convs); ++i)
+ if (! comptypes (TREE_TYPE (TREE_VEC_ELT (cand1->convs, i)),
+ TREE_TYPE (TREE_VEC_ELT (cand2->convs, i)), 1))
+ break;
+ if (i == TREE_VEC_LENGTH (cand1->convs))
+ return 1;
+ }
+
return winner;
}
@@ -2951,7 +4230,7 @@ int joust (cand1, cand2)
case of O(n/2) (totally ambiguous); much better than a sorting
algorithm. */
-struct z_candidate *
+static struct z_candidate *
tourney (candidates)
struct z_candidate *candidates;
{
@@ -2995,4 +4274,3 @@ tourney (candidates)
return champ;
}
-#endif
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3ac5bb8beb6..6aa922f3f86 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -126,8 +126,6 @@ static struct stack_level *decl_stack;
static tree grokparms PROTO((tree, int));
static tree lookup_nested_type PROTO((tree, tree));
static char *redeclaration_error_message PROTO((tree, tree));
-extern void* push_eh_context PROTO(());
-extern void pop_eh_context PROTO((void *));
tree define_function
PROTO((char *, tree, enum built_in_function, void (*)(), char *));
@@ -5493,7 +5491,7 @@ init_decl_processing ()
init_search_processing ();
init_rtti_processing ();
- if (flag_handle_exceptions)
+ if (flag_exceptions)
init_exception_processing ();
if (flag_no_inline)
{
@@ -10892,7 +10890,6 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
current_function_parms_stored = 0;
original_result_rtx = NULL_RTX;
base_init_expr = NULL_TREE;
- protect_list = NULL_TREE;
current_base_init_list = NULL_TREE;
current_member_init_list = NULL_TREE;
ctor_label = dtor_label = NULL_TREE;
@@ -11092,7 +11089,11 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
= (interface_only
|| (DECL_THIS_INLINE (decl1) && ! flag_implement_inlines));
else
- DECL_EXTERNAL (decl1) = 0;
+ {
+ DECL_EXTERNAL (decl1) = 0;
+ if (DECL_C_STATIC (decl1))
+ TREE_PUBLIC (decl1) = 0;
+ }
DECL_NOT_REALLY_EXTERN (decl1) = 0;
DECL_INTERFACE_KNOWN (decl1) = 1;
}
@@ -11227,27 +11228,44 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
}
void
-expand_start_early_try_stmts ()
-{
- rtx insns;
- start_sequence ();
- expand_start_try_stmts ();
- insns = get_insns ();
- end_sequence ();
- store_in_parms (insns);
-}
-
-void
-store_in_parms (insns)
+store_after_parms (insns)
rtx insns;
{
- rtx last_parm_insn;
+ rtx x;
+
+ for (x = get_insns (); x; x = next_insn (x))
+ {
+ if (GET_CODE (x) == NOTE && NOTE_LINE_NUMBER (x) == NOTE_INSN_FUNCTION_BEG)
+ {
+ emit_insns_after (insns, x);
+ return;
+ }
+ }
+#if 0
+ /* This doesn't work, because the inline output routine doesn't reset
+ last_parm_insn correctly for get_first_nonparm_insn () to work. */
last_parm_insn = get_first_nonparm_insn ();
if (last_parm_insn == NULL_RTX)
emit_insns (insns);
else
- emit_insns_before (insns, previous_insn (last_parm_insn));
+ emit_insns_before (insns, last_parm_insn);
+#endif
+}
+
+void
+expand_start_early_try_stmts ()
+{
+ rtx insns;
+ start_sequence ();
+ expand_start_try_stmts ();
+ insns = get_insns ();
+ end_sequence ();
+#if 1
+ emit_insns_after (insns, get_insns ());
+#else
+ store_after_parms (insns);
+#endif
}
/* Store the parameter declarations into the current function declaration.
@@ -11395,23 +11413,27 @@ store_parm_decls ()
}
/* Take care of exception handling things. */
- if (! current_template_parms && flag_handle_exceptions)
+ if (! current_template_parms && flag_exceptions)
{
rtx insns;
start_sequence ();
+#if 0
/* Mark the start of a stack unwinder if we need one. */
start_eh_unwinder ();
+#endif
+#if 0
/* Do the starting of the exception specifications, if we have any. */
if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
expand_start_eh_spec ();
+#endif
insns = get_insns ();
end_sequence ();
if (insns)
- store_in_parms (insns);
+ store_after_parms (insns);
}
last_dtor_insn = get_last_insn ();
}
@@ -11915,7 +11937,7 @@ finish_function (lineno, call_poplevel, nested)
/* Generate rtl for function exit. */
expand_function_end (input_filename, lineno, 1);
- if (flag_handle_exceptions)
+ if (flag_exceptions)
expand_exception_blocks ();
}
@@ -12478,7 +12500,6 @@ struct cp_function
tree ctor_label;
tree dtor_label;
rtx last_dtor_insn;
- tree protect_list;
tree base_init_list;
tree member_init_list;
tree base_init_expr;
@@ -12487,7 +12508,6 @@ struct cp_function
rtx result_rtx;
struct cp_function *next;
struct binding_level *binding_level;
- void* eh_context;
};
@@ -12525,14 +12545,11 @@ push_cp_function_context (context)
p->parms_stored = current_function_parms_stored;
p->result_rtx = original_result_rtx;
p->base_init_expr = base_init_expr;
- p->protect_list = protect_list;
p->temp_name_counter = temp_name_counter;
p->base_init_list = current_base_init_list;
p->member_init_list = current_member_init_list;
p->current_class_ptr = current_class_ptr;
p->current_class_ref = current_class_ref;
-
- p->eh_context = push_eh_context ();
}
/* Restore the variables used during compilation of a C++ function. */
@@ -12563,7 +12580,6 @@ pop_cp_function_context (context)
ctor_label = p->ctor_label;
dtor_label = p->dtor_label;
last_dtor_insn = p->last_dtor_insn;
- protect_list = p->protect_list;
current_function_assigns_this = p->assigns_this;
current_function_just_assigned_this = p->just_assigned_this;
current_function_parms_stored = p->parms_stored;
@@ -12575,8 +12591,6 @@ pop_cp_function_context (context)
current_class_ptr = p->current_class_ptr;
current_class_ref = p->current_class_ref;
- pop_eh_context (p->eh_context);
-
free (p);
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 389cd06571b..632ce767c03 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -155,7 +155,7 @@ int warn_implicit = 1;
int warn_ctor_dtor_privacy = 1;
/* True if we want to implement vtables using "thunks".
- The default is off by default, on if explicitly supported. */
+ The default is off. */
int flag_vtable_thunks;
@@ -301,11 +301,6 @@ int write_virtuals;
int flag_elide_constructors;
-/* Nonzero means recognize and handle exception handling constructs.
- Use ansi syntax and semantics. WORK IN PROGRESS! */
-
-int flag_handle_exceptions;
-
/* Nonzero means recognize and handle signature language constructs. */
int flag_handle_signatures;
@@ -405,7 +400,6 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"all-virtual", &flag_all_virtual, 1},
{"memoize-lookups", &flag_memoize_lookups, 1},
{"elide-constructors", &flag_elide_constructors, 1},
- {"handle-exceptions", &flag_handle_exceptions, 1},
{"handle-signatures", &flag_handle_signatures, 1},
{"default-inline", &flag_default_inline, 1},
{"dollars-in-identifiers", &dollars_in_ident, 1},
@@ -2542,10 +2536,6 @@ import_export_vtable (decl, type, final)
TREE_PUBLIC (decl) = 1;
DECL_WEAK (decl) = 1;
}
-#ifdef ASM_OUTPUT_EXTERNAL
- else if (TREE_PUBLIC (decl))
- cp_error ("all virtual functions redeclared inline");
-#endif
else
TREE_PUBLIC (decl) = 0;
DECL_EXTERNAL (decl) = 0;
@@ -2995,7 +2985,7 @@ finish_file ()
vars = static_aggregates;
- if (static_ctors || vars || might_have_exceptions_p ())
+ if (static_ctors || vars || exception_table_p ())
needs_messing_up = 1;
if (static_dtors)
needs_cleaning = 1;
@@ -3096,7 +3086,7 @@ finish_file ()
push_momentary ();
expand_start_bindings (0);
- if (might_have_exceptions_p ())
+ if (exception_table_p ())
register_exception_table ();
while (vars)
@@ -3318,9 +3308,6 @@ finish_file ()
TREE_PUBLIC (vars) = 0;
}
- if (might_have_exceptions_p ())
- emit_exception_table ();
-
if (write_virtuals == 2)
{
/* Now complain about an virtual function tables promised
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 9d68c5e2a8a..4dd7e6096d3 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -720,6 +720,8 @@ dump_decl (t, v)
if (TREE_CODE (DECL_TEMPLATE_RESULT (t)) == TYPE_DECL)
dump_type (TREE_TYPE (t), v);
+ else if (TREE_TYPE (t) == NULL_TREE)
+ my_friendly_abort (353);
else switch (NEXT_CODE (t))
{
case METHOD_TYPE:
@@ -738,7 +740,7 @@ dump_decl (t, v)
break;
case CONST_DECL:
- if (NEXT_CODE (t) == ENUMERAL_TYPE
+ if ((TREE_TYPE (t) != NULL_TREE && NEXT_CODE (t) == ENUMERAL_TYPE)
|| TREE_CODE (DECL_INITIAL (t)) == TEMPLATE_CONST_PARM)
goto general;
else
@@ -1075,7 +1077,7 @@ dump_expr (t, nop)
if (TREE_CODE (fn) == ADDR_EXPR)
fn = TREE_OPERAND (fn, 0);
- if (NEXT_CODE (fn) == METHOD_TYPE)
+ if (TREE_TYPE (fn) != NULL_TREE && NEXT_CODE (fn) == METHOD_TYPE)
{
tree ob = TREE_VALUE (args);
if (TREE_CODE (ob) == ADDR_EXPR)
@@ -1198,7 +1200,8 @@ dump_expr (t, nop)
}
else
{
- if (NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
+ if (TREE_OPERAND (t,0) != NULL_TREE
+ && NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
dump_expr (TREE_OPERAND (t, 0), nop);
else
dump_unary_op ("*", t, nop);
@@ -1225,7 +1228,7 @@ dump_expr (t, nop)
/* FIXME: This is a KLUDGE workaround for a parsing problem. There
should be another level of INDIRECT_REF so that I don't have to do
this. */
- if (NEXT_CODE (t) == POINTER_TYPE)
+ if (TREE_TYPE (t) != NULL_TREE && NEXT_CODE (t) == POINTER_TYPE)
{
tree next = TREE_TYPE (TREE_TYPE (t));
@@ -1251,7 +1254,7 @@ dump_expr (t, nop)
case CONSTRUCTOR:
OB_PUTC ('{');
- dump_expr_list (CONSTRUCTOR_ELTS (t), 0);
+ dump_expr_list (CONSTRUCTOR_ELTS (t));
OB_PUTC ('}');
break;
@@ -1296,7 +1299,7 @@ dump_expr (t, nop)
{
dump_type (TREE_TYPE (t), 0);
OB_PUTC ('(');
- dump_expr_list (TREE_OPERAND (t, 0), 0);
+ dump_expr_list (TREE_OPERAND (t, 0));
OB_PUTC (')');
}
else
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 03c4e71d3f8..1d207e54664 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1,5 +1,5 @@
/* Handle exceptional things in C++.
- Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 92-95, 1996 Free Software Foundation, Inc.
Contributed by Michael Tiemann <tiemann@cygnus.com>
Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
initial re-implementation courtesy Tad Hunt.
@@ -22,8 +22,6 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
-
#include "config.h"
#include "tree.h"
#include "rtl.h"
@@ -32,48 +30,13 @@ Boston, MA 02111-1307, USA. */
#include "obstack.h"
#include "expr.h"
#include "output.h"
+#include "except.h"
+#include "function.h"
-tree protect_list;
-
-extern void (*interim_eh_hook) PROTO((tree));
rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
-static void end_eh_unwinder PROTO((rtx));
/* holds the fndecl for __builtin_return_address () */
tree builtin_return_address_fndecl;
-tree throw_fndecl;
-
-static int
-doing_eh (do_warn)
- int do_warn;
-{
- if (! flag_handle_exceptions)
- {
- static int warned = 0;
- if (! warned && do_warn)
- {
- error ("exception handling disabled, use -fhandle-exceptions to enable.");
- warned = 1;
- }
- return 0;
- }
- return 1;
-}
-
-
-/*
-NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
-to supporting exception handling as per ANSI C++ working draft.
-It is a complete rewrite of all the EH stuff that was here before
- Shortcomings:
- 1. Throw specifications of functions still don't work.
- Cool Things:
- 1. Destructors are called properly :-)
- 2. No overhead for the non-exception thrown case.
- 3. Fixing shortcoming 1 is simple.
- -Tad Hunt (tad@mail.csh.rit.edu)
-
-*/
/* A couple of backend routines from m88k.c */
@@ -83,20 +46,6 @@ static tree BuiltinReturnAddress;
#include <stdio.h>
-/* XXX - Tad: for EH */
-/* output an exception table entry */
-
-static void
-output_exception_table_entry (file, start_label, end_label, eh_label)
- FILE *file;
- rtx start_label, end_label, eh_label;
-{
- assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
- assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
- assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
- putc ('\n', file); /* blank line */
-}
-
static void
easy_expand_asm (str)
char *str;
@@ -115,8 +64,8 @@ easy_expand_asm (str)
#ifdef EXCEPT_SECTION_ASM_OP
typedef struct {
- void *start_protect;
- void *end_protect;
+ void *start_region;
+ void *end_region;
void *exception_handler;
} exception_table;
#endif /* EXCEPT_SECTION_ASM_OP */
@@ -145,45 +94,9 @@ asm (TEXT_SECTION_ASM_OP);
#endif
-static void
-exception_section ()
-{
-#ifdef ASM_OUTPUT_SECTION_NAME
- named_section (NULL_TREE, ".gcc_except_table");
-#else
- if (flag_pic)
- data_section ();
- else
-#if defined (TARGET_POWERPC) /* are we on a __rs6000? */
- data_section ();
-#else
- readonly_data_section ();
-#endif
-#endif
-}
-
-
-
-
-/* from: my-cp-except.c */
-
-/* VI: ":set ts=4" */
-#if 0
-#include <stdio.h> */
-#include "config.h"
-#include "tree.h"
-#include "rtl.h"
-#include "cp-tree.h"
-#endif
#include "decl.h"
-#if 0
-#include "flags.h"
-#endif
#include "insn-flags.h"
#include "obstack.h"
-#if 0
-#include "expr.h"
-#endif
/* ======================================================================
Briefly the algorithm works like this:
@@ -194,15 +107,15 @@ exception_section ()
output to start the protection for that block.
When a destructor or end try block is encountered, pop_eh_entry
- (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
- created when push_eh_entry () was called. The ehEntry structure
+ (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
+ created when push_eh_entry () was called. The eh_entry structure
contains three things at this point. The start protect label,
the end protect label, and the exception handler label. The end
protect label should be output before the call to the destructor
(if any). If it was a destructor, then its parse tree is stored
- in the finalization variable in the ehEntry structure. Otherwise
+ in the finalization variable in the eh_entry structure. Otherwise
the finalization variable is set to NULL to reflect the fact that
- is the the end of a try block. Next, this modified ehEntry node
+ is the the end of a try block. Next, this modified eh_entry node
is enqueued in the finalizations queue by calling
enqueue_eh_entry (&queue,entry).
@@ -231,12 +144,12 @@ exception_section ()
any of those finalizations throw an exception, we must call
terminate according to the ARM (section r.15.6.1). What this
means is that we need to dequeue and emit finalizations for each
- entry in the ehQueue until we get to an entry with a NULL
+ entry in the eh_queue until we get to an entry with a NULL
finalization field. For any of the finalization entries, if it
is not a call to terminate (), we must protect it by giving it
another start label, end label, and exception handler label,
setting its finalization tree to be a call to terminate (), and
- enqueue'ing this new ehEntry to be output at an outer level.
+ enqueue'ing this new eh_entry to be output at an outer level.
Finally, after all that is done, we can get around to outputting
the catch block which basically wraps all the "catch (...) {...}"
statements in a big if/then/else construct that matches the
@@ -252,7 +165,7 @@ extern rtx gen_nop PROTO(());
/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
"set_unexpected ()" after default_conversion. (lib-except.c) */
-static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw;
+static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
/* used to cache __find_first_exception_table_match ()
for throw (lib-except.c) */
@@ -269,46 +182,6 @@ static tree empty_fndecl;
/* ====================================================================== */
-
-/* data structures for my various quick and dirty stacks and queues
- Eventually, most of this should go away, because I think it can be
- integrated with stuff already built into the compiler. */
-
-/* =================================================================== */
-
-struct labelNode {
- union {
- rtx rlabel;
- tree tlabel;
- } u;
- struct labelNode *chain;
-};
-
-
-/* this is the most important structure here. Basically this is how I store
- an exception table entry internally. */
-struct ehEntry {
- rtx start_label;
- rtx end_label;
- rtx exception_handler_label;
-
- tree finalization;
- tree context;
-};
-
-struct ehNode {
- struct ehEntry *entry;
- struct ehNode *chain;
-};
-
-struct ehStack {
- struct ehNode *top;
-};
-
-struct ehQueue {
- struct ehNode *head;
- struct ehNode *tail;
-};
/* ========================================================================= */
@@ -329,264 +202,13 @@ static tree saved_cleanup;
/* Indicates if we are in a catch clause. */
static tree saved_in_catch;
-static int throw_used;
+extern int throw_used;
+extern rtx catch_clauses;
-static rtx catch_clauses;
-
-static struct ehStack ehstack;
-static struct ehQueue ehqueue;
-static struct ehQueue eh_table_output_queue;
-static struct labelNode *false_label_stack = NULL;
-static struct labelNode *caught_return_label_stack = NULL;
/* ========================================================================= */
-/* function prototypes */
-static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
-static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
-static rtx push_eh_entry PROTO((struct ehStack *stack));
-static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
-static void new_eh_queue PROTO((struct ehQueue *queue));
-static void new_eh_stack PROTO((struct ehStack *stack));
-static void push_label_entry PROTO((struct labelNode **labelstack, rtx rlabel, tree tlabel));
-static rtx pop_label_entry PROTO((struct labelNode **labelstack));
-static tree top_label_entry PROTO((struct labelNode **labelstack));
-static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
-
-
-/* Routines to save and restore eh context information. */
-struct eh_context {
- struct ehStack ehstack;
- struct ehQueue ehqueue;
- rtx catch_clauses;
- struct labelNode *false_label_stack;
- struct labelNode *caught_return_label_stack;
- tree protect_list;
-};
-
-/* Save the context and push into a new one. */
-void*
-push_eh_context ()
-{
- struct eh_context *p
- = (struct eh_context*)xmalloc (sizeof (struct eh_context));
-
- p->ehstack = ehstack;
- p->ehqueue = ehqueue;
- p->catch_clauses = catch_clauses;
- p->false_label_stack = false_label_stack;
- p->caught_return_label_stack = caught_return_label_stack;
- p->protect_list = protect_list;
-
- new_eh_stack (&ehstack);
- new_eh_queue (&ehqueue);
- catch_clauses = NULL_RTX;
- false_label_stack = NULL;
- caught_return_label_stack = NULL;
- protect_list = NULL_TREE;
-
- return p;
-}
-
-/* Pop and restore the context. */
-void
-pop_eh_context (vp)
- void *vp;
-{
- struct eh_context *p = (struct eh_context *)vp;
-
- protect_list = p->protect_list;
- caught_return_label_stack = p->caught_return_label_stack;
- false_label_stack = p->false_label_stack;
- catch_clauses = p->catch_clauses;
- ehqueue = p->ehqueue;
- ehstack = p->ehstack;
-
- free (p);
-}
-
-
-
-/* All my cheesy stack/queue/misc data structure handling routines
-
- ========================================================================= */
-
-static void
-push_label_entry (labelstack, rlabel, tlabel)
- struct labelNode **labelstack;
- rtx rlabel;
- tree tlabel;
-{
- struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
-
- if (rlabel)
- newnode->u.rlabel = rlabel;
- else
- newnode->u.tlabel = tlabel;
- newnode->chain = *labelstack;
- *labelstack = newnode;
-}
-
-static rtx
-pop_label_entry (labelstack)
- struct labelNode **labelstack;
-{
- rtx label;
- struct labelNode *tempnode;
-
- if (! *labelstack) return NULL_RTX;
-
- tempnode = *labelstack;
- label = tempnode->u.rlabel;
- *labelstack = (*labelstack)->chain;
- free (tempnode);
-
- return label;
-}
-
-static tree
-top_label_entry (labelstack)
- struct labelNode **labelstack;
-{
- if (! *labelstack) return NULL_TREE;
-
- return (*labelstack)->u.tlabel;
-}
-
-/* Push to permanent obstack for rtl generation.
- One level only! */
-static struct obstack *saved_rtl_obstack;
-
-static void
-push_rtl_perm ()
-{
- extern struct obstack permanent_obstack;
- extern struct obstack *rtl_obstack;
-
- saved_rtl_obstack = rtl_obstack;
- rtl_obstack = &permanent_obstack;
-}
-
-/* Pop back to normal rtl handling. */
-static void
-pop_rtl_from_perm ()
-{
- extern struct obstack *rtl_obstack;
- rtl_obstack = saved_rtl_obstack;
-}
-
-static rtx
-push_eh_entry (stack)
- struct ehStack *stack;
-{
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
- struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
-
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry->start_label = gen_label_rtx ();
- entry->end_label = gen_label_rtx ();
- entry->exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
-
- LABEL_PRESERVE_P (entry->start_label) = 1;
- LABEL_PRESERVE_P (entry->end_label) = 1;
- LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
-
- entry->finalization = NULL_TREE;
- entry->context = current_function_decl;
-
- node->entry = entry;
- node->chain = stack->top;
- stack->top = node;
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
-
- return entry->start_label;
-}
-
-/* Pop an entry from the given STACK. */
-static struct ehEntry *
-pop_eh_entry (stack)
- struct ehStack *stack;
-{
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
-
- tempnode = stack->top;
- tempentry = tempnode->entry;
- stack->top = stack->top->chain;
- free (tempnode);
-
- return tempentry;
-}
-
-static struct ehEntry *
-copy_eh_entry (entry)
- struct ehEntry *entry;
-{
- struct ehEntry *newentry;
-
- newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
- memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
-
- return newentry;
-}
-
-static void
-enqueue_eh_entry (queue, entry)
- struct ehQueue *queue;
- struct ehEntry *entry;
-{
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
-
- node->entry = entry;
- node->chain = NULL;
-
- if (queue->head == NULL)
- {
- queue->head = node;
- }
- else
- {
- queue->tail->chain = node;
- }
- queue->tail = node;
-}
-
-static struct ehEntry *
-dequeue_eh_entry (queue)
- struct ehQueue *queue;
-{
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
-
- if (queue->head == NULL)
- return NULL;
+/* Cheesyness to save some typing. Returns the return value rtx. */
- tempnode = queue->head;
- queue->head = queue->head->chain;
-
- tempentry = tempnode->entry;
- free (tempnode);
-
- return tempentry;
-}
-
-static void
-new_eh_queue (queue)
- struct ehQueue *queue;
-{
- queue->head = queue->tail = NULL;
-}
-
-static void
-new_eh_stack (stack)
- struct ehStack *stack;
-{
- stack->top = NULL;
-}
-
-/* cheesyness to save some typing. returns the return value rtx */
static rtx
do_function_call (func, params, return_type)
tree func, params, return_type;
@@ -599,42 +221,15 @@ do_function_call (func, params, return_type)
return NULL_RTX;
}
-static void
-expand_internal_throw (pc)
- rtx pc;
-{
- emit_move_insn (DECL_RTL (saved_pc), pc);
-#ifdef JUMP_TO_THROW
- emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
-#else
- do_function_call (Throw, NULL_TREE, NULL_TREE);
-#endif
- throw_used = 1;
-}
-
/* ========================================================================= */
-static void
-lang_interim_eh (finalization)
- tree finalization;
-{
- if (finalization)
- end_protect (finalization);
- else
- start_protect ();
-}
-
extern tree auto_function PROTO((tree, tree, enum built_in_function));
/* sets up all the global eh stuff that needs to be initialized at the
start of compilation.
This includes:
- - Setting up all the function call trees
- - Initializing the ehqueue
- - Initializing the eh_table_output_queue
- - Initializing the ehstack
-*/
+ - Setting up all the function call trees. */
void
init_exception_processing ()
@@ -671,8 +266,6 @@ init_exception_processing ()
terminate_fndecl = auto_function (get_identifier ("terminate"),
vtype, NOT_BUILT_IN);
- interim_eh_hook = lang_interim_eh;
-
push_lang_context (lang_name_c);
catch_match_fndecl =
@@ -697,12 +290,6 @@ init_exception_processing ()
tree_cons (NULL_TREE, ptr_type_node,
void_list_node)),
NOT_BUILT_IN, NULL_PTR);
- throw_fndecl =
- builtin_function ("__throw",
- build_function_type (void_type_node, void_list_node),
- NOT_BUILT_IN, NULL_PTR);
- DECL_EXTERNAL (throw_fndecl) = 0;
- TREE_PUBLIC (throw_fndecl) = 0;
empty_fndecl =
builtin_function ("__empty",
build_function_type (void_type_node, void_list_node),
@@ -717,17 +304,12 @@ init_exception_processing ()
CatchMatch = default_conversion (catch_match_fndecl);
FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
Unwind = default_conversion (unwind_fndecl);
- Throw = default_conversion (throw_fndecl);
BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
pop_lang_context ();
- new_eh_queue (&ehqueue);
- new_eh_queue (&eh_table_output_queue);
- new_eh_stack (&ehstack);
-
declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
d = start_decl (d, declspecs, 0, NULL_TREE);
@@ -765,150 +347,26 @@ init_exception_processing ()
saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
}
-/* call this to begin a block of unwind protection (ie: when an object is
- constructed) */
-void
-start_protect ()
-{
- if (! doing_eh (0))
- return;
-
- emit_label (push_eh_entry (&ehstack));
-}
-
-/* call this to end a block of unwind protection. the finalization tree is
- the finalization which needs to be run in order to cleanly unwind through
- this level of protection. (ie: call this when a scope is exited)*/
-void
-end_protect (finalization)
- tree finalization;
-{
- struct ehEntry *entry;
-
- if (! doing_eh (0))
- return;
-
- entry = pop_eh_entry (&ehstack);
-
- emit_label (entry->end_label);
- /* Put in something that takes up space, as otherwise the end
- address for the EH region could have the exact same address as
- the outer region, causing us to miss the fact that resuming
- exception handling with this PC value would be inside the outer
- region. */
- emit_insn (gen_nop ());
-
- entry->finalization = finalization;
+/* Call this on start of a try block. */
- enqueue_eh_entry (&ehqueue, entry);
-}
-
-/* call this on start of a try block. */
void
expand_start_try_stmts ()
{
if (! doing_eh (1))
return;
- start_protect ();
+ expand_eh_region_start ();
}
void
expand_end_try_stmts ()
{
- end_protect (integer_zero_node);
-}
-
-
-/* call this to start processing of all the catch blocks. */
-void
-expand_start_all_catch ()
-{
- struct ehEntry *entry;
- tree label;
-
- if (! doing_eh (1))
- return;
-
- emit_line_note (input_filename, lineno);
- label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- /* The label for the exception handling block we will save. This is
- Lresume, in the documention. */
- expand_label (label);
-
- /* Put in something that takes up space, as otherwise the end
- address for the EH region could have the exact same address as
- the outer region, causing us to miss the fact that resuming
- exception handling with this PC value would be inside the outer
- region. */
- emit_insn (gen_nop ());
-
- push_label_entry (&caught_return_label_stack, NULL_RTX, label);
-
- /* Start a new sequence for all the catch blocks. We will add this
- to the gloabl sequence catch_clauses, when we have completed all
- the handlers in this handler-seq. */
- start_sequence ();
-
- while (1)
- {
- entry = dequeue_eh_entry (&ehqueue);
- emit_label (entry->exception_handler_label);
-
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
- /* When we get down to the matching entry, stop. */
- if (entry->finalization == integer_zero_node)
- break;
-
- /* The below can be optimized away, and we could just fall into the
- next EH handler, if we are certain they are nested. */
- /* Code to throw out to outer context, if we fall off end of the
- handler. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- entry->end_label));
- free (entry);
- }
-}
-
-/* call this to end processing of all the catch blocks. */
-void
-expand_end_all_catch ()
-{
- rtx new_catch_clause;
-
- if (! doing_eh (1))
- return;
-
- /* Code to throw out to outer context, if we fall off end of catch
- handlers. This is rethrow (Lresume, same id, same obj); in the
- documentation. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- DECL_RTL (top_label_entry (&caught_return_label_stack))));
-
- /* Now we have the complete catch sequence. */
- new_catch_clause = get_insns ();
- end_sequence ();
-
- /* this level of catch blocks is done, so set up the successful catch jump
- label for the next layer of catch blocks. */
- pop_label_entry (&caught_return_label_stack);
-
- /* Add the new sequence of catchs to the main one for this
- function. */
- push_to_sequence (catch_clauses);
- emit_insns (new_catch_clause);
- catch_clauses = get_insns ();
- end_sequence ();
-
- /* Here we fall through into the continuation code. */
+ expand_eh_region_end (integer_zero_node);
}
/* Build a type value for use at runtime for a type that is matched
against by the exception handling system. */
+
static tree
build_eh_type_type (type)
tree type;
@@ -938,6 +396,7 @@ build_eh_type_type (type)
/* Build a type value for use at runtime for a exp that is thrown or
matched against by the exception handling system. */
+
static tree
build_eh_type (exp)
tree exp;
@@ -951,6 +410,7 @@ build_eh_type (exp)
}
/* This routine creates the cleanup for the exception handling object. */
+
static void
push_eh_cleanup ()
{
@@ -973,12 +433,12 @@ push_eh_cleanup ()
matter. If typename is NULL, that means its a "catch (...)" or catch
everything. In that case we don't need to do any type checking.
(ie: it ends up as the "else" clause rather than an "else if" clause) */
+
void
expand_start_catch_block (declspecs, declarator)
tree declspecs, declarator;
{
rtx false_label_rtx;
- rtx protect_label_rtx;
tree decl = NULL_TREE;
tree init;
@@ -989,12 +449,7 @@ expand_start_catch_block (declspecs, declarator)
expand_start_bindings (0);
false_label_rtx = gen_label_rtx ();
- /* This is saved for the exception table. */
- push_rtl_perm ();
- protect_label_rtx = gen_label_rtx ();
- pop_rtl_from_perm ();
push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
- push_label_entry (&false_label_stack, protect_label_rtx, NULL_TREE);
if (declspecs)
{
@@ -1008,6 +463,9 @@ expand_start_catch_block (declspecs, declarator)
if (decl == NULL_TREE)
{
error ("invalid catch parameter");
+
+ /* This is cheap, but we want to maintain the data structures. */
+ expand_eh_region_start ();
return;
}
@@ -1058,115 +516,62 @@ expand_start_catch_block (declspecs, declarator)
}
emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
- /* This is the starting of something to protect. */
- emit_label (protect_label_rtx);
-
- emit_line_note (input_filename, lineno);
-}
-
-
-/* this is called from expand_exception_blocks and
- expand_end_catch_block to expand the toplevel finalizations for a
- function. We return the first label emitted, if any, otherwise
- return NULL_RTX. */
-static rtx
-expand_leftover_cleanups ()
-{
- struct ehEntry *entry;
- rtx first_label = NULL_RTX;
-
- while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
- {
- if (! first_label)
- first_label = entry->exception_handler_label;
- emit_label (entry->exception_handler_label);
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+ /* Because we are reordered out of line, we arrange
+ to rethrow in the outer context, should we encounter
+ an exception in the catch handler.
- /* The below can be optimized away, and we could just fall into the
- next EH handler, if we are certain they are nested. */
- /* Code to throw out to outer context, if we fall off end of the
- handler. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- entry->end_label));
+ Matches the end in expand_end_catch_block (). */
+ expand_eh_region_start ();
- /* leftover try block, opps. */
- if (entry->finalization == integer_zero_node)
- abort ();
+ emit_line_note (input_filename, lineno);
+}
- free (entry);
- }
- return first_label;
-}
/* Call this to end a catch block. Its responsible for emitting the
code to handle jumping back to the correct place, and for emitting
the label to jump to if this catch block didn't match. */
+
void expand_end_catch_block ()
{
- rtx start_protect_label_rtx;
- rtx end_protect_label_rtx;
- tree decls;
- struct ehEntry entry;
+ rtx start_region_label_rtx;
+ rtx end_region_label_rtx;
+ tree decls, t;
if (! doing_eh (1))
return;
- /* fall to outside the try statement when done executing handler and
+ /* Fall to outside the try statement when done executing handler and
we fall off end of handler. This is jump Lresume in the
documentation. */
expand_goto (top_label_entry (&caught_return_label_stack));
- /* We end the rethrow protection region as soon as we hit a label. */
- end_protect_label_rtx = expand_leftover_cleanups ();
-
- /* Code to throw out to outer context, if we get a throw from within
- our catch handler. */
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry.exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
- /* This label is Lhandler in the documentation. */
- emit_label (entry.exception_handler_label);
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- DECL_RTL (top_label_entry (&caught_return_label_stack))));
-
- /* No associated finalization. */
- entry.finalization = NULL_TREE;
- entry.context = current_function_decl;
+ t = make_node (RTL_EXPR);
+ TREE_TYPE (t) = void_type_node;
+ RTL_EXPR_RTL (t) = const0_rtx;
+ TREE_SIDE_EFFECTS (t) = 1;
+ start_sequence_for_rtl_expr (t);
+ expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
+ RTL_EXPR_SEQUENCE (t) = get_insns ();
+ end_sequence ();
- if (end_protect_label_rtx == NULL_RTX)
- end_protect_label_rtx = entry.exception_handler_label;
+ /* Matches the start in expand_start_catch_block (). */
+ expand_eh_region_end (t);
- /* Because we are emitted out of line, we have to protect this. */
- /* label for the start of the protection region. */
- start_protect_label_rtx = pop_label_entry (&false_label_stack);
+ expand_leftover_cleanups ();
/* Cleanup the EH parameter. */
decls = getdecls ();
expand_end_bindings (decls, decls != NULL_TREE, 0);
- /* label we emit to jump to if this catch block didn't match. */
+ /* label we emit to jump to if this catch block didn't match. */
/* This the closing } in the `if (eq) {' of the documentation. */
emit_label (pop_label_entry (&false_label_stack));
-
- /* Because we are reordered out of line, we have to protect this. */
- entry.start_label = start_protect_label_rtx;
- entry.end_label = end_protect_label_rtx;
-
- LABEL_PRESERVE_P (entry.start_label) = 1;
- LABEL_PRESERVE_P (entry.end_label) = 1;
- LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
-
- /* These set up a call to throw the caught exception into the outer
- context. */
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
}
-/* unwind the stack. */
+/* unwind the stack. */
+
static void
do_unwind (inner_throw_label)
rtx inner_throw_label;
@@ -1248,48 +653,6 @@ do_unwind (inner_throw_label)
}
-/* Given the return address, compute the new pc to throw. This has to
- work for the current frame of the current function, and the one
- above it in the case of throw. */
-static rtx
-eh_outer_context (addr)
- rtx addr;
-{
-#if defined (ARM_FRAME_RTX) /* was __arm */
- /* On the ARM, '__builtin_return_address', must have 4
- subtracted from it. */
- emit_insn (gen_add2_insn (addr, GEN_INT (-4)));
-
- /* If we are generating code for an ARM2/ARM3 machine or for an ARM6
- in 26 bit mode, the condition codes must be masked out of the
- return value, or else they will confuse BuiltinReturnAddress.
- This does not apply to ARM6 and later processors when running in
- 32 bit mode. */
- if (!TARGET_6)
- emit_insn (gen_rtx (SET, Pmode,
- addr,
- gen_rtx (AND, Pmode,
- addr, GEN_INT (0x03fffffc))));
-#else
-#if ! defined (SPARC_STACK_ALIGN) /* was sparc */
-#if defined (TARGET_SNAKE)
- /* On HPPA, the low order two bits hold the priviledge level, so we
- must get rid of them. */
- emit_insn (gen_rtx (SET, Pmode,
- addr,
- gen_rtx (AND, Pmode,
- addr, GEN_INT (0xfffffffc))));
-#endif
-
- /* On the SPARC, __builtin_return_address is already -8 or -12, no
- need to subtract any more from it. */
- addr = plus_constant (addr, -1);
-#endif
-#endif
-
- return addr;
-}
-
/* is called from expand_exception_blocks () to generate the code in a function
to "throw" if anything in the function needs to perform a throw.
@@ -1303,9 +666,8 @@ eh_outer_context (addr)
gotta_rethrow_it:
saved_pc = __builtin_return_address (0);
pop_to_previous_level ();
- goto throw;
+ goto throw; */
- */
void
expand_builtin_throw ()
{
@@ -1391,7 +753,7 @@ expand_builtin_throw ()
return_val_rtx = eh_outer_context (return_val_rtx);
/* Yes it did. */
- emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
+ emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
emit_jump (top_of_loop);
@@ -1429,7 +791,7 @@ expand_builtin_throw ()
void
expand_start_eh_spec ()
{
- start_protect ();
+ expand_eh_region_start ();
}
static void
@@ -1472,11 +834,11 @@ expand_end_eh_spec (raises)
emit_jump (check);
emit_label (cont);
jumpif (make_tree (integer_type_node, flag), end);
- start_protect ();
+ expand_eh_region_start ();
do_function_call (Unexpected, NULL_TREE, NULL_TREE);
assemble_external (TREE_OPERAND (Unexpected, 0));
emit_barrier ();
- end_protect (second_try);
+ expand_eh_region_end (second_try);
emit_label (check);
emit_move_insn (flag, const1_rtx);
@@ -1511,17 +873,19 @@ expand_end_eh_spec (raises)
RTL_EXPR_SEQUENCE (expr) = get_insns ();
end_sequence ();
- end_protect (expr);
+ expand_eh_region_end (expr);
}
/* This is called to expand all the toplevel exception handling
finalization for a function. It should only be called once per
function. */
+
void
expand_exception_blocks ()
{
rtx funcend;
rtx insns;
+ rtx eh_spec_insns = NULL_RTX;
start_sequence ();
@@ -1540,11 +904,22 @@ expand_exception_blocks ()
insns = get_insns ();
end_sequence ();
- /* Do this after we expand leftover cleanups, so that the end_protect
- that expand_end_eh_spec does will match the right start_protect,
+ /* Do this after we expand leftover cleanups, so that the expand_eh_region_end
+ that expand_end_eh_spec does will match the right expand_eh_region_start,
and make sure it comes out before the terminate protected region. */
if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
{
+#if 1
+ {
+ rtx insns;
+ /* New... */
+ start_sequence ();
+ expand_start_eh_spec ();
+ eh_spec_insns = get_insns ();
+ end_sequence ();
+ }
+#endif
+
expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
push_to_sequence (insns);
@@ -1557,39 +932,22 @@ expand_exception_blocks ()
if (insns)
{
- struct ehEntry entry;
-
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry.start_label = gen_label_rtx ();
- entry.end_label = gen_label_rtx ();
- entry.exception_handler_label = gen_label_rtx ();
- entry.finalization = TerminateFunctionCall;
- entry.context = current_function_decl;
+ /* Is this necessary? */
assemble_external (TREE_OPERAND (Terminate, 0));
- pop_rtl_from_perm ();
-
- LABEL_PRESERVE_P (entry.start_label) = 1;
- LABEL_PRESERVE_P (entry.end_label) = 1;
- LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
- emit_label (entry.start_label);
+ expand_eh_region_start ();
emit_insns (insns);
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
-
- emit_label (entry.exception_handler_label);
- expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
- emit_label (entry.end_label);
- emit_barrier ();
+ expand_eh_region_end (TerminateFunctionCall);
+ expand_leftover_cleanups ();
}
{
/* Mark the end of the stack unwinder. */
rtx unwind_insns;
start_sequence ();
- end_eh_unwinder (funcend);
- expand_leftover_cleanups ();
+#if 0
+ end_eh_unwinder ();
+#endif
unwind_insns = get_insns ();
end_sequence ();
if (unwind_insns)
@@ -1607,6 +965,14 @@ expand_exception_blocks ()
insns = get_insns ();
end_sequence ();
+#if 1
+ if (eh_spec_insns)
+ emit_insns_after (eh_spec_insns, get_insns ());
+#else
+ if (eh_spec_insns)
+ store_after_parms (eh_spec_insns);
+#endif
+
emit_insns (insns);
}
@@ -1661,7 +1027,7 @@ end_anon_func ()
pop_cp_function_context (NULL_TREE);
}
-/* call this to expand a throw statement. This follows the following
+/* Expand a throw statement. This follows the following
algorithm:
1. Allocate space to save the current PC onto the stack.
@@ -1670,6 +1036,7 @@ end_anon_func ()
3. If this is the first call to throw in this function:
generate a label for the throw block
4. jump to the throw block label. */
+
void
expand_throw (exp)
tree exp;
@@ -1679,12 +1046,6 @@ expand_throw (exp)
if (! doing_eh (1))
return;
- /* This is the label that represents where in the code we were, when
- we got an exception. This needs to be updated when we rethrow an
- exception, so that the matching routine knows to search out. */
- label = gen_label_rtx ();
- emit_label (label);
-
if (exp)
{
tree throw_type;
@@ -1760,75 +1121,17 @@ expand_throw (exp)
/* This part is easy, as we don't have to do anything else. */
}
- expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
-}
-
-void
-end_protect_partials () {
- while (protect_list)
- {
- end_protect (TREE_VALUE (protect_list));
- protect_list = TREE_CHAIN (protect_list);
- }
-}
-
-int
-might_have_exceptions_p ()
-{
- if (eh_table_output_queue.head)
- return 1;
- return 0;
-}
-
-/* Output the exception table.
- Return the number of handlers. */
-void
-emit_exception_table ()
-{
- int count = 0;
- extern FILE *asm_out_file;
- struct ehEntry *entry;
-
- if (! doing_eh (0))
- return;
-
- exception_section ();
-
- /* Beginning marker for table. */
- assemble_align (GET_MODE_ALIGNMENT (Pmode));
- assemble_label ("__EXCEPTION_TABLE__");
- output_exception_table_entry (asm_out_file,
- const0_rtx, const0_rtx, const0_rtx);
-
- while (entry = dequeue_eh_entry (&eh_table_output_queue))
- {
- tree context = entry->context;
-
- if (context && ! TREE_ASM_WRITTEN (context))
- continue;
-
- count++;
- output_exception_table_entry (asm_out_file,
- entry->start_label, entry->end_label,
- entry->exception_handler_label);
- }
-
- /* Ending marker for table. */
- assemble_label ("__EXCEPTION_END__");
- output_exception_table_entry (asm_out_file,
- constm1_rtx, constm1_rtx, constm1_rtx);
-}
+ /* This is the label that represents where in the code we were, when
+ we got an exception. This needs to be updated when we rethrow an
+ exception, so that the matching routine knows to search out. */
+ label = gen_label_rtx ();
+ emit_label (label);
-void
-register_exception_table ()
-{
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
- VOIDmode, 1,
- gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
- Pmode);
+ expand_internal_throw (label);
}
/* Build a throw expression. */
+
tree
build_throw (e)
tree e;
@@ -1843,58 +1146,3 @@ build_throw (e)
}
return e;
}
-
-void
-start_eh_unwinder ()
-{
- start_protect ();
-}
-
-static void
-end_eh_unwinder (end)
- rtx end;
-{
- tree expr;
- rtx return_val_rtx, ret_val, label;
-
- if (! doing_eh (0))
- return;
-
- expr = make_node (RTL_EXPR);
- TREE_TYPE (expr) = void_type_node;
- RTL_EXPR_RTL (expr) = const0_rtx;
- TREE_SIDE_EFFECTS (expr) = 1;
- start_sequence_for_rtl_expr (expr);
-
- ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0, hard_frame_pointer_rtx);
- return_val_rtx = copy_to_reg (ret_val);
-
- return_val_rtx = eh_outer_context (return_val_rtx);
-
- emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
-
-#ifdef JUMP_TO_THROW
- emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
-#else
- label = gen_label_rtx ();
- emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
-#endif
-
-#ifdef RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
- if (return_val_rtx != ret_val)
- emit_move_insn (ret_val, return_val_rtx);
-#endif
-
- emit_jump (end);
-
-#ifndef JUMP_TO_THROW
- emit_label (label);
- do_function_call (Throw, NULL_TREE, NULL_TREE);
-#endif
-
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
- end_protect (expr);
-}
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 862dca75a66..62e3909c86b 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -245,7 +245,7 @@ perform_member_init (member, name, init, explicit, protect_list)
if (expr != error_mark_node)
{
- start_protect ();
+ expand_eh_region_start ();
*protect_list = tree_cons (NULL_TREE, expr, *protect_list);
}
}
@@ -618,7 +618,7 @@ emit_base_init (t, immediately)
if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
- start_protect ();
+ expand_eh_region_start ();
/* All cleanups must be on the function_obstack. */
push_obstacks_nochange ();
@@ -3369,7 +3369,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
expand_start_cond (build (GE_EXPR, boolean_type_node,
iterator, integer_zero_node), 0);
if (TYPE_NEEDS_DESTRUCTOR (type))
- start_protect ();
+ expand_eh_region_start ();
expand_start_loop_continue_elsewhere (1);
if (from_array)
@@ -3429,7 +3429,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
use_variable (DECL_RTL (base2));
}
expand_end_loop ();
- if (TYPE_NEEDS_DESTRUCTOR (type) && flag_handle_exceptions)
+ if (TYPE_NEEDS_DESTRUCTOR (type) && flag_exceptions)
{
/* We have to ensure that this can live to the cleanup
expansion time, since we know it is only ever needed
@@ -3450,7 +3450,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
expand_expr (e1, const0_rtx, VOIDmode, 0);
RTL_EXPR_SEQUENCE (e2) = get_insns ();
end_sequence ();
- end_protect (e2);
+ expand_eh_region_end (e2);
}
pop_obstacks ();
}
diff --git a/gcc/cp/lang-options.h b/gcc/cp/lang-options.h
index 627189cb3d7..54c214e2e48 100644
--- a/gcc/cp/lang-options.h
+++ b/gcc/cp/lang-options.h
@@ -50,8 +50,6 @@ Boston, MA 02111-1307, USA. */
"-fno-for-scope",
"-fgnu-keywords",
"-fno-gnu-keywords",
- "-fhandle-exceptions",
- "-fno-handle-exceptions",
"-fhandle-signatures",
"-fno-handle-signatures",
"-fhuge-objects",
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 7ce0a96ae6b..56cf159cdc9 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -676,14 +676,14 @@ init_lex ()
opname_tab[(int) COMPONENT_REF] = "->";
opname_tab[(int) MEMBER_REF] = "->*";
opname_tab[(int) METHOD_CALL_EXPR] = "->()";
- opname_tab[(int) INDIRECT_REF] = "(unary *)";
+ opname_tab[(int) INDIRECT_REF] = "*";
opname_tab[(int) ARRAY_REF] = "[]";
opname_tab[(int) MODIFY_EXPR] = "=";
opname_tab[(int) NEW_EXPR] = "new";
opname_tab[(int) DELETE_EXPR] = "delete";
opname_tab[(int) VEC_NEW_EXPR] = "new []";
opname_tab[(int) VEC_DELETE_EXPR] = "delete []";
- opname_tab[(int) COND_EXPR] = "... ? ... : ...";
+ opname_tab[(int) COND_EXPR] = "?:";
opname_tab[(int) CALL_EXPR] = "()";
opname_tab[(int) PLUS_EXPR] = "+";
opname_tab[(int) MINUS_EXPR] = "-";
@@ -720,9 +720,9 @@ init_lex ()
opname_tab[(int) EQ_EXPR] = "==";
opname_tab[(int) NE_EXPR] = "!=";
opname_tab[(int) IN_EXPR] = "in";
- opname_tab[(int) RANGE_EXPR] = "..";
- opname_tab[(int) CONVERT_EXPR] = "(unary +)";
- opname_tab[(int) ADDR_EXPR] = "(unary &)";
+ opname_tab[(int) RANGE_EXPR] = "...";
+ opname_tab[(int) CONVERT_EXPR] = "+";
+ opname_tab[(int) ADDR_EXPR] = "&";
opname_tab[(int) PREDECREMENT_EXPR] = "--";
opname_tab[(int) PREINCREMENT_EXPR] = "++";
opname_tab[(int) POSTDECREMENT_EXPR] = "--";
@@ -764,7 +764,7 @@ init_lex ()
#if 0
/* let's parse things, and if they use it, then give them an error. */
- if (!flag_handle_exceptions)
+ if (!flag_exceptions)
{
UNSET_RESERVED_WORD ("throw");
UNSET_RESERVED_WORD ("try");
@@ -3039,7 +3039,7 @@ real_yylex ()
|| strcmp ("try", token_buffer) == 0)
{
static int did_warn = 0;
- if (! did_warn && ! flag_handle_exceptions)
+ if (! did_warn && ! flag_exceptions)
{
pedwarn ("`catch', `throw', and `try' are all C++ reserved words");
did_warn = 1;
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 0927f177f6e..bb8a2046688 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1193,6 +1193,10 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
int try_second;
int binary_is_unary;
+#ifdef NEW_OVER
+ return build_new_op (code, flags, xarg1, xarg2, arg3);
+#endif
+
if (xarg1 == error_mark_node)
return error_mark_node;
@@ -2203,7 +2207,12 @@ synthesize_method (fndecl)
/* Turn off DECL_INLINE for the moment so function_cannot_inline_p
will check our size. */
DECL_INLINE (fndecl) = 0;
- if (function_cannot_inline_p (fndecl) == 0)
+
+ /* We say !at_eof because at the end of the file some of the rtl
+ for fndecl may have been allocated on the temporary obstack.
+ (The function_obstack is the temporary one if we're not in a
+ function). */
+ if ((! at_eof) && function_cannot_inline_p (fndecl) == 0)
DECL_INLINE (fndecl) = 1;
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index fc334e4004d..d86e852f401 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1181,6 +1181,8 @@ instantiate_class_template (type)
= TYPE_USES_COMPLEX_INHERITANCE (pattern);
TYPE_USES_VIRTUAL_BASECLASSES (type)
= TYPE_USES_VIRTUAL_BASECLASSES (pattern);
+ TYPE_PACKED (type) = TYPE_PACKED (pattern);
+ TYPE_ALIGN (type) = TYPE_ALIGN (pattern);
if (! uses_template_parms (type))
{
@@ -1189,8 +1191,7 @@ instantiate_class_template (type)
if (TREE_CODE (tmp) == FIELD_DECL)
require_complete_type (tmp);
- /* XXX handle attributes */
- type = finish_struct_1 (type, NULL_TREE, 0);
+ type = finish_struct_1 (type, 0);
CLASSTYPE_GOT_SEMICOLON (type) = 1;
repo_template_used (type);
@@ -2265,6 +2266,13 @@ tsubst_expr (t, args, nargs, in_decl)
error ("break statement not within loop or switch");
break;
+ case CONTINUE_STMT:
+ lineno = TREE_COMPLEXITY (t);
+ emit_line_note (input_filename, lineno);
+ if (! expand_continue_loop (0))
+ error ("continue statement not within a loop");
+ break;
+
case SWITCH_STMT:
{
tree val, tmp;
@@ -2403,12 +2411,15 @@ overload_template_name (type)
If SUBR is 1, we're being called recursively (to unify the arguments of
a function or method parameter of a function template), so don't zero
- out targs and don't fail on an incomplete match. */
+ out targs and don't fail on an incomplete match.
+
+ If STRICT is 1, the match must be exact (for casts of overloaded
+ addresses, explicit instantiation, and more_specialized). */
int
-type_unification (tparms, targs, parms, args, nsubsts, subr)
+type_unification (tparms, targs, parms, args, nsubsts, subr, strict)
tree tparms, *targs, parms, args;
- int *nsubsts, subr;
+ int *nsubsts, subr, strict;
{
tree parm, arg;
int i;
@@ -2472,7 +2483,7 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
parm = tree_cons (NULL_TREE, parm, NULL_TREE);
return type_unification (DECL_TEMPLATE_PARMS (arg), targs,
TYPE_ARG_TYPES (TREE_TYPE (arg)),
- parm, &nsubsts, 0);
+ parm, &nsubsts, 0, strict);
}
arg = TREE_TYPE (arg);
}
@@ -2491,7 +2502,7 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
arg = TYPE_MAIN_VARIANT (arg);
}
- switch (unify (tparms, targs, ntparms, parm, arg, nsubsts))
+ switch (unify (tparms, targs, ntparms, parm, arg, nsubsts, strict))
{
case 0:
break;
@@ -2521,9 +2532,9 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
/* Tail recursion is your friend. */
static int
-unify (tparms, targs, ntparms, parm, arg, nsubsts)
+unify (tparms, targs, ntparms, parm, arg, nsubsts, strict)
tree tparms, *targs, parm, arg;
- int *nsubsts, ntparms;
+ int *nsubsts, ntparms, strict;
{
int idx;
@@ -2546,6 +2557,9 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
case TEMPLATE_TYPE_PARM:
(*nsubsts)++;
idx = TEMPLATE_TYPE_IDX (parm);
+ if (strict && (TYPE_READONLY (arg) < TYPE_READONLY (parm)
+ || TYPE_VOLATILE (arg) < TYPE_VOLATILE (parm)))
+ return 1;
#if 0
/* Template type parameters cannot contain cv-quals; i.e.
template <class T> void f (T& a, T& b) will not generate
@@ -2606,26 +2620,27 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
case POINTER_TYPE:
if (TREE_CODE (arg) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (arg))
return unify (tparms, targs, ntparms, parm,
- TYPE_PTRMEMFUNC_FN_TYPE (arg), nsubsts);
+ TYPE_PTRMEMFUNC_FN_TYPE (arg), nsubsts, strict);
if (TREE_CODE (arg) != POINTER_TYPE)
return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
- nsubsts);
+ nsubsts, strict);
case REFERENCE_TYPE:
if (TREE_CODE (arg) == REFERENCE_TYPE)
arg = TREE_TYPE (arg);
- return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg, nsubsts);
+ return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg,
+ nsubsts, strict);
case ARRAY_TYPE:
if (TREE_CODE (arg) != ARRAY_TYPE)
return 1;
if (unify (tparms, targs, ntparms, TYPE_DOMAIN (parm), TYPE_DOMAIN (arg),
- nsubsts) != 0)
+ nsubsts, strict) != 0)
return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
- nsubsts);
+ nsubsts, strict);
case REAL_TYPE:
case INTEGER_TYPE:
@@ -2635,12 +2650,12 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
if (TREE_CODE (parm) == INTEGER_TYPE)
{
if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
- && unify (tparms, targs, ntparms,
- TYPE_MIN_VALUE (parm), TYPE_MIN_VALUE (arg), nsubsts))
+ && unify (tparms, targs, ntparms, TYPE_MIN_VALUE (parm),
+ TYPE_MIN_VALUE (arg), nsubsts, strict))
return 1;
if (TYPE_MAX_VALUE (parm) && TYPE_MAX_VALUE (arg)
- && unify (tparms, targs, ntparms,
- TYPE_MAX_VALUE (parm), TYPE_MAX_VALUE (arg), nsubsts))
+ && unify (tparms, targs, ntparms, TYPE_MAX_VALUE (parm),
+ TYPE_MAX_VALUE (arg), nsubsts, strict))
return 1;
}
/* As far as unification is concerned, this wins. Later checks
@@ -2660,7 +2675,7 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
t2 = TREE_OPERAND (parm, 1);
return unify (tparms, targs, ntparms, t1,
fold (build (PLUS_EXPR, integer_type_node, arg, t2)),
- nsubsts);
+ nsubsts, strict);
}
case TREE_VEC:
@@ -2673,7 +2688,7 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
for (i = TREE_VEC_LENGTH (parm) - 1; i >= 0; i--)
if (unify (tparms, targs, ntparms,
TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
- nsubsts))
+ nsubsts, strict))
return 1;
return 0;
}
@@ -2681,7 +2696,7 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (parm))
return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm),
- arg, nsubsts);
+ arg, nsubsts, strict);
/* Allow trivial conversions. */
if (TREE_CODE (arg) != RECORD_TYPE
@@ -2689,13 +2704,22 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
|| TYPE_VOLATILE (parm) < TYPE_VOLATILE (arg))
return 1;
- if (CLASSTYPE_TEMPLATE_INFO (parm) && CLASSTYPE_TEMPLATE_INFO (arg)
- && uses_template_parms (parm))
+ if (CLASSTYPE_TEMPLATE_INFO (parm) && uses_template_parms (parm))
{
- if (CLASSTYPE_TI_TEMPLATE (parm) != CLASSTYPE_TI_TEMPLATE (arg))
+ tree t = NULL_TREE;
+#ifdef NEW_OVER
+ if (! strict)
+ t = get_template_base (CLASSTYPE_TI_TEMPLATE (parm), arg);
+ else
+#endif
+ if (CLASSTYPE_TEMPLATE_INFO (arg)
+ && CLASSTYPE_TI_TEMPLATE (parm) == CLASSTYPE_TI_TEMPLATE (arg))
+ t = arg;
+ if (! t || t == error_mark_node)
return 1;
+
return unify (tparms, targs, ntparms, CLASSTYPE_TI_ARGS (parm),
- CLASSTYPE_TI_ARGS (arg), nsubsts);
+ CLASSTYPE_TI_ARGS (t), nsubsts, strict);
}
else if (TYPE_MAIN_VARIANT (parm) != TYPE_MAIN_VARIANT (arg))
return 1;
@@ -2711,19 +2735,19 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
return 1;
check_args:
if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
- TREE_TYPE (arg), nsubsts))
+ TREE_TYPE (arg), nsubsts, strict))
return 1;
return type_unification (tparms, targs, TYPE_ARG_TYPES (parm),
- TYPE_ARG_TYPES (arg), nsubsts, 1);
+ TYPE_ARG_TYPES (arg), nsubsts, 1, strict);
case OFFSET_TYPE:
if (TREE_CODE (arg) != OFFSET_TYPE)
return 1;
if (unify (tparms, targs, ntparms, TYPE_OFFSET_BASETYPE (parm),
- TYPE_OFFSET_BASETYPE (arg), nsubsts))
+ TYPE_OFFSET_BASETYPE (arg), nsubsts, strict))
return 1;
return unify (tparms, targs, ntparms, TREE_TYPE (parm),
- TREE_TYPE (arg), nsubsts);
+ TREE_TYPE (arg), nsubsts, strict);
default:
sorry ("use of `%s' in template type unification",
@@ -2748,6 +2772,44 @@ mark_decl_instantiated (result, extern_p)
}
}
+/* Given two function templates PAT1 and PAT2, return:
+
+ 1 if PAT1 is more specialized than PAT2 as described in [temp.func.order].
+ -1 if PAT2 is more specialized than PAT1.
+ 0 if neither is more specialized. */
+
+int
+more_specialized (pat1, pat2)
+ tree pat1, pat2;
+{
+ int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (pat1));
+ tree *targs = (tree *) malloc (sizeof (tree) * ntparms);
+ int i, dummy = 0, winner = 0;
+
+ i = type_unification (DECL_TEMPLATE_PARMS (pat1), targs,
+ TYPE_ARG_TYPES (TREE_TYPE (pat1)),
+ TYPE_ARG_TYPES (TREE_TYPE (pat2)),
+ &dummy, 0, 1);
+
+ free (targs);
+ if (i == 0)
+ --winner;
+
+ ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (pat2));
+ targs = (tree *) malloc (sizeof (tree) * ntparms);
+
+ i = type_unification (DECL_TEMPLATE_PARMS (pat2), targs,
+ TYPE_ARG_TYPES (TREE_TYPE (pat2)),
+ TYPE_ARG_TYPES (TREE_TYPE (pat1)),
+ &dummy, 0, 1);
+
+ free (targs);
+ if (i == 0)
+ ++winner;
+
+ return winner;
+}
+
/* called from the parser. */
void
@@ -2794,11 +2856,19 @@ do_function_instantiation (declspecs, declarator, storage)
i = type_unification (DECL_TEMPLATE_PARMS (fn), targs,
TYPE_ARG_TYPES (TREE_TYPE (fn)),
TYPE_ARG_TYPES (TREE_TYPE (decl)),
- &dummy, 0);
+ &dummy, 0, 1);
if (i == 0)
{
if (result)
- cp_error ("ambiguous template instantiation for `%D' requested", decl);
+ {
+ int win = more_specialized (DECL_TI_TEMPLATE (result), fn);
+
+ if (win == 0)
+ cp_error ("ambiguous template instantiation for `%D' requested", decl);
+ else if (win == -1)
+ result = instantiate_template (fn, targs);
+ /* else keep current winner */
+ }
else
result = instantiate_template (fn, targs);
}
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 1446df11cdc..ed7843329ec 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -919,7 +919,7 @@ compute_access (basetype_path, field)
{
if (current_class_type
&& static_mem
- && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
+ && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
PUBLIC_RETURN;
else
PROTECTED_RETURN;
@@ -1580,7 +1580,7 @@ lookup_fnfields_1 (type, name)
which gives the following information (in a list):
TREE_TYPE: list of basetypes needed to get to...
- TREE_VALUE: list of all functions in of given type
+ TREE_VALUE: list of all functions in a given type
which have name NAME.
No access information is computed by this function,
@@ -1898,7 +1898,7 @@ lookup_fnfields (basetype_path, name, complain)
/* Search a multiple inheritance hierarchy by breadth-first search.
- TYPE is an aggregate type, possibly in a multiple-inheritance hierarchy.
+ BINFO is an aggregate type, possibly in a multiple-inheritance hierarchy.
TESTFN is a function, which, if true, means that our condition has been met,
and its return value should be returned.
QFN, if non-NULL, is a predicate dictating whether the type should
@@ -3084,11 +3084,14 @@ build_mi_matrix (type)
}
#endif
+ dfs_walk (binfo, dfs_number, unnumberedp);
+
mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
+ if (mi_size < cid)
+ mi_size = cid;
mi_matrix = (char *)xmalloc ((mi_size + 1) * (mi_size + 1));
mi_type = type;
bzero (mi_matrix, (mi_size + 1) * (mi_size + 1));
- dfs_walk (binfo, dfs_number, unnumberedp);
dfs_walk (binfo, dfs_record_inheritance, unmarkedp);
dfs_walk (binfo, dfs_unmark, markedp);
}
@@ -3559,3 +3562,82 @@ lookup_conversions (type)
dfs_walk (TYPE_BINFO (type), add_conversions, 0);
return conversions;
}
+
+/* Subroutine of get_template_base. */
+
+static tree
+get_template_base_recursive (binfo, rval, template, via_virtual)
+ tree binfo, template, rval;
+ int via_virtual;
+{
+ tree binfos;
+ int i, n_baselinks;
+ tree type = BINFO_TYPE (binfo);
+
+ if (CLASSTYPE_TEMPLATE_INFO (type)
+ && CLASSTYPE_TI_TEMPLATE (type) == template)
+ {
+ if (rval == NULL_TREE || rval == type)
+ return type;
+ else
+ return error_mark_node;
+ }
+
+ binfos = BINFO_BASETYPES (binfo);
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ /* Process base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ /* Find any specific instance of a virtual base, when searching with
+ a binfo... */
+ if (BINFO_MARKED (base_binfo) == 0)
+ {
+ int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
+
+ /* When searching for a non-virtual, we cannot mark
+ virtually found binfos. */
+ if (! this_virtual)
+ SET_BINFO_MARKED (base_binfo);
+
+ rval = get_template_base_recursive
+ (base_binfo, rval, template, this_virtual);
+ if (rval == error_mark_node)
+ return rval;
+ }
+ }
+
+ return rval;
+}
+
+/* Given a class template TEMPLATE and a class type or binfo node BINFO,
+ find the unique base type in BINFO that is an instance of TEMPLATE.
+ If there are more than one, return error_mark_node. Used by unify. */
+
+tree
+get_template_base (template, binfo)
+ register tree template, binfo;
+{
+ tree type, rval;
+
+ if (TREE_CODE (binfo) == TREE_VEC)
+ type = BINFO_TYPE (binfo);
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
+ {
+ type = complete_type (binfo);
+ binfo = TYPE_BINFO (type);
+ }
+ else
+ my_friendly_abort (92);
+
+ if (CLASSTYPE_TEMPLATE_INFO (type)
+ && CLASSTYPE_TI_TEMPLATE (type) == template)
+ return type;
+
+ rval = get_template_base_recursive (binfo, NULL_TREE, template, 0);
+ dfs_walk (binfo, dfs_unmark, markedp);
+
+ return rval;
+}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 3e837f78d5b..775e2c81318 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -132,8 +132,9 @@ complete_type (type)
else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
{
tree t = complete_type (TREE_TYPE (type));
- if (TYPE_SIZE (t) != NULL_TREE)
- type = build_cplus_array_type (t, TYPE_DOMAIN (type));
+ if (TYPE_SIZE (t) != NULL_TREE
+ && current_template_parms == NULL_TREE)
+ layout_type (type);
}
else if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
instantiate_class_template (TYPE_MAIN_VARIANT (type));
@@ -1632,65 +1633,7 @@ build_component_ref_1 (datum, field, protect)
tree datum, field;
int protect;
{
- register tree basetype = TREE_TYPE (datum);
- register enum tree_code code = TREE_CODE (basetype);
- register tree ref;
-
- if (code == REFERENCE_TYPE)
- {
- datum = convert_from_reference (datum);
- basetype = TREE_TYPE (datum);
- code = TREE_CODE (basetype);
- }
-
- if (! IS_AGGR_TYPE_CODE (code))
- {
- if (code != ERROR_MARK)
- cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
- field, datum, basetype);
- return error_mark_node;
- }
-
- if (TYPE_SIZE (basetype) == 0)
- {
- incomplete_type_error (0, basetype);
- return error_mark_node;
- }
-
- /* Look up component name in the structure type definition. */
-
- if (field == error_mark_node)
- my_friendly_abort (115);
-
- if (TREE_STATIC (field))
- return field;
-
- if (datum == current_class_ref)
- {
- tree access = compute_access (TYPE_BINFO (current_class_type), field);
-
- if (access == access_private_node)
- {
- cp_error ("field `%D' is private", field);
- return error_mark_node;
- }
- else if (access == access_protected_node)
- {
- cp_error ("field `%D' is protected", field);
- return error_mark_node;
- }
- }
-
- ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
-
- if (TREE_READONLY (datum) || TREE_READONLY (field))
- TREE_READONLY (ref) = 1;
- if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
- TREE_THIS_VOLATILE (ref) = 1;
- if (DECL_MUTABLE_P (field))
- TREE_READONLY (ref) = 0;
-
- return ref;
+ return build_component_ref (datum, field, NULL_TREE, protect);
}
/* Given a COND_EXPR in T, return it in a form that we can, for
@@ -2414,8 +2357,7 @@ build_x_function_call (function, params, decl)
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- if (TYPE_LANG_SPECIFIC (type)
- && TYPE_OVERLOADS_CALL_EXPR (complete_type (type)))
+ if (IS_AGGR_TYPE (type))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
}
@@ -5586,10 +5528,8 @@ build_modify_expr (lhs, modifycode, rhs)
else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype)
&& TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
{
- if (warn_synth)
- /* If we care about this, do overload resolution. */
- build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
+ build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
+ lhs, rhs, make_node (NOP_EXPR));
/* Do the default thing */;
}
@@ -6778,6 +6718,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
if (TREE_CODE (rhstype) == REFERENCE_TYPE)
rhstype = TREE_TYPE (rhstype);
+ type = complete_type (type);
+
if (TYPE_LANG_SPECIFIC (type)
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
return build_signature_pointer_constructor (type, rhs);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index c224892f063..16b29dc0c5d 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -302,7 +302,7 @@ ack (s, v, v2)
silly. So instead, we just do the equivalent of a call to fatal in the
same situation (call exit). */
-/* First used: 0 (reserved), Last used: 366. Free: */
+/* First used: 0 (reserved), Last used: 367. Free: */
static int abortcount = 0;
@@ -1091,7 +1091,8 @@ process_init_constructor (type, init, elts)
/* Find the first named field. ANSI decided in September 1990
that only named fields count here. */
- while (field && DECL_NAME (field) == 0)
+ while (field && (DECL_NAME (field) == 0
+ || TREE_CODE (field) != FIELD_DECL))
field = TREE_CHAIN (field);
/* If this element specifies a field, initialize via that field. */