parse.y (parser_check_super_interface): Don't call check_pkg_class_access for an...
authorBryce McKinlay <bryce@albatross.co.nz>
Mon, 19 Feb 2001 22:48:16 +0000 (22:48 +0000)
committerBryce McKinlay <bryce@gcc.gnu.org>
Mon, 19 Feb 2001 22:48:16 +0000 (22:48 +0000)
* parse.y (parser_check_super_interface): Don't call
check_pkg_class_access for an inner interface.
(parser_check_super): Don't call check_pkg_class_access for inner
class.
(do_resolve_class): Simplify enclosing type loop. Don't call
check_pkg_class_access if CL and DECL are not set.
(find_in_imports_on_demand): Set DECL if class_type needed to be
loaded. Don't call check_pkg_class_access for an inner class.
(check_inner_class_access): Rewritten to implement member access
rules as per spec 6.6.1.
(check_pkg_class_access): Handle the empty package correctly.
(in_same_package): New function. Determine if two classes are in the
same package.

From-SVN: r39909

gcc/java/ChangeLog
gcc/java/parse.y

index f19c3fffc499e5f7199a320c4ff2f198c250db2f..4a74ae7214e42298281af3bf79ebff9811f13c15 100644 (file)
@@ -1,3 +1,19 @@
+2001-02-19  Bryce McKinlay  <bryce@albatross.co.nz>
+
+       * parse.y (parser_check_super_interface): Don't call 
+       check_pkg_class_access for an inner interface.
+       (parser_check_super): Don't call check_pkg_class_access for inner 
+       class.
+       (do_resolve_class): Simplify enclosing type loop. Don't call 
+       check_pkg_class_access if CL and DECL are not set.
+       (find_in_imports_on_demand): Set DECL if class_type needed to be
+       loaded. Don't call check_pkg_class_access for an inner class.
+       (check_inner_class_access): Rewritten to implement member access
+       rules as per spec 6.6.1.
+       (check_pkg_class_access): Handle the empty package correctly.
+       (in_same_package): New function. Determine if two classes are in the
+       same package.
+
 2001-02-18  Bryce McKinlay  <bryce@albatross.co.nz>
 
        * typeck.c (build_java_array_type): Don't try to poke a public `clone'
index cb8525a8521462457c426a9d50418efa3deb6c7f..971a8876cc2f6f8bb5eb6bb814027f35a1e642b4 100644 (file)
@@ -127,6 +127,7 @@ static int check_class_interface_creation PARAMS ((int, int, tree,
 static tree patch_method_invocation PARAMS ((tree, tree, tree, int,
                                            int *, tree *));
 static int breakdown_qualified PARAMS ((tree *, tree *, tree));
+static int in_same_package PARAMS ((tree, tree));
 static tree resolve_and_layout PARAMS ((tree, tree));
 static tree qualify_and_find PARAMS ((tree, tree, tree));
 static tree resolve_no_layout PARAMS ((tree, tree));
@@ -4895,8 +4896,10 @@ parser_check_super_interface (super_decl, this_decl, this_wfl)
       return 1;
     }
 
-  /* Check scope: same package OK, other package: OK if public */
-  if (check_pkg_class_access (DECL_NAME (super_decl), lookup_cl (this_decl)))
+  /* Check top-level interface access. Inner classes are subject to member 
+     access rules (6.6.1). */
+  if (! INNER_CLASS_P (super_type)
+      && check_pkg_class_access (DECL_NAME (super_decl), lookup_cl (this_decl)))
     return 1;
 
   SOURCE_FRONTEND_DEBUG (("Completing interface %s with %s",
@@ -4932,8 +4935,10 @@ parser_check_super (super_decl, this_decl, wfl)
       return 1;
     }
 
-  /* Check scope: same package OK, other package: OK if public */
-  if (check_pkg_class_access (DECL_NAME (super_decl), wfl))
+  /* Check top-level class scope. Inner classes are subject to member access
+     rules (6.6.1). */
+  if (! INNER_CLASS_P (super_type)
+      && (check_pkg_class_access (DECL_NAME (super_decl), wfl)))
     return 1;
   
   SOURCE_FRONTEND_DEBUG (("Completing class %s with %s",
@@ -5508,7 +5513,6 @@ do_resolve_class (enclosing, class_type, decl, cl)
      being loaded from class file. FIXME. */
   while (enclosing)
     {
-      tree name;
       tree intermediate;
 
       if ((new_class_decl = find_as_inner_class (enclosing, class_type, cl)))
@@ -5527,19 +5531,12 @@ do_resolve_class (enclosing, class_type, decl, cl)
       /* Now go to the upper classes, bail out if necessary. */
       enclosing = CLASSTYPE_SUPER (TREE_TYPE (enclosing));
       if (!enclosing || enclosing == object_type_node)
-       break;
-      
-      if (TREE_CODE (enclosing) == RECORD_TYPE)
-       {
-         enclosing = TYPE_NAME (enclosing);
-         continue;
-       }
+        break;
 
-      if (TREE_CODE (enclosing) == IDENTIFIER_NODE)
-       BUILD_PTR_FROM_NAME (name, enclosing);
+      if (TREE_CODE (enclosing) == POINTER_TYPE)
+       enclosing = do_resolve_class (NULL, enclosing, NULL, NULL);
       else
-       name = enclosing;
-      enclosing = do_resolve_class (NULL, name, NULL, NULL);
+        enclosing = TYPE_NAME (enclosing);
     }
 
   /* 1- Check for the type in single imports. This will change
@@ -5592,10 +5589,19 @@ do_resolve_class (enclosing, class_type, decl, cl)
 
   /* 5- Check an other compilation unit that bears the name of type */
   load_class (TYPE_NAME (class_type), 0);
-  if (check_pkg_class_access (TYPE_NAME (class_type), 
-                             (cl ? cl : lookup_cl (decl))))
-    return NULL_TREE;
-
+  
+  if (!cl)
+    cl = lookup_cl (decl);
+  
+  /* If we don't have a value for CL, then we're being called recursively. 
+     We can't check package access just yet, but it will be taken care of
+     by the caller. */
+  if (cl)
+    {
+      if (check_pkg_class_access (TYPE_NAME (class_type), cl))
+        return NULL_TREE;
+    }
+  
   /* 6- Last call for a resolution */
   return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
 }
@@ -6671,9 +6677,16 @@ find_in_imports_on_demand (class_type)
         loaded and not seen in source yet, the load */
       if (!decl || (!CLASS_LOADED_P (TREE_TYPE (decl))
                    && !CLASS_FROM_SOURCE_P (TREE_TYPE (decl))))
-       load_class (node_to_use, 0);
+       {
+         load_class (node_to_use, 0);
+         decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type));
+       }
       lineno = saved_lineno;
-      return check_pkg_class_access (TYPE_NAME (class_type), cl);
+      if (! INNER_CLASS_P (TREE_TYPE (decl)))
+       return check_pkg_class_access (TYPE_NAME (class_type), cl);
+      else
+        /* 6.6.1: Inner classes are subject to member access rules. */
+        return 0;
     }
   else
     return (seen_once < 0 ? 0 : seen_once); /* It's ok not to have found */
@@ -6767,11 +6780,15 @@ lookup_package_type (name, from)
   return get_identifier (subname);
 }
 
+/* Check accessibility of inner classes according to member access rules. 
+   DECL is the inner class, ENCLOSING_DECL is the class from which the
+   access is being attempted. */
+
 static void
 check_inner_class_access (decl, enclosing_decl, cl)
      tree decl, enclosing_decl, cl;
 {
-  int access = 0;
+  const char *access;
 
   /* We don't issue an error message when CL is null. CL can be null
      as a result of processing a JDEP crafted by source_start_java_method
@@ -6781,30 +6798,69 @@ check_inner_class_access (decl, enclosing_decl, cl)
   if (!decl || !cl)
     return;
 
-  /* We grant access to private and protected inner classes if the
-     location from where we're trying to access DECL is an enclosing
-     context for DECL or if both have a common enclosing context. */
+  tree enclosing_decl_type = TREE_TYPE (enclosing_decl);
+
   if (CLASS_PRIVATE (decl))
-    access = 1;
-  if (CLASS_PROTECTED (decl))
-    access = 2;
-  if (!access)
-    return;
+    {
+      /* Access is permitted only within the body of the top-level
+         class in which DECL is declared. */
+      tree top_level = decl;
+      while (DECL_CONTEXT (top_level))
+        top_level = DECL_CONTEXT (top_level);      
+      while (DECL_CONTEXT (enclosing_decl))
+        enclosing_decl = DECL_CONTEXT (enclosing_decl);
+      if (top_level == enclosing_decl)
+        return;      
+      access = "private";
+    }
+  else if (CLASS_PROTECTED (decl))
+    {
+      tree decl_context;
+      /* Access is permitted from within the same package... */
+      if (in_same_package (decl, enclosing_decl))
+        return;
       
-  if (common_enclosing_context_p (TREE_TYPE (enclosing_decl),
-                                 TREE_TYPE (decl))
-      || enclosing_context_p (TREE_TYPE (enclosing_decl),
-                             TREE_TYPE (decl)))
+      /* ... or from within the body of a subtype of the context in which
+         DECL is declared. */
+      decl_context = DECL_CONTEXT (decl);
+      while (enclosing_decl)
+        {
+         if (CLASS_INTERFACE (decl))
+           {
+             if (interface_of_p (TREE_TYPE (decl_context), 
+                                 enclosing_decl_type))
+               return;
+           }
+         else
+           {
+             /* Eww. The order of the arguments is different!! */
+             if (inherits_from_p (enclosing_decl_type, 
+                                  TREE_TYPE (decl_context)))
+               return;
+           }
+         enclosing_decl = DECL_CONTEXT (enclosing_decl);
+       }      
+      access = "protected";
+    }
+  else if (! CLASS_PUBLIC (decl))
+    {
+      /* Access is permitted only from within the same package as DECL. */
+      if (in_same_package (decl, enclosing_decl))
+        return;
+      access = "non-public";
+    }
+  else
+    /* Class is public. */
     return;
 
-  parse_error_context (cl, "Can't access %s nested %s %s. Only public classes and interfaces in other packages can be accessed",
-                      (access == 1 ? "private" : "protected"),
+  parse_error_context (cl, "Nested %s %s is %s; cannot be accessed from here",
                       (CLASS_INTERFACE (decl) ? "interface" : "class"),
-                      lang_printable_name (decl, 0));
+                      lang_printable_name (decl, 0), access);
 }
 
-/* Check that CLASS_NAME refers to a PUBLIC class. Return 0 if no
-   access violations were found, 1 otherwise.  */
+/* Accessibility check for top-level classes. If CLASS_NAME is in a foreign 
+   package, it must be PUBLIC. Return 0 if no access violations were found, 
+   1 otherwise.  */
 
 static int
 check_pkg_class_access (class_name, cl)
@@ -6813,7 +6869,7 @@ check_pkg_class_access (class_name, cl)
 {
   tree type;
 
-  if (!QUALIFIED_P (class_name) || !IDENTIFIER_CLASS_VALUE (class_name))
+  if (!IDENTIFIER_CLASS_VALUE (class_name))
     return 0;
 
   if (!(type = TREE_TYPE (IDENTIFIER_CLASS_VALUE (class_name))))
@@ -6825,7 +6881,11 @@ check_pkg_class_access (class_name, cl)
          allowed. */
       tree l, r;
       breakdown_qualified (&l, &r, class_name);
+      if (!QUALIFIED_P (class_name) && !ctxp->package)
+       /* Both in the empty package. */
+        return 0;
       if (l == ctxp->package)
+       /* Both in the same package. */
        return 0;
 
       parse_error_context 
@@ -10948,6 +11008,35 @@ breakdown_qualified (left, right, source)
   return 0;
 }
 
+/* Return TRUE if two classes are from the same package. */
+
+static int
+in_same_package (name1, name2)
+  tree name1, name2;
+{
+  tree tmp;
+  tree pkg1;
+  tree pkg2;
+  
+  if (TREE_CODE (name1) == TYPE_DECL)
+    name1 = DECL_NAME (name1);
+  if (TREE_CODE (name2) == TYPE_DECL)
+    name2 = DECL_NAME (name2);
+
+  if (QUALIFIED_P (name1) != QUALIFIED_P (name2))
+    /* One in empty package. */
+    return 0;
+
+  if (QUALIFIED_P (name1) == 0 && QUALIFIED_P (name2) == 0)
+    /* Both in empty package. */
+    return 1;
+
+  breakdown_qualified (&pkg1, &tmp, name1);
+  breakdown_qualified (&pkg2, &tmp, name2);
+  
+  return (pkg1 == pkg2);
+}
+
 /* Patch tree nodes in a function body. When a BLOCK is found, push
    local variable decls if present.
    Same as java_complete_lhs, but does resolve static finals to values. */