diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 123cb3fa84d428cefc53c498e2eb43fb2ed965c6..2a742ac49ee6027f91d9e3559917a46ed3dfe408 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,22 @@
+2003-10-03  Alexander Malmberg  <alexander@malmberg.org>
+	    Ziemowit Laski  <zlaski@apple.com>
+
+	* objc/objc-act.c (add_method_to_hash_list, lookup_category):
+	New functions.
+	(lookup_method_in_hash_lists): New parameter indicating whether
+	we are messaging 'Class' or 'id'.
+	(check_duplicates): Likewise; do not assume all methods will
+	be either class or instance methods.
+	(generate_category, finish_class): Use lookup_category().
+	(add_method): Use add_method_to_hash_list(); insert instance
+	methods of root classes into the global class method hash table.
+	(add_category): Use lookup_category(); avoid constructing
+	duplicate categories.
+	(really_start_method): Add method to corresponding @interface,
+	if not already there (and if the @interface exists).
+	(finish_message_expr, finish_objc): Adjust calls to
+	check_duplicates().
+
 2003-10-03  Roger Sayle  <roger@eyesopen.com>
 
 	PR optimization/9325, PR java/6391
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 42141a4ab42d9aa26f11383a4eef9891e6415798..6b6d2f1907f32f0aeec90a4e42f293e904bdb027 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -149,7 +149,7 @@ static tree build_private_template (tree);
 static void build_class_template (void);
 static void build_selector_template (void);
 static void build_category_template (void);
-static tree lookup_method_in_hash_lists (tree);
+static tree lookup_method_in_hash_lists (tree, int);
 static void build_super_template (void);
 static tree build_category_initializer (tree, tree, tree, tree, tree, tree);
 static tree build_protocol_initializer (tree, tree, tree, tree, tree);
@@ -184,8 +184,10 @@ static hash hash_lookup (hash *, tree);
 static void hash_add_attr (hash, tree);
 static tree lookup_method (tree, tree);
 static tree lookup_method_static (tree, tree, int);
+static void add_method_to_hash_list (hash *, tree);
 static tree add_class (tree);
 static void add_category (tree, tree);
+static tree lookup_category (tree, tree);
 
 enum string_section
 {
@@ -280,7 +282,7 @@ static tree build_shared_structure_initializer (tree, tree, tree, tree,
 static void generate_category (tree);
 static int is_objc_type_qualifier (tree);
 static tree adjust_type_for_id_default (tree);
-static tree check_duplicates (hash, int);
+static tree check_duplicates (hash, int, int);
 static tree receiver_is_class_object (tree, int, int);
 static int check_methods (tree, tree, int);
 static int conforms_to_protocol (tree, tree);
@@ -5064,6 +5066,18 @@ build_shared_structure_initializer (tree type, tree isa, tree super,
   return objc_build_constructor (type, nreverse (initlist));
 }
 
+/* Retrieve category interface CAT_NAME (if any) associated with CLASS.  */
+
+static tree
+lookup_category (tree class, tree cat_name)
+{
+  tree category = CLASS_CATEGORY_LIST (class);
+
+  while (category && CLASS_SUPER_NAME (category) != cat_name)
+    category = CLASS_CATEGORY_LIST (category);
+  return category;
+}
+
 /* static struct objc_category _OBJC_CATEGORY_<name> = { ... };  */
 
 static void
@@ -5078,15 +5092,8 @@ generate_category (tree cat)
 
   class_name_expr = add_objc_string (CLASS_NAME (cat), class_names);
 
-  category = CLASS_CATEGORY_LIST (implementation_template);
-
-  /* find the category interface from the class it is associated with */
-  while (category)
-    {
-      if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category))
-	break;
-      category = CLASS_CATEGORY_LIST (category);
-    }
+  category = lookup_category (implementation_template,
+				CLASS_SUPER_NAME (cat));
 
   if (category && CLASS_PROTOCOL_LIST (category))
     {
@@ -5481,7 +5488,7 @@ get_arg_type_list (tree meth, int context, int superflag)
 }
 
 static tree
-check_duplicates (hash hsh, int methods)
+check_duplicates (hash hsh, int methods, int is_class)
 {
   tree meth = NULL_TREE;
 
@@ -5494,15 +5501,23 @@ check_duplicates (hash hsh, int methods)
 	  /* We have two or more methods with the same name but
 	     different types.  */
 	  attr loop;
-	  char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+';
 
 	  warning ("multiple %s named `%c%s' found",
-		   methods ? "methods" : "selectors", type,
+		   methods ? "methods" : "selectors",
+		   (is_class ? '+' : '-'),
 		   IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
 
-	  warn_with_method (methods ? "using" : "found", type, meth);
+	  warn_with_method (methods ? "using" : "found",
+			    ((TREE_CODE (meth) == INSTANCE_METHOD_DECL)
+			     ? '-'
+			     : '+'), 
+			    meth);
 	  for (loop = hsh->list; loop; loop = loop->next)
-	    warn_with_method ("also found", type, loop->value);
+	    warn_with_method ("also found",
+			      ((TREE_CODE (loop->value) == INSTANCE_METHOD_DECL)
+			       ? '-' 
+			       : '+'),
+			      loop->value);
         }
     }
   return meth;
@@ -5638,17 +5653,27 @@ build_message_expr (tree mess)
   return finish_message_expr (receiver, sel_name, method_params);
 }
 
+/* Look up method SEL_NAME that would be suitable for receiver
+   of type 'id' (if IS_CLASS is zero) or 'Class' (if IS_CLASS is
+   non-zero), and report on any duplicates.  */
+
 static tree
-lookup_method_in_hash_lists (tree sel_name)
+lookup_method_in_hash_lists (tree sel_name, int is_class)
 {
-  hash method_prototype = hash_lookup (nst_method_hash_list,
-				       sel_name);
+  hash method_prototype = NULL;
+
+  if (!is_class)
+    method_prototype = hash_lookup (nst_method_hash_list,
+				    sel_name);
 					
   if (!method_prototype)
-    method_prototype = hash_lookup (cls_method_hash_list,
-				    sel_name);
+    {
+      method_prototype = hash_lookup (cls_method_hash_list,
+				      sel_name);
+      is_class = 1;
+    }
 
-  return check_duplicates (method_prototype, 1);
+  return check_duplicates (method_prototype, 1, is_class);
 }
 
 /* The 'finish_message_expr' routine is called from within
@@ -5726,9 +5751,8 @@ finish_message_expr (tree receiver, tree sel_name, tree method_params)
 					    is_class != NULL_TREE);
       if (!method_prototype && !rprotos)
 	method_prototype
-	  = (is_class
-	     ? check_duplicates (hash_lookup (cls_method_hash_list, sel_name), 1)
-	     : lookup_method_in_hash_lists (sel_name));
+	  = lookup_method_in_hash_lists (sel_name,
+					 is_class != NULL_TREE);
     }
   else
     {
@@ -6251,11 +6275,34 @@ lookup_method_static (tree interface, tree ident, int is_class)
   return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE;
 }
 
+/* Add the method to the hash list if it doesn't contain an identical
+   method already. */
+static void
+add_method_to_hash_list (hash *hash_list, tree method)
+{
+  hash hsh;
+
+  if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method))))
+    {
+      /* Install on a global chain.  */
+      hash_enter (hash_list, method);
+    }
+  else
+    {
+      /* Check types against those; if different, add to a list.  */
+      attr loop;
+      int already_there = comp_proto_with_proto (method, hsh->key);
+      for (loop = hsh->list; !already_there && loop; loop = loop->next)
+	already_there |= comp_proto_with_proto (method, loop->value);
+      if (!already_there)
+	hash_add_attr (hsh, method);
+    }
+}
+
 tree
 add_method (tree class, tree method, int is_class)
 {
   tree mth;
-  hash hsh;
 
   if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), method)))
     {
@@ -6273,10 +6320,11 @@ add_method (tree class, tree method, int is_class)
     }
   else
     {
-      /* When processing an @interface for a class or category, give hard errors on methods with
-	 identical selectors but differing argument and/or return types. We do not do this for
-	 @implementations, because C/C++ will do it for us (i.e., there will be
-	 duplicate function definition errors).  */
+      /* When processing an @interface for a class or category, give hard
+	 errors on methods with identical selectors but differing argument
+	 and/or return types. We do not do this for @implementations, because
+	 C/C++ will do it for us (i.e., there will be duplicate function
+	 definition errors).  */
       if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE
 	   || TREE_CODE (class) == CATEGORY_INTERFACE_TYPE)
 	  && !comp_proto_with_proto (method, mth))
@@ -6284,23 +6332,23 @@ add_method (tree class, tree method, int is_class)
 		is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
     }
 
-  if (!(hsh = hash_lookup (is_class
-			   ? cls_method_hash_list
-			   : nst_method_hash_list, METHOD_SEL_NAME (method))))
-    {
-      /* Install on a global chain.  */
-      hash_enter (is_class ? cls_method_hash_list : nst_method_hash_list, method);
-    }
+  if (is_class)
+    add_method_to_hash_list (cls_method_hash_list, method);
   else
     {
-      /* Check types against those; if different, add to a list.  */
-      attr loop;
-      int already_there = comp_proto_with_proto (method, hsh->key);
-      for (loop = hsh->list; !already_there && loop; loop = loop->next)
-	already_there |= comp_proto_with_proto (method, loop->value);
-      if (!already_there)
-	hash_add_attr (hsh, method);
+      add_method_to_hash_list (nst_method_hash_list, method);
+
+      /* Instance methods in root classes (and categories thereof)
+	 may acts as class methods as a last resort. */
+      if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE
+	  || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
+	class = lookup_interface (CLASS_NAME (class));
+
+      if (TREE_CODE (class) != PROTOCOL_INTERFACE_TYPE
+	  && !CLASS_SUPER_NAME (class))
+	add_method_to_hash_list (cls_method_hash_list, method);
     }
+
   return method;
 }
 
@@ -6317,23 +6365,19 @@ static void
 add_category (tree class, tree category)
 {
   /* Put categories on list in reverse order.  */
-  tree cat = CLASS_CATEGORY_LIST (class);
+  tree cat = lookup_category (class, CLASS_SUPER_NAME (category));
 
-  while (cat)
+  if (cat)
     {
-      if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category))
-#ifdef OBJCPLUS
-	error ("duplicate interface declaration for category `%s(%s)'",
-#else	
-	warning ("duplicate interface declaration for category `%s(%s)'",
-#endif	
-		 IDENTIFIER_POINTER (CLASS_NAME (class)),
-		 IDENTIFIER_POINTER (CLASS_SUPER_NAME (category)));
-      cat = CLASS_CATEGORY_LIST (cat);
+      warning ("duplicate interface declaration for category `%s(%s)'",
+	       IDENTIFIER_POINTER (CLASS_NAME (class)),
+	       IDENTIFIER_POINTER (CLASS_SUPER_NAME (category)));
+    }
+  else
+    {
+      CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
+      CLASS_CATEGORY_LIST (class) = category;
     }
-
-  CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
-  CLASS_CATEGORY_LIST (class) = category;
 }
 
 /* Called after parsing each instance variable declaration. Necessary to
@@ -6951,15 +6995,7 @@ finish_class (tree class)
 
   else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
     {
-      tree category = CLASS_CATEGORY_LIST (implementation_template);
-
-      /* Find the category interface from the class it is associated with.  */
-      while (category)
-	{
-	  if (CLASS_SUPER_NAME (class) == CLASS_SUPER_NAME (category))
-	    break;
-	  category = CLASS_CATEGORY_LIST (category);
-	}
+      tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class));
 
       if (category)
 	{
@@ -7753,12 +7789,34 @@ really_start_method (tree method, tree parmlist)
 				METHOD_SEL_NAME (method),
 				TREE_CODE (method) == CLASS_METHOD_DECL);
 
-      if (proto && ! comp_method_with_proto (method, proto))
+      if (proto)
 	{
-	  char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+');
+	  if (!comp_method_with_proto (method, proto))
+	    {
+	      char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+');
 
-	  warn_with_method ("conflicting types for", type, method);
-	  warn_with_method ("previous declaration of", type, proto);
+	      warn_with_method ("conflicting types for", type, method);
+	      warn_with_method ("previous declaration of", type, proto);
+	    }
+	}
+      else
+	{
+	  /* We have a method @implementation even though we did not
+	     see a corresponding @interface declaration (which is allowed
+	     by Objective-C rules).  Go ahead and place the method in
+	     the @interface anyway, so that message dispatch lookups
+	     will see it.  */
+	  tree interface = implementation_template;
+
+	  if (TREE_CODE (objc_implementation_context)
+	      == CATEGORY_IMPLEMENTATION_TYPE)
+	    interface = lookup_category
+			(interface,
+			 CLASS_SUPER_NAME (objc_implementation_context));
+
+	  if (interface)
+	    add_method (interface, copy_node (method),
+			TREE_CODE (method) == CLASS_METHOD_DECL);
 	}
     }
 }
@@ -8844,9 +8902,9 @@ finish_objc (void)
       for (slot = 0; slot < SIZEHASHTABLE; slot++)
 	{
 	  for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
-	    check_duplicates (hsh, 0);
+	    check_duplicates (hsh, 0, 1);
 	  for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
-	    check_duplicates (hsh, 0);
+	    check_duplicates (hsh, 0, 1);
 	}
     }
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7e10c016b4cce50af372e697341b5cfadc626b84..66151d408aefe8b91ed28ef4fd670583941df1c8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2003-10-03  Alexander Malmberg  <alexander@malmberg.org>
+	    Ziemowit Laski  <zlaski@apple.com>
+
+	* objc.dg/method-6.m ('starboard'): Move prototype from 'Base' to
+	'Derived', so that it is never considered a class method; add
+	new warning for '+port' method ambiguity.
+	* objc.dg/method-12.m: Include <objc/objc.h> instead of
+	<objc/objc-api.h> (needed on Mac OS X).
+	* objc.dg/method-13.m: New test.
+
 2003-10-03  Roger Sayle  <roger@eyesopen.com>
 
 	PR optimization/9325, PR java/6391
diff --git a/gcc/testsuite/objc.dg/method-12.m b/gcc/testsuite/objc.dg/method-12.m
index d6e6ce58a4fbfe8e3b003b03132184c5c5b453f3..411caac111ad283318ec7431a18ce6905a4e8097 100644
--- a/gcc/testsuite/objc.dg/method-12.m
+++ b/gcc/testsuite/objc.dg/method-12.m
@@ -1,7 +1,7 @@
 /* Contributed by Igor Seleznev <selez@mail.ru>.  */
 /* This used to be broken.  */
 
-#include <objc/objc-api.h>
+#include <objc/objc.h>
 
 @interface A
 + (A *)currentContext;
diff --git a/gcc/testsuite/objc.dg/method-13.m b/gcc/testsuite/objc.dg/method-13.m
new file mode 100644
index 0000000000000000000000000000000000000000..c824398ac5b9ba4d0cdf5f8379bf07a04add58ed
--- /dev/null
+++ b/gcc/testsuite/objc.dg/method-13.m
@@ -0,0 +1,77 @@
+/* Test if instance methods of root classes are used as class methods, if no
+   "real" methods are found.  For receivers of type 'id' and 'Class', all
+   root classes must be considered.  */
+/* Author: Ziemowit Laski <zlaski@apple.com>.  */
+/* { dg-do run } */
+
+#include <objc/objc.h>
+
+#ifdef __NEXT_RUNTIME__
+#define OBJC_GETCLASS objc_getClass
+#else
+#define OBJC_GETCLASS objc_get_class
+#endif
+
+extern void abort(void);
+extern int strcmp(const char *, const char *);
+#define CHECK_IF(expr) if(!(expr)) abort()
+
+@protocol Proto
+- (const char *) method4;
+@end
+
+@interface Root
+{ Class isa; }
++ (const char *) method2;
+@end
+
+@interface Derived: Root
+- (const char *) method1;
+- (const char *) method2;
+- (const char *) method3;
+@end
+
+@interface Root (Categ)
+- (const char *) method3;
+@end
+
+@implementation Root (Categ)
+- (const char *) method3 { return "Root(Categ)::-method3"; }
+- (const char *) method4 { return "Root(Categ)::-method4"; }
+@end
+
+@implementation Derived
+- (const char *) method1 { return "Derived::-method1"; }
+- (const char *) method2 { return "Derived::-method2"; }
+- (const char *) method3 { return "Derived::-method3"; }
+@end
+
+@implementation Root
+#ifdef __NEXT_RUNTIME__
++ initialize { return self; }
+#endif
+- (const char *) method1 { return "Root::-method1"; }
++ (const char *) method2 { return "Root::+method2"; }
+@end
+
+int main(void)
+{
+  Class obj = OBJC_GETCLASS("Derived");
+
+  /* None of the following should elicit compiler-time warnings.  */
+
+  CHECK_IF(!strcmp([Root method1], "Root::-method1"));
+  CHECK_IF(!strcmp([Root method2], "Root::+method2"));
+  CHECK_IF(!strcmp([Root method3], "Root(Categ)::-method3"));
+  CHECK_IF(!strcmp([Root method4], "Root(Categ)::-method4"));
+  CHECK_IF(!strcmp([Derived method1], "Root::-method1"));
+  CHECK_IF(!strcmp([Derived method2], "Root::+method2"));
+  CHECK_IF(!strcmp([Derived method3], "Root(Categ)::-method3"));
+  CHECK_IF(!strcmp([Derived method4], "Root(Categ)::-method4"));
+  CHECK_IF(!strcmp([obj method1], "Root::-method1"));
+  CHECK_IF(!strcmp([obj method2], "Root::+method2"));
+  CHECK_IF(!strcmp([obj method3], "Root(Categ)::-method3"));
+  CHECK_IF(!strcmp([obj method4], "Root(Categ)::-method4"));
+
+  return 0;
+}
diff --git a/gcc/testsuite/objc.dg/method-6.m b/gcc/testsuite/objc.dg/method-6.m
index 212958b55c7dc4445dd0ddcabc66c60629faa375..a4ca787b7f66ac5503fa42fc9593cd46e0077f8d 100644
--- a/gcc/testsuite/objc.dg/method-6.m
+++ b/gcc/testsuite/objc.dg/method-6.m
@@ -1,4 +1,5 @@
-/* Check that sending messages to variables of type 'Class' does not involve instance methods.  */
+/* Check that sending messages to variables of type 'Class' does not involve instance methods,
+   unless they reside in root classes.  */
 /* Author: Ziemowit Laski <zlaski@apple.com>  */
 /* { dg-do compile } */
 
@@ -6,21 +7,25 @@
 
 @interface Base
 - (unsigned)port;
-- (id)starboard;
 @end
 
 @interface Derived: Base
 - (Object *)port;
 + (Protocol *)port;
+- (id)starboard;
 @end
 
-id foo(void) {
+void foo(void) {
   Class receiver;
-  id p = [receiver port];  /* there should be no warnings here! */
-  p = [receiver starboard];  /* { dg-warning ".Class. may not respond to .\\+starboard." } */
-       /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 20 } */
-       /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 20 } */
-       /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 20 } */
-  p = [Class port];  /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */
-  return p;
+
+  [receiver port];  /* { dg-warning "multiple methods named .\\+port. found" } */
+       /* { dg-warning "using .\\-\\(unsigned\\)port." "" { target *-*-* } 9 } */
+       /* { dg-warning "also found .\\+\\(Protocol \\*\\)port." "" { target *-*-* } 14 } */
+
+  [receiver starboard];  /* { dg-warning ".Class. may not respond to .\\+starboard." } */
+       /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 25 } */
+       /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 25 } */
+       /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 25 } */
+
+  [Class port];  /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */
 }