* except.c (check_handlers): New fn.
* cp-tree.h: Declare it.
* semantics.c (finish_handler_sequence): Call it.
(finish_function_handler_sequence): Likewise.
(finish_handler_parms): Set TREE_TYPE on the handler.
* cp-tree.h (PUBLICLY_UNIQUELY_DERIVED_P): New macro.
* search.c (get_base_distance_recursive): If protect>1, ignore
special access.
(get_base_distance): Don't reduce watch_access.
From-SVN: r33904
+2000-05-14 Jason Merrill <jason@casey.cygnus.com>
+
+ * except.c (check_handlers): New fn.
+ * cp-tree.h: Declare it.
+ * semantics.c (finish_handler_sequence): Call it.
+ (finish_function_handler_sequence): Likewise.
+ (finish_handler_parms): Set TREE_TYPE on the handler.
+ * cp-tree.h (PUBLICLY_UNIQUELY_DERIVED_P): New macro.
+ * search.c (get_base_distance_recursive): If protect>1, ignore
+ special access.
+ (get_base_distance): Don't reduce watch_access.
+
2000-05-13 Gabriel Dos Reis <gdr@codesourcery.com>
* lex.c: #include diagnostic.h.
#define UNIQUELY_DERIVED_FROM_P(PARENT, TYPE) (get_base_distance (PARENT, TYPE, 0, (tree *)0) >= 0)
#define ACCESSIBLY_DERIVED_FROM_P(PARENT, TYPE) (get_base_distance (PARENT, TYPE, -1, (tree *)0) >= 0)
#define ACCESSIBLY_UNIQUELY_DERIVED_P(PARENT, TYPE) (get_base_distance (PARENT, TYPE, 1, (tree *)0) >= 0)
+#define PUBLICLY_UNIQUELY_DERIVED_P(PARENT, TYPE) (get_base_distance (PARENT, TYPE, 2, (tree *)0) >= 0)
#define DERIVED_FROM_P(PARENT, TYPE) (get_base_distance (PARENT, TYPE, 0, (tree *)0) != -1)
\f
/* This structure provides additional information above and beyond
extern tree build_throw PARAMS ((tree));
extern void mark_all_runtime_matches PARAMS ((void));
extern int nothrow_libfn_p PARAMS ((tree));
+extern void check_handlers PARAMS ((tree));
/* in expr.c */
extern void init_cplus_expand PARAMS ((void));
id = DECL_ASSEMBLER_NAME (fn);
return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
}
+
+/* Returns nonzero if an exception of type FROM will be caught by a
+ handler for type TO, as per [except.handle]. */
+
+static int
+can_convert_eh (to, from)
+ tree to, from;
+{
+ if (TREE_CODE (to) == REFERENCE_TYPE)
+ to = TREE_TYPE (to);
+ if (TREE_CODE (from) == REFERENCE_TYPE)
+ from = TREE_TYPE (from);
+
+ if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE)
+ {
+ to = TREE_TYPE (to);
+ from = TREE_TYPE (from);
+
+ if (! at_least_as_qualified_p (to, from))
+ return 0;
+
+ if (TREE_CODE (to) == VOID_TYPE)
+ return 1;
+
+ /* else fall through */
+ }
+
+ if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+ && PUBLICLY_UNIQUELY_DERIVED_P (to, from))
+ return 1;
+
+ return 0;
+}
+
+/* Check whether any of HANDLERS are shadowed by another handler accepting
+ TYPE. Note that the shadowing may not be complete; even if an exception
+ of type B would be caught by a handler for A, there could be a derived
+ class C for which A is an ambiguous base but B is not, so the handler
+ for B would catch an exception of type C. */
+
+static void
+check_handlers_1 (master, handlers)
+ tree master;
+ tree handlers;
+{
+ tree type = TREE_TYPE (master);
+ tree handler;
+
+ for (handler = handlers; handler; handler = TREE_CHAIN (handler))
+ if (TREE_TYPE (handler)
+ && can_convert_eh (type, TREE_TYPE (handler)))
+ {
+ lineno = STMT_LINENO (handler);
+ cp_warning ("exception of type `%T' will be caught",
+ TREE_TYPE (handler));
+ lineno = STMT_LINENO (master);
+ cp_warning (" by earlier handler for `%T'", type);
+ break;
+ }
+}
+
+/* Given a chain of HANDLERs, make sure that they're OK. */
+
+void
+check_handlers (handlers)
+ tree handlers;
+{
+ tree handler;
+ int save_line = lineno;
+ for (handler = handlers; handler; handler = TREE_CHAIN (handler))
+ {
+ if (TREE_CHAIN (handler) == NULL_TREE)
+ /* No more handlers; nothing to shadow. */;
+ else if (TREE_TYPE (handler) == NULL_TREE)
+ {
+ lineno = STMT_LINENO (handler);
+ cp_pedwarn
+ ("`...' handler must be the last handler for its try block");
+ }
+ else
+ check_handlers_1 (handler, TREE_CHAIN (handler));
+ }
+ lineno = save_line;
+}
tree binfos;
int i, n_baselinks;
- if (protect
+ if (protect == 1
&& !current_scope_in_chain
&& is_friend (BINFO_TYPE (binfo), current_scope ()))
current_scope_in_chain = 1;
tree base_binfo = TREE_VEC_ELT (binfos, i);
int via_private
- = (protect
- && (is_private
- || (!TREE_VIA_PUBLIC (base_binfo)
- && !(TREE_VIA_PROTECTED (base_binfo)
- && current_scope_in_chain)
- && !is_friend (BINFO_TYPE (binfo), current_scope ()))));
+ = ((protect == 1
+ && (is_private
+ || (!TREE_VIA_PUBLIC (base_binfo)
+ && !(TREE_VIA_PROTECTED (base_binfo)
+ && current_scope_in_chain)
+ && !is_friend (BINFO_TYPE (binfo), current_scope ()))))
+ || (protect > 1
+ && (is_private || !TREE_VIA_PUBLIC (base_binfo))));
+
int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
rval = get_base_distance_recursive (base_binfo, depth, via_private,
Return -1 if TYPE is not derived from PARENT.
Return -2 if PARENT is an ambiguous base class of TYPE, and PROTECT is
non-negative.
- Return -3 if PARENT is private to TYPE, and PROTECT is non-zero.
+ Return -3 if PARENT is not accessible in TYPE, and PROTECT is non-zero.
If PATH_PTR is non-NULL, then also build the list of types
from PARENT to TYPE, with TREE_VIA_VIRTUAL and TREE_VIA_PUBLIC
set.
+ If PROTECT is greater than 1, ignore any special access the current
+ scope might have when determining whether PARENT is inaccessible.
+
PARENT can also be a binfo, in which case that exact parent is found
and no other. convert_pointer_to_real uses this functionality.
return 0;
}
- if (path_ptr)
+ if (path_ptr && watch_access == 0)
watch_access = 1;
rval = get_base_distance_recursive (binfo, 0, 0, -1,
tree try_block;
{
if (building_stmt_tree ())
- RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+ {
+ RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+ check_handlers (TRY_HANDLERS (try_block));
+ }
else
expand_end_all_catch ();
}
in_function_try_handler = 0;
if (building_stmt_tree ())
- RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+ {
+ RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+ check_handlers (TRY_HANDLERS (try_block));
+ }
else
expand_end_all_catch ();
}
else if (building_stmt_tree ())
blocks = expand_start_catch_block (decl);
+ if (decl)
+ TREE_TYPE (handler) = TREE_TYPE (decl);
+
return blocks;
}