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: RFA: Fix java/21045


When an anonymous class is instantiated based on a constructor with a throws clause, we need to copy the throws clause of the super-constructor into the new synthetic constructor for the anonymous class. Currently GCJ does not do this, resulting in an error because a constructor's throws clause must normally match the constructor it is overriding.

In addition, it is legal to throw from an anonymous class initializer. Exceptions thrown from an anonymous class initializer need to be added to the initializer's throws clause.

One complication here is purge_unchecked_exceptions: java_complete_expand_method was saving the methods throws list, removing unchecked exceptions from it, and restoring the throws list later. This meant that exceptions could not be added to the throws list during expansion of the method. purge_unchecked_exceptions seems to be unneccessary, since exception checking code is already testing IS_UNCHECKED_EXCEPTION_P everywhere that it matters, as far as I can tell. So I have removed it. There is some further discussion of this here: http://gcc.gnu.org/ml/java/2001-08/msg00113.html

No testsuite regressions, and 4 new JACKS passes. OK to commit?

Bryce


2005-07-06  Bryce McKinlay  <mckinlay@redhat.com>

        PR java/21045
	* parse.y (add_exception_to_throws): New function.
	(purge_unchecked_exceptions): Removed.
	(fix_constructors): When building an anonymous inner class
	constructor, copy exception signature from the superclass being
	overriden.
	(get_constructor_super): Renamed from verify_constructor_super. Now
	returns the super constructor after verification.
	(java_complete_expand_method): Don't use purge_unchecked_exceptions
	or save/restore the exception list.
	(check_thrown_exceptions): Add uncaught exceptions in anonymous
	class initializers and constructors to the throws clause of the method.

2005-07-06  Bryce McKinlay  <mckinlay@redhat.com>

	* testsuite/libjava.compile/PR21045.java: New test.
	* testsuite/libjava.jacks/jacks.xfail: Remove 15.9.5.1-exception-1,
	15.9.5.1-exception-3, 8.3.2-abrupt-6, 8.3.2-abrupt-7.

Index: gcc/java/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.546
diff -u -r1.546 parse.y
--- gcc/java/parse.y	5 Jul 2005 21:09:44 -0000	1.546
+++ gcc/java/parse.y	7 Jul 2005 00:15:42 -0000
@@ -233,13 +233,13 @@
 static tree patch_try_statement (tree);
 static tree patch_synchronized_statement (tree, tree);
 static tree patch_throw_statement (tree, tree);
+static void add_exception_to_throws (tree, tree);
 #ifdef USE_MAPPED_LOCATION
 static void check_thrown_exceptions (source_location, tree, tree);
 #else
 static void check_thrown_exceptions (int, tree, tree);
 #endif
 static int check_thrown_exceptions_do (tree);
-static void purge_unchecked_exceptions (tree);
 static bool ctors_unchecked_throws_clause_p (tree);
 static void check_concrete_throws_clauses (tree, tree, tree, tree);
 static void check_throws_clauses (tree, tree, tree);
@@ -256,7 +256,7 @@
 static void fix_constructors (tree);
 static tree build_alias_initializer_parameter_list (int, tree, tree, int *);
 static tree craft_constructor (tree, tree);
-static int verify_constructor_super (tree);
+static tree get_constructor_super (tree);
 static tree create_artificial_method (tree, int, tree, tree, tree);
 static void start_artificial_method_body (tree);
 static void end_artificial_method_body (tree);
@@ -2082,7 +2082,7 @@
 		     must be generated following the hints provided by
 		     the `new' expression. Whether a super constructor
 		     of that nature exists or not is to be verified
-		     later on in verify_constructor_super.
+		     later on in get_constructor_super.
 
 		     It's during the expansion of a `new' statement
 		     referring to an anonymous class that a ctor will
@@ -8161,11 +8161,6 @@
   current_this = (!METHOD_STATIC (mdecl) ?
 		  BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE);
 
-  /* Purge the `throws' list of unchecked exceptions (we save a copy
-     of the list and re-install it later.) */
-  exception_copy = copy_list (DECL_FUNCTION_THROWS (mdecl));
-  purge_unchecked_exceptions (mdecl);
-
   /* Install exceptions thrown with `throws' */
   PUSH_EXCEPTIONS (DECL_FUNCTION_THROWS (mdecl));
 
@@ -8223,9 +8218,6 @@
   POP_EXCEPTIONS();
   if (currently_caught_type_list)
     abort ();
-
-  /* Restore the copy of the list of exceptions. */
-  DECL_FUNCTION_THROWS (mdecl) = exception_copy;
 }
 
 /* For with each class for which there's code to generate. */
@@ -9038,7 +9030,8 @@
       /* It is an error for the compiler to generate a default
 	 constructor if the superclass doesn't have a constructor that
 	 takes no argument, or the same args for an anonymous class */
-      if (verify_constructor_super (mdecl))
+      tree sdecl = get_constructor_super (mdecl);
+      if (sdecl == NULL_TREE)
 	{
 	  tree sclass_decl = TYPE_NAME (CLASSTYPE_SUPER (class_type));
 	  tree save = DECL_NAME (mdecl);
@@ -9051,6 +9044,13 @@
 	  DECL_NAME (mdecl) = save;
 	}
 
+      if (ANONYMOUS_CLASS_P (class_type))
+	{
+	  /* Copy throws clause from the super constructor.  */
+	  tree throws = DECL_FUNCTION_THROWS (sdecl);
+	  DECL_FUNCTION_THROWS (mdecl) = copy_list (throws);
+	}
+
       /* The constructor body must be crafted by hand. It's the
 	 constructor we defined when we realize we didn't have the
 	 CLASSNAME() constructor */
@@ -9135,19 +9135,18 @@
 }
 
 /* Browse constructors in the super class, searching for a constructor
-   that doesn't take any argument. Return 0 if one is found, 1
-   otherwise.  If the current class is an anonymous inner class, look
-   for something that has the same signature. */
-
-static int
-verify_constructor_super (tree mdecl)
+   that doesn't take any argument. Return the constructor if one is found, 
+   NULL_TREE otherwise.  If the current class is an anonymous inner class, 
+   look for something that has the same signature. */
+static tree
+get_constructor_super (tree mdecl)
 {
   tree class = CLASSTYPE_SUPER (current_class);
   int super_inner = PURE_INNER_CLASS_TYPE_P (class);
   tree sdecl;
 
   if (!class)
-    return 0;
+    return NULL_TREE;
 
   if (ANONYMOUS_CLASS_P (current_class))
     {
@@ -9171,7 +9170,7 @@
 		break;
 
 	    if (arg_type == end_params_node && m_arg_type == end_params_node)
-	      return 0;
+	      return sdecl;
 	  }
     }
   else
@@ -9182,10 +9181,10 @@
 	  if (super_inner)
 	    arg = TREE_CHAIN (arg);
 	  if (DECL_CONSTRUCTOR_P (sdecl) && arg == end_params_node)
-	    return 0;
+	    return sdecl;
 	}
     }
-  return 1;
+  return NULL_TREE;
 }
 
 /* Generate code for all context remembered for code generation.  */
@@ -15911,6 +15910,34 @@
   return node;
 }
 
+/* Add EXCEPTION to the throws clause of MDECL.  If MDECL already throws
+   a super-class of EXCEPTION, keep the superclass instead.  If MDECL already
+   throws a sub-class of EXCEPTION, replace the sub-class with EXCEPTION.  */
+static void
+add_exception_to_throws (tree mdecl, tree exception)
+{
+  tree mthrows;
+  
+  /* Ignore unchecked exceptions. */
+  if (IS_UNCHECKED_EXCEPTION_P (exception))
+    return;
+
+  for (mthrows = DECL_FUNCTION_THROWS (mdecl);
+       mthrows; mthrows = TREE_CHAIN (mthrows))
+    {
+      if (inherits_from_p (exception, TREE_VALUE (mthrows)))
+        return;
+      if (inherits_from_p (TREE_VALUE (mthrows), exception))
+        {
+	  TREE_VALUE (mthrows) = exception;
+	  return;
+	}
+    }
+  
+  mthrows = DECL_FUNCTION_THROWS (mdecl);
+  DECL_FUNCTION_THROWS (mdecl) = build_tree_list (mthrows, exception);
+}
+
 /* Check that exception said to be thrown by method DECL can be
    effectively caught from where DECL is invoked.  THIS_EXPR is the
    expression that computes `this' for the method call.  */
@@ -15950,10 +15977,21 @@
 #else
 	EXPR_WFL_LINECOL (wfl_operator) = location;
 #endif
-	if (DECL_FINIT_P (current_function_decl))
-	  parse_error_context
-            (wfl_operator, "Exception %qs can't be thrown in initializer",
-	     lang_printable_name (TREE_VALUE (throws), 0));
+	if (ANONYMOUS_CLASS_P (DECL_CONTEXT (current_function_decl))
+	    && (DECL_FINIT_P (current_function_decl)
+	        || DECL_INIT_P (current_function_decl)
+		|| DECL_CONSTRUCTOR_P (current_function_decl)))
+	  {
+	    /* Add "throws" to the initializer's exception list */
+	    tree exception = TREE_VALUE (throws);
+	    add_exception_to_throws (current_function_decl, exception);	  
+	  }
+	else if (DECL_FINIT_P (current_function_decl))
+	  {
+	    parse_error_context
+              (wfl_operator, "Exception %qs can't be thrown in initializer",
+	       lang_printable_name (TREE_VALUE (throws), 0));
+	  }
 	else
 	  {
 	    parse_error_context
@@ -15990,26 +16028,6 @@
   return 0;
 }
 
-static void
-purge_unchecked_exceptions (tree mdecl)
-{
-  tree throws = DECL_FUNCTION_THROWS (mdecl);
-  tree new = NULL_TREE;
-
-  while (throws)
-    {
-      tree next = TREE_CHAIN (throws);
-      if (!IS_UNCHECKED_EXCEPTION_P (TREE_VALUE (throws)))
-	{
-	  TREE_CHAIN (throws) = new;
-	  new = throws;
-	}
-      throws = next;
-    }
-  /* List is inverted here, but it doesn't matter */
-  DECL_FUNCTION_THROWS (mdecl) = new;
-}
-
 /* This function goes over all of CLASS_TYPE ctors and checks whether
    each of them features at least one unchecked exception in its
    `throws' clause. If it's the case, it returns `true', `false'
Index: libjava/testsuite/libjava.compile/PR21045.java
===================================================================
RCS file: libjava/testsuite/libjava.compile/PR21045.java
diff -N libjava/testsuite/libjava.compile/PR21045.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libjava/testsuite/libjava.compile/PR21045.java	7 Jul 2005 00:15:42 -0000
@@ -0,0 +1,11 @@
+public class PR21045
+{
+	class InnerBase {
+		InnerBase() throws Exception, NullPointerException {}
+	}
+	void method() {
+		try {
+			InnerBase obj = new InnerBase() {};
+		} catch (Exception e) {}
+	}
+}
Index: libjava/testsuite/libjava.jacks/jacks.xfail
===================================================================
RCS file: /cvs/gcc/gcc/libjava/testsuite/libjava.jacks/jacks.xfail,v
retrieving revision 1.26
diff -u -r1.26 jacks.xfail
--- libjava/testsuite/libjava.jacks/jacks.xfail	6 Jul 2005 15:07:46 -0000	1.26
+++ libjava/testsuite/libjava.jacks/jacks.xfail	7 Jul 2005 00:15:42 -0000
@@ -347,8 +347,6 @@
 15.9.4-runtime-creation-1
 15.9.4-runtime-creation-2
 15.9.4-runtime-creation-5
-15.9.5.1-exception-1
-15.9.5.1-exception-3
 15.9.5.1-exception-4
 15.9.5.1-superconstructor-7
 15.9.5.1-superconstructor-8
@@ -563,8 +561,6 @@
 8.3.1.2-final-29
 8.3.2-abrupt-3
 8.3.2-abrupt-5
-8.3.2-abrupt-6
-8.3.2-abrupt-7
 8.3.2.2-super-2
 8.3.2.3-illegal-forward-instance-1
 8.3.2.3-illegal-forward-instance-2

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