[PATCH] Java: front-end improvements.

Alexandre Petit-Bianco apbianco@cygnus.com
Thu Dec 30 14:38:00 GMT 1999


I checked in this patch which brings some improvements to the Java
source code front-end:

  - better error recovery in certain situations,
  - default constructors are generated if necessary even if the parsed
    class isn't a candidate for code generation. This ensures that
    they can be found during the expansion of code generation class
    candidates.

./A

1999-12-14  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* class.c (class_depth): Return -1 if the class doesn't load
	properly.
	* expr.c (can_widen_reference_to): Check for errors during depth
	computation and return 0 accordingly.
	* jcf-parse.c (parse_source_file): Call java_fix_constructors to
	create default constructors and add an other error check.
	* parse.h (java_fix_constructors): Prototyped.
	* parse.y (java_pre_expand_clinit): Likewise.
	(build_super_invocation): Re-prototyped to feature one argument.
	(java_check_circular_reference): Directly use `current'.
	(java_fix_constructors): New function.
	(java_check_regular_methods): Don't create default constructors
	here, but abort if none were found.
	(java_complete_expand_methods): Pre-process <clinit> calling
	java_pre_expand_clinit.
	(java_pre_expand_clinit): New function.
	(fix_constructors): build_super_invocation invoked with the
	current method declaration as an argument.
	(build_super_invocation): Use the context of the processed method
	decl argument instead of current_class.
	* typeck.c (lookup_java_method): Take WFLs in method names into
	account.
	
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/class.c,v
retrieving revision 1.50
diff -u -p -r1.50 class.c
--- class.c	1999/12/14 22:25:37	1.50
+++ class.c	1999/12/30 22:25:26
@@ -403,6 +403,8 @@ class_depth (clas)
   int depth = 0;
   if (! CLASS_LOADED_P (clas))
     load_class (clas, 1);
+  if (TYPE_SIZE (clas) == error_mark_node)
+    return -1;
   while (clas != object_type_node)
     {
       depth++;
Index: expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/expr.c,v
retrieving revision 1.50
diff -u -p -r1.50 expr.c
--- expr.c	1999/12/10 16:06:23	1.50
+++ expr.c	1999/12/30 22:25:39
@@ -386,6 +386,10 @@ can_widen_reference_to (source_type, tar
 	  int source_depth = class_depth (source_type);
 	  int target_depth = class_depth (target_type);
 
+	  /* class_depth can return a negative depth if an error occurred */
+	  if (source_depth < 0 || target_depth < 0)
+	    return 0;
+
 	  if (CLASS_INTERFACE (TYPE_NAME (target_type)))
 	    {
 	      /* target_type is OK if source_type or source_type ancestors
Index: jcf-parse.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/jcf-parse.c,v
retrieving revision 1.37
diff -u -p -r1.37 jcf-parse.c
--- jcf-parse.c	1999/12/06 19:49:06	1.37
+++ jcf-parse.c	1999/12/30 22:25:54
@@ -756,6 +756,8 @@ parse_source_file (file)
   java_parse_abort_on_error ();
   java_check_circular_reference (); /* Check on circular references */
   java_parse_abort_on_error ();
+  java_fix_constructors ();	    /* Fix the constructors */
+  java_parse_abort_on_error ();
 }
 
 static int
Index: parse.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/parse.h,v
retrieving revision 1.38
diff -u -p -r1.38 parse.h
--- parse.h	1999/12/12 19:54:35	1.38
+++ parse.h	1999/12/30 22:26:55
@@ -662,6 +662,7 @@ struct parser_ctxt {
 void safe_layout_class PROTO ((tree));
 void java_complete_class PROTO ((void));
 void java_check_circular_reference PROTO ((void));
+void java_fix_constructors PROTO ((void));
 void java_check_final PROTO ((void));
 void java_layout_classes PROTO ((void));
 tree java_method_add_stmt PROTO ((tree, tree));
Index: parse.y
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/parse.y,v
retrieving revision 1.123
diff -u -p -r1.123 parse.y
--- parse.y	1999/12/13 01:50:55	1.123
+++ parse.y	1999/12/30 22:27:23
@@ -134,6 +134,7 @@ static tree register_incomplete_type PRO
 static tree obtain_incomplete_type PROTO ((tree));
 static tree java_complete_lhs PROTO ((tree));
 static tree java_complete_tree PROTO ((tree));
+static int java_pre_expand_clinit PROTO ((tree));
 static void java_complete_expand_method PROTO ((tree));
 static int  unresolved_type_p PROTO ((tree, tree *));
 static void create_jdep_list PROTO ((struct parser_ctxt *));
@@ -216,7 +217,7 @@ static int check_thrown_exceptions_do PR
 static void purge_unchecked_exceptions PROTO ((tree));
 static void check_throws_clauses PROTO ((tree, tree, tree));
 static void finish_method_declaration PROTO ((tree));
-static tree build_super_invocation PROTO ((void));
+static tree build_super_invocation PROTO ((tree));
 static int verify_constructor_circularity PROTO ((tree, tree));
 static char *constructor_circularity_msg PROTO ((tree, tree));
 static tree build_this_super_qualified_invocation PROTO ((int, tree, tree,
@@ -3985,7 +3986,7 @@ java_check_circular_reference ()
   for (current = ctxp->class_list; current; current = TREE_CHAIN (current))
     {
       tree type = TREE_TYPE (current);
-      if (CLASS_INTERFACE (TYPE_NAME (type)))
+      if (CLASS_INTERFACE (current))
 	{
 	  /* Check all interfaces this class extends */
 	  tree basetype_vec = TYPE_BINFO_BASETYPES (type);
@@ -4010,6 +4011,44 @@ java_check_circular_reference ()
     }
 }
 
+/* Fix the constructors. This will be called right after circular
+   references have been checked. It is necessary to fix constructors
+   early even if no code generation will take place for that class:
+   some generated constructor might be required by the class whose
+   compilation triggered this one to be simply loaded.  */
+
+void
+java_fix_constructors ()
+{
+  tree current;
+
+  for (current = ctxp->class_list; current; current = TREE_CHAIN (current))
+    {
+      tree decl;
+      tree class_type = TREE_TYPE (current);
+      int saw_ctor = 0;
+
+      for (decl = TYPE_METHODS (class_type); decl; decl = TREE_CHAIN (decl))
+	{
+	  if (DECL_CONSTRUCTOR_P (decl))
+	    {
+	      fix_constructors (decl);
+	      saw_ctor = 1;
+	    }
+	}
+
+      if (!saw_ctor)
+	{
+	  int flags = (get_access_flags_from_decl (current) & ACC_PUBLIC ?
+		       ACC_PUBLIC : 0);
+	  decl = create_artificial_method (class_type, flags, void_type_node, 
+					   init_identifier_node, 
+					   end_params_node);
+	  DECL_CONSTRUCTOR_P (decl) = 1;
+	}
+    }
+}
+
 /* safe_layout_class just makes sure that we can load a class without
    disrupting the current_class, input_file, lineno, etc, information
    about the class processed currently.  */
@@ -4916,24 +4955,7 @@ java_check_regular_methods (class_decl)
   java_check_abstract_method_definitions (class_decl);
 
   if (!saw_constructor)
-    {
-      /* No constructor seen, we craft one, at line 0. Since this
-       operation takes place after we laid methods out
-       (layout_class_methods), we prepare the its DECL
-       appropriately. */
-      int flags;
-      tree decl;
-
-      /* If the class is declared PUBLIC, the default constructor is
-         PUBLIC otherwise it has default access implied by no access
-         modifiers. */
-      flags = (get_access_flags_from_decl (class_decl) & ACC_PUBLIC ?
-	       ACC_PUBLIC : 0);
-      decl = create_artificial_method (class, flags, void_type_node, 
-				       init_identifier_node, end_params_node);
-      DECL_CONSTRUCTOR_P (decl) = 1;
-      layout_class_method (TREE_TYPE (class_decl), NULL_TREE, decl, NULL_TREE);
-    }
+    fatal ("No constructor found");
 }
 
 /* Return a non zero value if the `throws' clause of METHOD (if any)
@@ -5999,7 +6021,7 @@ java_complete_expand_methods ()
     {
       int is_interface;
       tree class_type = CLASS_TO_HANDLE_TYPE (TREE_TYPE (current));
-      tree decl;
+      tree decl, prev_decl;
 
       current_class = TREE_TYPE (current);
       is_interface = CLASS_INTERFACE (TYPE_NAME (current_class));
@@ -6008,42 +6030,21 @@ java_complete_expand_methods ()
       init_outgoing_cpool ();
 
       /* We want <clinit> (if any) to be processed first. */
-      decl = tree_last (TYPE_METHODS (class_type));
-      if (IS_CLINIT (decl))
-	{
-	  tree fbody = DECL_FUNCTION_BODY (decl);
-	  tree list;
-	  if (fbody != NULL_TREE)
-	    {
-	      /* First check if we can ignore empty <clinit> */
-	      tree block_body = BLOCK_EXPR_BODY (fbody);
-
-	      current_this = NULL_TREE;
-	      current_function_decl = decl;
-	      if (block_body != NULL_TREE)
-		{
-		  /* Prevent the use of `this' inside <clinit> */
-		  ctxp->explicit_constructor_p = 1;
+      for (prev_decl = NULL_TREE, decl = TYPE_METHODS (class_type); 
+	   decl; prev_decl= decl, decl = TREE_CHAIN (decl))
+	if (IS_CLINIT (decl))
+	  {
+	    if (!java_pre_expand_clinit (decl))
+	      {
+		if (prev_decl)
+		  TREE_CHAIN (prev_decl) = TREE_CHAIN (decl);
+		else
+		  TYPE_METHODS (class_type) = TREE_CHAIN (decl);
+	      }
+	    break;
+	  }
 
-		  block_body = java_complete_tree (block_body);
-		  ctxp->explicit_constructor_p = 0;
-		  BLOCK_EXPR_BODY (fbody) = block_body;
-		  if (block_body != NULL_TREE
-		      && TREE_CODE (block_body) == BLOCK
-		      && BLOCK_EXPR_BODY (block_body) == empty_stmt_node)
-		    decl = NULL_TREE;
-		}
-	    }
-	  list = nreverse (TREE_CHAIN (nreverse (TYPE_METHODS (class_type))));
-	  if (decl != NULL_TREE)
-	    {
-	      TREE_CHAIN (decl) = list;
-	      TYPE_METHODS (class_type) = decl;
-	    }
-	    else
-	      TYPE_METHODS (class_type) = list;
-	}
-      
+      /* Now go on for regular business.  */
       for (decl = TYPE_METHODS (class_type); decl; decl = TREE_CHAIN (decl))
 	{
 	  current_function_decl = decl;
@@ -6092,6 +6093,40 @@ java_complete_expand_methods ()
    the list of the catch clauses of the currently analysed try block. */
 static tree currently_caught_type_list;
 
+/* Complete and expand <clinit>. Return a non zero value if <clinit>
+   is worth keeping.  */
+
+static int
+java_pre_expand_clinit (decl)
+     tree decl;
+{
+  tree fbody = DECL_FUNCTION_BODY (decl);
+  tree list;
+  int to_return = 1;
+
+  if (fbody != NULL_TREE)
+    {
+      /* First check if we can ignore empty <clinit> */
+      tree block_body = BLOCK_EXPR_BODY (fbody);
+      
+      current_this = NULL_TREE;
+      current_function_decl = decl;
+      if (block_body != NULL_TREE)
+	{
+	  /* Prevent the use of `this' inside <clinit> */
+	  ctxp->explicit_constructor_p = 1;
+	  block_body = java_complete_tree (block_body);
+	  ctxp->explicit_constructor_p = 0;
+
+	  BLOCK_EXPR_BODY (fbody) = block_body;
+	  if (block_body != NULL_TREE  && TREE_CODE (block_body) == BLOCK
+	      && BLOCK_EXPR_BODY (block_body) == empty_stmt_node)
+	    to_return = 0;
+	}
+    }
+  return to_return;
+}
+
 /* Complete and expand a method.  */
 
 static void
@@ -6197,7 +6232,7 @@ fix_constructors (mdecl)
       /* We don't generate a super constructor invocation if we're
 	 compiling java.lang.Object. build_super_invocation takes care
 	 of that. */
-      compound = java_method_add_stmt (mdecl, build_super_invocation ());
+      compound = java_method_add_stmt (mdecl, build_super_invocation (mdecl));
 
       end_artificial_method_body (mdecl);
     }
@@ -6229,7 +6264,7 @@ fix_constructors (mdecl)
       /* The constructor is missing an invocation of super() */
       if (!found)
 	compound = add_stmt_to_compound (compound, NULL_TREE,
-					 build_super_invocation ());
+					 build_super_invocation (mdecl));
       
       /* Fix the constructor main block if we're adding extra stmts */
       if (compound)
@@ -8923,9 +8958,10 @@ maybe_absorb_scoping_blocks ()
    we're currently dealing with the class java.lang.Object. */
 
 static tree
-build_super_invocation ()
+build_super_invocation (mdecl)
+     tree mdecl;
 {
-  if (current_class == object_type_node)
+  if (DECL_CONTEXT (mdecl) == object_type_node)
     return empty_stmt_node;
   else
     {
Index: typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/typeck.c,v
retrieving revision 1.20
diff -u -p -r1.20 typeck.c
--- typeck.c	1999/11/18 03:59:48	1.20
+++ typeck.c	1999/12/30 22:27:26
@@ -755,7 +755,10 @@ lookup_java_method (searched_class, meth
 	   method != NULL_TREE;  method = TREE_CHAIN (method))
 	{
 	  tree method_sig = build_java_signature (TREE_TYPE (method));
-	  if (DECL_NAME (method) == method_name 
+	  tree name = DECL_NAME (method);
+
+	  if ((TREE_CODE (name) == EXPR_WITH_FILE_LOCATION ?
+	       EXPR_WFL_NODE (name) : name) == method_name
 	      && method_sig == method_signature)
 	    return method;
 	}
@@ -788,8 +791,10 @@ lookup_java_method (searched_class, meth
               method != NULL_TREE;  method = TREE_CHAIN (method))
            {
              tree method_sig = build_java_signature (TREE_TYPE (method));
+	     tree name = DECL_NAME (method);
 
-             if (DECL_NAME (method) == method_name 
+	     if ((TREE_CODE (name) == EXPR_WITH_FILE_LOCATION ?
+		  EXPR_WFL_NODE (name) : name) == method_name
 		 && method_sig == method_signature)
                return method;
            }





More information about the Gcc-patches mailing list