=== modified file 'includes/menu.inc'
--- includes/menu.inc	2008-01-28 19:09:19 +0000
+++ includes/menu.inc	2008-01-29 16:30:56 +0000
@@ -609,6 +609,7 @@ function menu_tail_to_arg($arg, $map, $i
  */
 function _menu_link_translate(&$item) {
   $item['options'] = unserialize($item['options']);
+  $item['_original_options'] = $item['options'];
   if ($item['external']) {
     $item['access'] = 1;
     $map = array();
@@ -921,7 +922,6 @@ function menu_tree_collect_node_links(&$
  * Check access and perform other dynamic operations for each link in the tree.
  */
 function menu_tree_check_access(&$tree, $node_links = array()) {
-
   if ($node_links) {
     // Use db_rewrite_sql to evaluate view access without loading each full node.
     $nids = array_keys($node_links);
@@ -935,7 +935,6 @@ function menu_tree_check_access(&$tree, 
     }
   }
   _menu_tree_check_access($tree);
-  return;
 }
 
 /**
@@ -1492,7 +1491,7 @@ function menu_get_active_trail() {
  */
 function menu_get_active_breadcrumb() {
   $breadcrumb = array();
-  
+
   // No breadcrumb for the front page.
   if (drupal_is_front_page()) {
     return $breadcrumb;
@@ -1680,15 +1679,25 @@ function _menu_navigation_links_rebuild(
       }
     }
   }
-  $result = db_query("SELECT ml.link_path, ml.mlid, ml.router_path, ml.updated FROM {menu_links} ml WHERE ml.updated = 1");
+  $placeholders = implode(', ', array_fill(0, count($menu), "'%s'"));
+  $paths = array_key($menu);
+  $result = db_query("SELECT ml.link_path, ml.mlid, ml.router_path, ml.updated FROM {menu_links} ml WHERE ml.updated = 1 OR (router_path NOT IN ('. $placeholders .') AND external = 0 AND customized = 1)", $paths);
   while ($item = db_fetch_array($result)) {
     $router_path = _menu_find_router_path($menu, $item['link_path']);
     if (!empty($router_path) && ($router_path != $item['router_path'] || $item['updated'])) {
       // If the router path and the link path matches, it's surely a working
       // item, so we clear the updated flag.
-      db_query("UPDATE {menu_links} SET router_path = '%s', updated = %d WHERE mlid = %d", $router_path, $router_path != $item['link_path'], $item['mlid']);
+      $updated = $item['updated'] && $router_path != $item['link_path'];
+      db_query("UPDATE {menu_links} SET router_path = '%s', updated = %d WHERE mlid = %d", $router_path, $updated, $item['mlid']);
     }
   }
+  // Find any items where their router path does not exist any more.
+  $result = db_query('SELECT * FROM {menu_links} WHERE router_path NOT IN ('. $placeholders .') AND external = 0 AND updated = 0 AND customized = 0 ORDER BY depth DESC', array_keys($menu));
+  // Remove all such items. Starting from those with the greatest depth will
+  // minimize the amount of re-parenting done by menu_link_delete().
+  while ($item = db_fetch_array($result)) {
+    _menu_delete_item($item, TRUE);
+  }
 }
 
 /**
@@ -1713,17 +1722,21 @@ function menu_link_delete($mlid, $path =
 
 /**
  * Helper function for menu_link_delete; deletes a single menu link.
+ *
+ * @param $item
+ *   Item to be deleted.
+ * @param $force
+ *   Forces deletion. Internal use only, setting to TRUE is discouraged.
  */
-function _menu_delete_item($item) {
-  // System-created items are never deleted. Updated items are an exception,
-  // as they can be broken.
-  if ($item && ($item['module'] != 'system' || $item['updated'])) {
+function _menu_delete_item($item, $force = FALSE) {
+  if ($item && ($item['module'] != 'system' || $item['updated'] || $force)) {
     // Children get re-attached to the item's parent.
     if ($item['has_children']) {
       $result = db_query("SELECT mlid FROM {menu_links} WHERE plid = %d", $item['mlid']);
       while ($m = db_fetch_array($result)) {
         $child = menu_link_load($m['mlid']);
         $child['plid'] = $item['plid'];
+        $child['options'] = $child['_original_options'];
         menu_link_save($child);
       }
     }

