diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 2b9bef58d883fb7196c0d74b15fd9fcbcf2a16df..3ea407057279f6498b83925f78425c117eeaf1bc 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,25 @@
+2002-01-23  Zack Weinberg  <zack@codesourcery.com>
+
+	* Make-lang.in (parse.c): Adjust expected number of
+	shift-reduce conflicts.
+	(decl.o): Depend on diagnostic.h.
+	* decl.c: Include diagnostic.h.
+	(grokdeclarator): Check for null pointer.
+	(finish_function): Don't abort when
+	current_binding_level->parm_flag != 1, if errors have
+	occurred; throw away the statement tree and extra binding
+	levels, and continue.
+	* lex.c (note_list_got_semicolon): Check for null pointer.
+	* method.c (hack_identifier): Just return error_mark_node if
+	value is error_mark_node.
+	* parse.y (primary: TYPEID(type_id)): No need to use
+	TYPE_MAIN_VARIANT here.
+	(handler_seq): Accept an empty list of catch clauses and
+	generate a fake handler block to avoid later crashes.
+	(ansi_raise_identifier): Accept the error token too.
+	* semantics.c (begin_class_definition,
+	finish_class_definition): Check for error_mark_node.
+
 2002-01-23  Zack Weinberg  <zack@codesourcery.com>
 
 	* typeck2.c (friendly_abort): Delete definition.
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index d848e3a5182a14e1b17bf2387702fe75cdb7e6ad..3b14ab181b3104191e131c4580d150096112129c 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -120,7 +120,7 @@ $(srcdir)/cp/cfns.h: $(srcdir)/cp/cfns.gperf
 
 $(srcdir)/cp/parse.h: $(srcdir)/cp/parse.c
 $(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
-	@echo "Expect 34 shift/reduce conflicts and 58 reduce/reduce conflicts."
+	@echo "Expect 36 shift/reduce conflicts and 58 reduce/reduce conflicts."
 	cd $(srcdir)/cp; $(BISON) $(BISONFLAGS) -d -o p$$$$.c parse.y ; \
 	grep '^#define[ 	]*YYEMPTY' p$$$$.c >> p$$$$.h ; \
 	mv -f p$$$$.c parse.c ; mv -f p$$$$.h parse.h
@@ -249,7 +249,7 @@ cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) toplev.h langhooks.h langhooks-def.h \
   c-common.h
 cp/decl.o: cp/decl.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h stack.h \
   output.h $(EXPR_H) except.h toplev.h hash.h $(GGC_H) $(RTL_H) \
-  cp/operators.def $(TM_P_H) tree-inline.h
+  cp/operators.def $(TM_P_H) tree-inline.h diagnostic.h
 cp/decl2.o: cp/decl2.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \
   output.h except.h toplev.h $(GGC_H) $(RTL_H)
 cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) flags.h toplev.h output.h $(TM_P_H) \
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 35211135cf0fe319f04564b5717868c54218c4e9..0bb5dfd404cdd60ba9a7b5bd9330823a0ff6d56e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -46,6 +46,7 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "target.h"
 #include "c-common.h"
+#include "diagnostic.h"
 
 extern const struct attribute_spec *lang_attribute_table;
 
@@ -10144,7 +10145,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 	 common.  With no options, it is allowed.  With -Wreturn-type,
 	 it is a warning.  It is only an error with -pedantic-errors.  */
       is_main = (funcdef_flag
-		 && MAIN_NAME_P (dname)
+		 && dname && MAIN_NAME_P (dname)
 		 && ctype == NULL_TREE
 		 && in_namespace == NULL_TREE
 		 && current_namespace == global_namespace);
@@ -14163,8 +14164,28 @@ finish_function (flags)
   /* This must come after expand_function_end because cleanups might
      have declarations (from inline functions) that need to go into
      this function's blocks.  */
+  
+  /* If the current binding level isn't the outermost binding level
+     for this function, either there is a bug, or we have experienced
+     syntax errors and the statement tree is malformed.  */
   if (current_binding_level->parm_flag != 1)
-    abort ();
+    {
+      /* Make sure we have already experienced errors.  */
+      if (errorcount == 0)
+	abort ();
+
+      /* Throw away the broken statement tree and extra binding
+         levels.  */
+      DECL_SAVED_TREE (fndecl) = build_stmt (COMPOUND_STMT, NULL_TREE);
+
+      while (current_binding_level->parm_flag != 1)
+	{
+	  if (current_binding_level->parm_flag == 2)
+	    pop_nested_class ();
+	  else
+	    poplevel (0, 0, 0);
+	}
+    }
   poplevel (1, 0, 1);
 
   /* Set up the named return value optimization, if we can.  Here, we
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index b30c8171675d3ea76aa988eb36fc8cb8a3701837..0287f7040323e0fb8422b950d69d87302f4cb215 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -1026,7 +1026,7 @@ note_list_got_semicolon (declspecs)
   for (link = declspecs; link; link = TREE_CHAIN (link))
     {
       tree type = TREE_VALUE (link);
-      if (TYPE_P (type))
+      if (type && TYPE_P (type))
 	note_got_semicolon (type);
     }
   clear_anon_tags ();
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 0848bd35a27155d58af7131fcf325f66bc307b46..b0cc63a5c0f0644183a57e9f44e28405d60a7e61 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -145,38 +145,7 @@ hack_identifier (value, name)
   tree type;
 
   if (value == error_mark_node)
-    {
-      if (current_class_name)
-	{
-	  tree fields = lookup_fnfields (TYPE_BINFO (current_class_type),
-					 name, 1);
-	  if (fields == error_mark_node)
-	    return error_mark_node;
-	  if (fields)
-	    {
-	      tree fndecl;
-
-	      fndecl = TREE_VALUE (fields);
-	      my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 251);
-	      /* I could not trigger this code. MvL */
-	      abort ();
-#ifdef DEAD
-	      if (DECL_CHAIN (fndecl) == NULL_TREE)
-		{
-		  warning ("methods cannot be converted to function pointers");
-		  return fndecl;
-		}
-	      else
-		{
-		  error ("ambiguous request for method pointer `%s'",
-			 IDENTIFIER_POINTER (name));
-		  return error_mark_node;
-		}
-#endif
-	    }
-	}
-      return error_mark_node;
-    }
+    return error_mark_node;
 
   type = TREE_TYPE (value);
   if (TREE_CODE (value) == FIELD_DECL)
diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y
index f6dba7ec4ceedcae53d159279ae5c9c03fc16f30..83a1cd020aa4d9247db58f0f6158f731c3aa38ce 100644
--- a/gcc/cp/parse.y
+++ b/gcc/cp/parse.y
@@ -1650,7 +1650,7 @@ primary:
 	| TYPEID '(' type_id ')'
 		{ tree type = groktypename ($3.t);
 		  check_for_new_type ("typeid", $3);
-		  $$ = get_typeid (TYPE_MAIN_VARIANT (type)); }
+		  $$ = get_typeid (type); }
 	| global_scope IDENTIFIER
 		{ $$ = do_scoped_id ($2, 1); }
 	| global_scope template_id
@@ -3505,6 +3505,15 @@ try_block:
 handler_seq:
 	  handler
 	| handler_seq handler
+	| /* empty */
+		{ /* Generate a fake handler block to avoid later aborts. */
+		  tree fake_handler = begin_handler ();
+		  finish_handler_parms (NULL_TREE, fake_handler);
+		  finish_handler (fake_handler);
+		  $<ttype>$ = fake_handler;
+
+		  error ("must have at least one catch per try block");
+		}
 	;
 
 handler:
@@ -3809,6 +3818,8 @@ ansi_raise_identifier:
 		  check_for_new_type ("exception specifier", $1);
 		  $$ = groktypename ($1.t);
 		}
+	  | error
+		{ $$ = error_mark_node; }
 	;
 
 ansi_raise_identifiers:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 1f8d48164769082a40d222d710063d92ab7b8f1c..37729bfd9670c6b0a8a770460abfe7df3427dbb5 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1669,6 +1669,9 @@ tree
 begin_class_definition (t)
      tree t;
 {
+  if (t == error_mark_node)
+    return error_mark_node;
+
   /* Check the bases are accessible. */
   decl_type_access_control (TYPE_NAME (t));
   reset_type_access_control ();
@@ -1878,6 +1881,9 @@ finish_class_definition (t, attributes, semi, pop_scope_p)
      int semi;
      int pop_scope_p;
 {
+  if (t == error_mark_node)
+    return error_mark_node;
+
   /* finish_struct nukes this anyway; if finish_exception does too,
      then it can go.  */
   if (semi)