This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch: g++ -vs- Java exceptions, take 2
- To: Gcc Patch List <gcc-patches at gcc dot gnu dot org>
- Subject: Patch: g++ -vs- Java exceptions, take 2
- From: Tom Tromey <tromey at cygnus dot com>
- Date: 28 Feb 2000 21:12:06 -0700
- Reply-To: tromey at cygnus dot com
Here's the second version of my Java-exceptions-for-g++ patch.
This one makes the generated code work when sjlj exceptions are in use.
It also gives an error if an invalid Java catch or throw is attempted
(for instance, catching by reference is not supported).
I didn't try the fuller fix of making the Java compiler emit typeinfo
objects for Java classes. We can still implement this at a later
date; meanwhile, this patch is a definite improvement over the current
state of affairs.
Ok to commit?
2000-02-28 Tom Tromey <tromey@cygnus.com>
* cp-tree.h (build_java_class_ref): Declare.
* init.c (build_java_class_ref): No longer static.
* except.c (expand_throw): Generate a Java-style `throw' if the
thrown object is a "Java" object.
(initialize_handler_parm): Generate a Java-style lookup of
exception info if the caught object is a "Java" object.
(catch_language, catch_language_init): New globals.
(decl_is_java_type): New function.
(expand_start_catch_block): Don't call push_eh_info() or
push_eh_cleanup() when handling a Java-style "catch". Pass Java
class reference to build_catch_block.
Tom
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.405
diff -u -r1.405 cp-tree.h
--- cp-tree.h 2000/02/21 04:19:11 1.405
+++ cp-tree.h 2000/02/29 03:47:25
@@ -3913,6 +3913,7 @@
extern void begin_init_stmts PARAMS ((tree *, tree *));
extern tree finish_init_stmts PARAMS ((tree, tree));
extern void initialize_vtbl_ptrs PARAMS ((tree, tree));
+extern tree build_java_class_ref PARAMS ((tree));
/* in input.c */
Index: gcc/cp/except.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/except.c,v
retrieving revision 1.95
diff -u -r1.95 except.c
--- except.c 2000/01/26 20:51:34 1.95
+++ except.c 2000/02/29 03:47:28
@@ -55,6 +55,7 @@
static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
static void initialize_handler_parm PARAMS ((tree));
static tree expand_throw PARAMS ((tree));
+static int decl_is_java_type PARAMS ((tree decl, int err));
#if 0
/* This is the startup, and finish stuff per exception table. */
@@ -92,6 +93,14 @@
#include "insn-flags.h"
#include "obstack.h"
+/* In a given translation unit we are constrained to catch only C++
+ types or only Java types. `catch_language' holds the current type,
+ and `catch_language_init' registers whether `catch_language' has
+ been set. */
+
+static int catch_language_init = 0;
+static int catch_language;
+
/* ======================================================================
Briefly the algorithm works like this:
@@ -450,6 +459,49 @@
return build_function_call (terminate_node, NULL_TREE);
}
+/* Return nonzero value if DECL is a Java type suitable for catch or
+ throw. */
+
+static int
+decl_is_java_type (decl, err)
+ tree decl;
+ int err;
+{
+ int r = (TREE_CODE (decl) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+ && TYPE_FOR_JAVA (TREE_TYPE (decl)));
+
+ if (err)
+ {
+ if (TREE_CODE (decl) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+ && TYPE_FOR_JAVA (TREE_TYPE (decl)))
+ {
+ /* Can't throw a reference. */
+ cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
+ decl);
+ }
+
+ if (r)
+ {
+ tree jthrow_node
+ = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
+ if (jthrow_node == NULL_TREE)
+ fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
+ jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
+
+ if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
+ {
+ /* Thrown object must be a Throwable. */
+ cp_error ("type `%T' is not derived from `java::lang::Throwable'",
+ TREE_TYPE (decl));
+ }
+ }
+ }
+
+ return r;
+}
+
/* Initialize the catch parameter DECL. */
static void
@@ -459,6 +511,7 @@
tree exp;
tree init;
tree init_type;
+ int lang;
/* Make sure we mark the catch param as used, otherwise we'll get a
warning about an unused ((anonymous)). */
@@ -470,8 +523,43 @@
&& TREE_CODE (init_type) != POINTER_TYPE)
init_type = build_reference_type (init_type);
- exp = get_eh_value ();
+ if (decl_is_java_type (init_type, 0))
+ {
+ tree fn
+ = builtin_function ("_Jv_exception_info",
+ build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE,
+ void_type_node,
+ NULL_TREE)),
+ 0, NOT_BUILT_IN, NULL_PTR);
+
+ exp = build (CALL_EXPR, ptr_type_node,
+ build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
+ fn),
+ NULL_TREE, NULL_TREE);
+ TREE_SIDE_EFFECTS (exp) = 1;
+ lang = EH_LANG_Java;
+ set_exception_lang_code (EH_LANG_Java);
+ set_exception_version_code (1);
+ }
+ else
+ {
+ exp = get_eh_value ();
+ lang = EH_LANG_C_plus_plus;
+ }
+
+ if (catch_language_init)
+ {
+ if (lang != catch_language)
+ error ("mixing C++ and Java `catch'es in single translation unit");
+ }
+ else
+ {
+ catch_language_init = 1;
+ catch_language = lang;
+ }
+
/* Since pointers are passed by value, initialize a reference to
pointer catch parm with the address of the value slot. */
if (TREE_CODE (init_type) == REFERENCE_TYPE
@@ -524,15 +612,28 @@
cleanup. */
compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
- if (decl)
- type = build_eh_type_type_ref (TREE_TYPE (decl));
- else
- type = NULL_TREE;
- begin_catch_block (type);
+ if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
+ {
+ /* The ordinary C++ case. */
- push_eh_info ();
- push_eh_cleanup ();
+ if (decl)
+ type = build_eh_type_type_ref (TREE_TYPE (decl));
+ else
+ type = NULL_TREE;
+ begin_catch_block (type);
+ push_eh_info ();
+ push_eh_cleanup ();
+ }
+ else
+ {
+ /* The Java case. In this case, the match_info is a pointer to
+ the Java class object. We assume that the class is a
+ compiled class. */
+ tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
+ begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
+ }
+
/* Create a binding level for the parm. */
compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
@@ -734,7 +835,35 @@
if (! doing_eh (1))
return error_mark_node;
- if (exp)
+ if (exp
+ && decl_is_java_type (TREE_TYPE (exp), 1))
+ {
+ /* A Java `throw' statement. */
+ tree args = tree_cons (NULL_TREE, exp, NULL);
+
+ fn = get_identifier (exceptions_via_longjmp
+ ? "_Jv_Sjlj_throw"
+ : "_Jv_Throw");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ /* Declare _Jv_Throw (void *), as defined in Java's
+ exception.cc. */
+ tree tmp;
+ tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ fn = build_lang_decl (FUNCTION_DECL, fn,
+ build_function_type (ptr_type_node, tmp));
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ }
+
+ exp = build_function_call (fn, args);
+ }
+ else if (exp)
{
tree throw_type;
tree cleanup = NULL_TREE, e;
Index: gcc/cp/init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.165
diff -u -r1.165 init.c
--- init.c 2000/02/21 04:19:12 1.165
+++ init.c 2000/02/29 03:47:36
@@ -45,7 +45,6 @@
static void expand_virtual_init PARAMS ((tree, tree));
static tree sort_member_init PARAMS ((tree));
static tree initializing_context PARAMS ((tree));
-static tree build_java_class_ref PARAMS ((tree));
static void expand_cleanup_for_base PARAMS ((tree, tree));
static tree get_temp_regvar PARAMS ((tree, tree));
static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *));
@@ -2076,7 +2075,7 @@
/* Given a Java class, return a decl for the corresponding java.lang.Class. */
-static tree
+tree
build_java_class_ref (type)
tree type;
{