This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[PATCH] java/12857: Fix class literals
- From: Jeff Sturm <jsturm at one-point dot com>
- To: java-patches at gcc dot gnu dot org
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 6 Nov 2003 08:53:25 -0500 (EST)
- Subject: [PATCH] java/12857: Fix class literals
In the test case, gcj illegally generates a static 'class$' method in an
interface class. It turns out that gcj differs from javac/jikes on
several counts: when class literals are used in inner classes, interfaces
or primtive types (references to 'int.class' causes generation of an
unnecessary 'class$' method). This patch tries to handle all cases.
For interfaces an anonymous inner class may be created. I opted to move
the creation of this class and the class$ method to pass 1
(build_incomplete_class_ref) from pass 2 (patch_incomplete_class_ref),
otherwise we'd need some ugliness to determine whether the new class is to
be generated or not. (And add some ugliness to save/restore parser
context, since build_dot_class_method was designed to be used in pass 2.
Ick.)
Passes all of libjava's testsuite, except for 10 new mauve failures that I
can't reproduce outside of the tree. Any insight into mauve is
appreciated.
Jeff
2003-11-06 Jeff Sturm <jsturm@one-point.com>
Fix PR java/12857.
parse.y: (build_dot_class_method_invocation): Add this_class
argument. Qualify method invocations to a different class.
(build_incomplete_class_ref): Special cases for interfaces
and inner classes. Move build_dot_class_method call to here...
(patch_incomplete_class_ref): ...from here. Pass current_class
to build_dot_class_method_invocation.
(build_assertion): Pass class_type to
build_dot_class_method_invocation.
Index: parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.452
diff -u -p -r1.452 parse.y
--- parse.y 3 Nov 2003 03:58:50 -0000 1.452
+++ parse.y 6 Nov 2003 13:20:59 -0000
@@ -326,7 +326,7 @@ static void patch_anonymous_class (tree,
static void add_inner_class_fields (tree, tree);
static tree build_dot_class_method (tree);
-static tree build_dot_class_method_invocation (tree);
+static tree build_dot_class_method_invocation (tree, tree);
static void create_new_parser_context (int);
static tree maybe_build_class_init_for_field (tree, tree);
@@ -8786,9 +8786,10 @@ build_dot_class_method (tree class)
}
static tree
-build_dot_class_method_invocation (tree type)
+build_dot_class_method_invocation (tree this_class, tree type)
{
- tree sig_id, s;
+ tree dot_class_method = TYPE_DOT_CLASS (this_class);
+ tree sig_id, s, t;
if (TYPE_ARRAY_P (type))
sig_id = build_java_signature (type);
@@ -8801,8 +8802,14 @@ build_dot_class_method_invocation (tree
s = build_string (IDENTIFIER_LENGTH (sig_id),
IDENTIFIER_POINTER (sig_id));
- return build_method_invocation (build_wfl_node (classdollar_identifier_node),
- build_tree_list (NULL_TREE, s));
+ t = build_method_invocation (build_wfl_node (DECL_NAME (dot_class_method)),
+ build_tree_list (NULL_TREE, s));
+ if (DECL_CONTEXT (dot_class_method) != this_class)
+ {
+ tree class_name = DECL_NAME (TYPE_NAME (DECL_CONTEXT (dot_class_method)));
+ t = make_qualified_primary (build_wfl_node (class_name), t, 0);
+ }
+ return t;
}
/* This section of the code deals with constructor. */
@@ -14091,6 +14098,51 @@ static tree
build_incomplete_class_ref (int location, tree class_name)
{
tree node = build1 (CLASS_LITERAL, NULL_TREE, class_name);
+ tree class_decl = GET_CPC ();
+ tree this_class = TREE_TYPE (class_decl);
+
+ /* Generate the synthetic static method `class$'. (Previously we
+ deferred this, causing different method tables to be emitted
+ for native code and bytecode.) */
+ if (!TYPE_DOT_CLASS (this_class)
+ && !JPRIMITIVE_TYPE_P (class_name)
+ && !(TREE_CODE (class_name) == VOID_TYPE))
+ {
+ tree target_class;
+
+ if (CLASS_INTERFACE (TYPE_NAME (this_class)))
+ {
+ /* For interfaces, adding a static 'class$' method directly
+ is illegal. So create an inner class to contain the new
+ method. Empirically this matches the behavior of javac. */
+ tree t = build_wfl_node (DECL_NAME (TYPE_NAME (object_type_node)));
+ tree inner = create_anonymous_class (0, t);
+ target_class = TREE_TYPE (inner);
+ end_class_declaration (1);
+ }
+ else
+ {
+ /* For inner classes, add a 'class$' method to their outermost
+ context, creating it if necessary. */
+ while (INNER_CLASS_DECL_P (class_decl))
+ class_decl = DECL_CONTEXT (class_decl);
+ target_class = TREE_TYPE (class_decl);
+ }
+
+ if (TYPE_DOT_CLASS (target_class) == NULL_TREE)
+ {
+ // XXX: save in context?
+ int old_anonymous_class_counter = anonymous_class_counter;
+ java_push_parser_context ();
+ build_dot_class_method (target_class);
+ java_pop_parser_context (0);
+ anonymous_class_counter = old_anonymous_class_counter;
+ }
+
+ if (this_class != target_class)
+ TYPE_DOT_CLASS (this_class) = TYPE_DOT_CLASS (target_class);
+ }
+
EXPR_WFL_LINECOL (node) = location;
return node;
}
@@ -14105,12 +14157,6 @@ patch_incomplete_class_ref (tree node)
if (!(ref_type = resolve_type_during_patch (type)))
return error_mark_node;
- /* Generate the synthetic static method `class$'. (Previously we
- deferred this, causing different method tables to be emitted
- for native code and bytecode.) */
- if (!TYPE_DOT_CLASS (current_class))
- build_dot_class_method (current_class);
-
/* If we're not emitting class files and we know ref_type is a
compiled class, build a direct reference. */
if ((! flag_emit_class_files && is_compiled_class (ref_type))
@@ -14126,7 +14172,7 @@ patch_incomplete_class_ref (tree node)
/* If we're emitting class files and we have to deal with non
primitive types, we invoke the synthetic static method `class$'. */
- ref_type = build_dot_class_method_invocation (ref_type);
+ ref_type = build_dot_class_method_invocation (current_class, ref_type);
return java_complete_tree (ref_type);
}
@@ -15390,7 +15436,7 @@ build_assertion (int location, tree cond
if (!TYPE_DOT_CLASS (class_type))
build_dot_class_method (class_type);
- classdollar = build_dot_class_method_invocation (class_type);
+ classdollar = build_dot_class_method_invocation (class_type, class_type);
/* Call CLASS.desiredAssertionStatus(). */
id = build_wfl_node (get_identifier ("desiredAssertionStatus"));