This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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"));


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]