OSDN Git Service

* config/cpu/s390/atomicity.h (__exchange_and_add): Add "memory"
[pf3gnuchains/gcc-fork.git] / gcc / java / check-init.c
index 6793533..0ecfec5 100644 (file)
@@ -1,18 +1,21 @@
 /* Code to test for "definitive [un]assignment".
-   Copyright (C) 1999, 2000, 2001  Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005 Free Software Foundation,
+   Inc.
 
-This program is free software; you can redistribute it and/or modify
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-This program is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  
 
@@ -24,6 +27,8 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "flags.h" /* Needed for optimize. */
 #include "java-tree.h"
@@ -72,8 +77,6 @@ static int start_current_locals = 0;
 
 static int num_current_words;
 
-static tree wfl;
-
 #define COPYN(DST, SRC, NWORDS) memcpy (DST, SRC, NWORDS * sizeof(word))
 #define COPY(DST, SRC) COPYN (DST, SRC, num_current_words)
 
@@ -98,17 +101,17 @@ static tree wfl;
 
 #define WORD_SIZE  ((unsigned int)(sizeof(word) * BITS_PER_UNIT))
 
-static void check_bool_init PARAMS ((tree, words, words, words));
-static void check_init PARAMS ((tree, words));
-static void check_cond_init PARAMS ((tree, tree, tree, words, words, words));
-static void check_bool2_init PARAMS ((enum tree_code, tree, tree, words, words, words));
+static void check_bool_init (tree, words, words, words);
+static void check_init (tree, words);
+static void check_cond_init (tree, tree, tree, words, words, words);
+static void check_bool2_init (enum tree_code, tree, tree, words, words, words);
 struct alternatives;
-static void done_alternative PARAMS ((words, struct alternatives *));
-static tree get_variable_decl PARAMS ((tree));
-static void final_assign_error PARAMS ((tree));
-static void check_final_reassigned PARAMS ((tree, words));
+static void done_alternative (words, struct alternatives *);
+static tree get_variable_decl (tree);
+static void final_assign_error (tree);
+static void check_final_reassigned (tree, words);
 
-#define ALLOC_WORDS(NUM) ((word*) xmalloc ((NUM) * sizeof (word)))
+#define ALLOC_WORDS(NUM) (xmalloc ((NUM) * sizeof (word)))
 #define FREE_WORDS(PTR) (free (PTR))
 
 /* DECLARE_BUFFERS is used to allocate NUMBUFFER bit sets, each of
@@ -158,9 +161,13 @@ static void check_final_reassigned PARAMS ((tree, words));
    Return the declaration or NULL_TREE if no interesting declaration.  */
 
 static tree
-get_variable_decl (exp)
-     tree exp;
+get_variable_decl (tree exp)
 {
+  /* A static field can be wrapped in a COMPOUND_EXPR where the first
+     argument initializes the class.  */
+  if (TREE_CODE (exp) == COMPOUND_EXPR)
+    exp = extract_field_decl (exp);
+
   if (TREE_CODE (exp) == VAR_DECL)
     {
       if (! TREE_STATIC (exp) ||  FIELD_FINAL (exp))
@@ -188,29 +195,70 @@ get_variable_decl (exp)
            return op1;
        }
     }
+  else if (TREE_CODE (exp) == INDIRECT_REF)
+    {
+      /* For indirect dispatch, look for an expression of the form 
+      (indirect_ref (+ (array_ref otable <N>) this)).  
+      FIXME: it would probably be better to generate a JAVA_FIELD_REF
+      expression that gets converted to OTABLE access at
+      gimplification time.  */
+      exp = TREE_OPERAND (exp, 0);
+      if (TREE_CODE (exp) == PLUS_EXPR)
+       {
+         tree op0 = TREE_OPERAND (exp, 0);
+         STRIP_NOPS (op0);
+         if (TREE_CODE (op0) == ARRAY_REF)
+           {
+             tree table = TREE_OPERAND (op0, 0);
+             if (TREE_CODE (table) == VAR_DECL
+                 && DECL_LANG_SPECIFIC (table)
+                 && DECL_OWNER (table) 
+                 && TYPE_OTABLE_DECL (DECL_OWNER (table)) == table)
+               {
+                 HOST_WIDE_INT index 
+                   = TREE_INT_CST_LOW (TREE_OPERAND (op0, 1));
+                 tree otable_methods 
+                   = TYPE_OTABLE_METHODS (DECL_OWNER (table));
+                 tree element;
+                 for (element = otable_methods; 
+                      element; 
+                      element = TREE_CHAIN (element))
+                   {
+                     if (index == 1)
+                       {
+                         tree purpose = TREE_PURPOSE (element);
+                         if (TREE_CODE (purpose) == FIELD_DECL)
+                           return purpose;
+                         else
+                           return NULL_TREE;
+                       }
+                     --index;
+                   }
+               }
+           }
+       }
+    }
+
   return NULL_TREE;
 }
 
 static void
-final_assign_error (name)
-     tree name;
+final_assign_error (tree name)
 {
-  static const char format[]
-    = "can't reassign a value to the final variable '%s'";
-  parse_error_context (wfl, format, IDENTIFIER_POINTER (name));
+  error ("Can't reassign a value to the final variable %qs",
+        IDENTIFIER_POINTER (name));
 }
 
 static void
-check_final_reassigned (decl, before)
-     tree decl;
-     words before;
+check_final_reassigned (tree decl, words before)
 {
   int index = DECL_BIT_INDEX (decl);
   /* A final local already assigned or a final parameter
      assigned must be reported as errors */
   if (DECL_FINAL (decl) && index != -2
       && (index < loop_current_locals /* I.e. -1, or outside current loop. */
-         || ! UNASSIGNED_P (before, index)))
+          || (DECL_LOCAL_FINAL_IUD (decl) ? ASSIGNED_P (before, index)
+              : ! UNASSIGNED_P (before, index))))
     {
       final_assign_error (DECL_NAME (decl));
     }
@@ -221,10 +269,8 @@ check_final_reassigned (decl, before)
    BEFORE, WHEN_FALSE, and WHEN_TRUE are as in check_bool_init. */
 
 static void
-check_cond_init (test_exp, then_exp, else_exp,
-                before, when_false, when_true)
-     tree test_exp, then_exp, else_exp;
-     words before, when_false, when_true;
+check_cond_init (tree test_exp, tree then_exp, tree else_exp,
+                words before, words when_false, words when_true)
 {
   int save_start_current_locals = start_current_locals;
   DECLARE_BUFFERS(test_false, 6);
@@ -249,9 +295,8 @@ check_cond_init (test_exp, then_exp, else_exp,
    BEFORE, WHEN_FALSE, and WHEN_TRUE are as in check_bool_init. */
 
 static void
-check_bool2_init (code, exp0, exp1, before, when_false, when_true)
-     enum tree_code code;  tree exp0, exp1;
-     words before, when_false, when_true;
+check_bool2_init (enum tree_code code, tree exp0, tree exp1,
+                 words before, words when_false, words when_true)
 {
   word buf[2*4];
   words tmp = num_current_words <= 2 ? buf
@@ -317,9 +362,7 @@ check_bool2_init (code, exp0, exp1, before, when_false, when_true)
    be used as temporary working areas. */
 
 static void
-check_bool_init (exp, before, when_false, when_true)
-     tree exp;
-     words before, when_false, when_true;
+check_bool_init (tree exp, words before, words when_false, words when_true)
 {
   switch (TREE_CODE (exp))
     {
@@ -342,27 +385,6 @@ check_bool_init (exp, before, when_false, when_true)
     case TRUTH_NOT_EXPR:
       check_bool_init (TREE_OPERAND (exp, 0), before, when_true, when_false);
       return;
-    case MODIFY_EXPR:
-      {
-       tree tmp = TREE_OPERAND (exp, 0);
-       if ((tmp = get_variable_decl (tmp)) != NULL_TREE)
-         {
-           int index;
-           check_bool_init (TREE_OPERAND (exp, 1), before,
-                            when_false, when_true);
-           check_final_reassigned (tmp, before);
-           index = DECL_BIT_INDEX (tmp);
-           if (index >= 0)
-             {
-               SET_ASSIGNED (when_false, index);
-               SET_ASSIGNED (when_true, index);
-               CLEAR_UNASSIGNED (when_false, index);
-               CLEAR_UNASSIGNED (when_true, index);
-             }
-           break;
-         }
-      }
-      goto do_default;
 
     case BIT_AND_EXPR:
     case BIT_IOR_EXPR:
@@ -395,8 +417,8 @@ check_bool_init (exp, before, when_false, when_true)
          COPY (when_true, before);
        }
       break;
+
     default:
-    do_default:
       check_init (exp, before);
       COPY (when_false, before);
       COPY (when_true, before);
@@ -412,7 +434,7 @@ struct alternatives
   /* The value of num_current_locals at the start of this compound. */
   int num_locals;
 
-  /* The value of the "before" set at the start of the control stucture.
+  /* The value of the "before" set at the start of the control structure.
    Used for SWITCH_EXPR but not set for LABELED_BLOCK_EXPR. */
   words saved;
 
@@ -451,9 +473,7 @@ struct alternatives * alternatives = NULL;
    of previous alternative branches. */
 
 static void
-done_alternative (after, current)
-     words after;
-     struct alternatives *current; 
+done_alternative (words after, struct alternatives *current)
 {
   INTERSECTN (current->combined, current->combined, after,
              WORDS_NEEDED (2 * current->num_locals));
@@ -475,12 +495,13 @@ done_alternative (after, current)
 /* Check for (un)initialized local variables in EXP.  */
 
 static void
-check_init (exp, before)
-     tree exp;
-     words before;
+check_init (tree exp, words before)
 {
   tree tmp;
+  location_t save_location = input_location;
  again:
+  if (EXPR_HAS_LOCATION (exp))
+    input_location = EXPR_LOCATION (exp);
   switch (TREE_CODE (exp))
     {
     case VAR_DECL:
@@ -494,10 +515,7 @@ check_init (exp, before)
          if (! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp)
              && index >= 0 && ! ASSIGNED_P (before, index))
            {
-             parse_error_context 
-               (wfl, "Variable `%s' may not have been initialized",
-                IDENTIFIER_POINTER (DECL_NAME (exp)));
-             /* Suppress further errors. */
+             error ("variable %qD may not have been initialized", exp);
              DECL_BIT_INDEX (exp) = -2;
            }
        }
@@ -510,9 +528,7 @@ check_init (exp, before)
          int index = DECL_BIT_INDEX (tmp);
          if (index >= 0 && ! ASSIGNED_P (before, index))
            {
-             parse_error_context 
-               (wfl, "variable '%s' may not have been initialized",
-                IDENTIFIER_POINTER (DECL_NAME (tmp)));
+             error ("variable %qD may not have been initialized", tmp);
              /* Suppress further errors. */
              DECL_BIT_INDEX (tmp) = -2;
            }
@@ -540,6 +556,7 @@ check_init (exp, before)
             definitely assigned when once we checked the whole
             function. */
          if (! STATIC_CLASS_INIT_OPT_P () /* FIXME */
+             && ! DECL_FINAL (tmp)
              && index >= start_current_locals
              && index == num_current_locals - 1)
            {
@@ -607,8 +624,10 @@ check_init (exp, before)
                  if (fndecl && METHOD_STATIC (fndecl)
                      && (DECL_INITIAL (decl) == boolean_true_node
                          || (index >= 0 && ASSIGNED_P (tmp, index))))
-                   hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
-                                DECL_FUNCTION_INIT_TEST_CLASS(decl), TRUE, NULL);  
+                   *(htab_find_slot 
+                     (DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
+                      DECL_FUNCTION_INIT_TEST_CLASS (decl), INSERT)) =
+                     DECL_FUNCTION_INIT_TEST_CLASS (decl);
                }
              DECL_BIT_INDEX (decl) = -1;
            }
@@ -645,7 +664,7 @@ check_init (exp, before)
        END_ALTERNATIVES (before, alt);
        loop_current_locals = save_loop_current_locals;
        start_current_locals = save_start_current_locals;
-       return;
+       break;
       }
     case EXIT_EXPR:
       {
@@ -660,7 +679,7 @@ check_init (exp, before)
        done_alternative (when_true, alt);
        COPY (before, when_false);
        RELEASE_BUFFERS(when_true);
-       return;
+       break;
       }
     case LABELED_BLOCK_EXPR:
       {
@@ -671,7 +690,7 @@ check_init (exp, before)
          check_init (LABELED_BLOCK_BODY (exp), before);
        done_alternative (before, &alt);
        END_ALTERNATIVES (before, alt);
-       return;
+       break;
       }
     case EXIT_BLOCK_EXPR:
       {
@@ -681,7 +700,7 @@ check_init (exp, before)
          alt = alt->outer;
        done_alternative (before, alt);
        SET_ALL (before);
-       return;
+       break;
       }
     case SWITCH_EXPR:
       {
@@ -698,7 +717,7 @@ check_init (exp, before)
          done_alternative (alt.saved, &alt);
        FREE_BUFFER(alt.saved, buf);
        END_ALTERNATIVES (before, alt);
-       return;
+       break;
       }
     case CASE_EXPR:
     case DEFAULT_EXPR:
@@ -740,7 +759,7 @@ check_init (exp, before)
          }
        END_ALTERNATIVES (before, alt);
       }
-    return;
+    break;
 
     case TRY_FINALLY_EXPR:
       {
@@ -751,7 +770,7 @@ check_init (exp, before)
        UNION (before, before, tmp);
        RELEASE_BUFFERS(tmp);
       }
-      return;
+      break;
 
     case RETURN_EXPR:
     case THROW_EXPR:
@@ -762,7 +781,7 @@ check_init (exp, before)
     case ERROR_MARK:
     never_continues:
       SET_ALL (before);
-      return;
+      break;
       
     case COND_EXPR:
     case TRUTH_ANDIF_EXPR:
@@ -777,7 +796,7 @@ check_init (exp, before)
       break;
 
     case NOP_EXPR:
-      if (exp == empty_stmt_node)
+      if (IS_EMPTY_STMT (exp))
        break;
       /* ... else fall through ... */
     case UNARY_PLUS_EXPR:
@@ -799,7 +818,6 @@ check_init (exp, before)
     case FIX_FLOOR_EXPR:
     case FIX_ROUND_EXPR:
     case ABS_EXPR:
-    case FFS_EXPR:
       /* Avoid needless recursion. */
       exp = TREE_OPERAND (exp, 0);
       goto again;
@@ -810,7 +828,14 @@ check_init (exp, before)
     case POSTINCREMENT_EXPR:
       tmp = get_variable_decl (TREE_OPERAND (exp, 0));
       if (tmp != NULL_TREE && DECL_FINAL (tmp))
-       final_assign_error (DECL_NAME (tmp));      
+       final_assign_error (DECL_NAME (tmp));
+      else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF)
+        {
+          /* Take care of array length accesses too.  */
+          tree decl = TREE_OPERAND (tmp, 1);
+          if (DECL_FINAL (decl))
+            final_assign_error (DECL_NAME (decl));
+        }
 
       /* Avoid needless recursion.  */
       exp = TREE_OPERAND (exp, 0);
@@ -818,7 +843,7 @@ check_init (exp, before)
 
     case SAVE_EXPR:
       if (IS_INIT_CHECKED (exp))
-       return;
+       break;
       IS_INIT_CHECKED (exp) = 1;
       exp = TREE_OPERAND (exp, 0);
       goto again;
@@ -854,6 +879,12 @@ check_init (exp, before)
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case EXACT_DIV_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
     binop:
       check_init (TREE_OPERAND (exp, 0), before);
       /* Avoid needless recursion, especially for COMPOUND_EXPR. */
@@ -865,6 +896,7 @@ check_init (exp, before)
     case INTEGER_CST:
     case REAL_CST:
     case STRING_CST:
+    case DECL_EXPR:
     case JAVA_EXC_OBJ_EXPR:
       break;
 
@@ -894,19 +926,18 @@ check_init (exp, before)
 
     case EXPR_WITH_FILE_LOCATION:
       {
-       const char *saved_input_filename = input_filename;
-       tree saved_wfl = wfl;
+       location_t saved_location = input_location;
        tree body = EXPR_WFL_NODE (exp);
-       int saved_lineno = lineno;
-       if (body == empty_stmt_node)
+       if (IS_EMPTY_STMT (body))
          break;
-       wfl = exp;
+#ifdef USE_MAPPED_LOCATION
+       input_location = EXPR_LOCATION (exp);
+#else
        input_filename = EXPR_WFL_FILENAME (exp);
-       lineno = EXPR_WFL_LINENO (exp);
+       input_line = EXPR_WFL_LINENO (exp);
+#endif
        check_init (body, before);
-       input_filename = saved_input_filename;
-       lineno = saved_lineno;
-       wfl = saved_wfl;
+       input_location = saved_location;
       }
       break;
       
@@ -915,11 +946,11 @@ check_init (exp, before)
        ("internal error in check-init: tree code not implemented: %s",
         tree_code_name [(int) TREE_CODE (exp)]);
     }
+  input_location = save_location;
 }
 
 void
-check_for_initialization (body, mdecl)
-     tree body, mdecl;
+check_for_initialization (tree body, tree mdecl)
 {
   tree decl;
   word buf[2];
@@ -985,7 +1016,8 @@ check_for_initialization (body, mdecl)
              if (index >= 0 && ! ASSIGNED_P (before, index))
                {
                  if (! is_finit_method)
-                   error_with_decl (decl, "final field '%s' may not have been initialized");
+                   error ("%Jfinal field %qD may not have been initialized",
+                           decl, decl);
                }
              else if (is_finit_method)
                DECL_FIELD_FINAL_IUD (decl) = 1;
@@ -999,27 +1031,3 @@ check_for_initialization (body, mdecl)
 
   start_current_locals = num_current_locals = 0;
 }
-
-/* Call for every element in DECL_FUNCTION_INITIALIZED_CLASS_TABLE of
-   a method to consider whether the type indirectly described by ENTRY
-   is definitly initialized and thus remembered as such. */
-
-bool
-attach_initialized_static_class (entry, ptr)
-     struct hash_entry *entry;
-     PTR ptr;
-{
-  struct init_test_hash_entry *ite = (struct init_test_hash_entry *) entry;
-  tree fndecl = DECL_CONTEXT (ite->init_test_decl);
-  int index = DECL_BIT_INDEX (ite->init_test_decl);
-
-  /* If the initializer flag has been definitly assigned (not taking
-     into account its first mandatory assignment which has been
-     already added but escaped analysis.) */
-  if (fndecl && METHOD_STATIC (fndecl)
-      && (DECL_INITIAL (ite->init_test_decl) == boolean_true_node
-         || (index >= 0 && ASSIGNED_P (((word *) ptr), index))))
-    hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
-                entry->key, TRUE, NULL);
-  return true;
-}