diff --git a/MAINTAINERS.txt b/MAINTAINERS.txt
index 81eb1a36e59e015b7952e32176055e79190ff486..346cd4e28df58333a4ed2602447266d77eaa377d 100644
--- a/MAINTAINERS.txt
+++ b/MAINTAINERS.txt
@@ -186,7 +186,7 @@ Filter module
 - Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
 
 Forum module
-- ?
+- Lee Rowlands 'larowlan' <http://drupal.org/user/395439>
 
 Help module
 - ?
diff --git a/includes/common.inc b/includes/common.inc
index 1ef681f121a9afdbed0b40a206cd72792bb6a08e..f54f29a7c39faf62f1f1ece5e0c601f4009d2952 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -5041,7 +5041,15 @@ function drupal_cron_run() {
     drupal_register_shutdown_function('drupal_cron_cleanup');
 
     // Iterate through the modules calling their cron handlers (if any):
-    module_invoke_all('cron');
+    foreach (module_implements('cron') as $module) {
+      // Do not let an exception thrown by one module disturb another.
+      try {
+        module_invoke($module, 'cron');
+      }
+      catch (Exception $e) {
+        watchdog_exception('cron', $e);
+      }
+    }
 
     // Record cron time
     variable_set('cron_last', REQUEST_TIME);
diff --git a/includes/file.inc b/includes/file.inc
index 30fd44577515d942334a22a170369ec3984aa535..6e2e5cb2828c9f4622b9253feed8a296b463050d 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -1539,7 +1539,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
   // directory. This overcomes open_basedir restrictions for future file
   // operations.
   $file->uri = $file->destination;
-  if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->uri)) {
+  if (!drupal_move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->uri)) {
     form_set_error($source, t('File upload error. Could not move uploaded file.'));
     watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->uri));
     return FALSE;
@@ -1566,6 +1566,42 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
   return FALSE;
 }
 
+/**
+ * Moves an uploaded file to a new location.
+ *
+ * PHP's move_uploaded_file() does not properly support streams if safe_mode
+ * or open_basedir are enabled, so this function fills that gap.
+ *
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param $filename
+ *   The filename of the uploaded file.
+ * @param $uri
+ *   A string containing the destination URI of the file.
+ *
+ * @return
+ *   TRUE on success, or FALSE on failure.
+ *
+ * @see move_uploaded_file()
+ * @ingroup php_wrappers
+ */
+function drupal_move_uploaded_file($filename, $uri) {
+  $result = @move_uploaded_file($filename, $uri);
+  // PHP's move_uploaded_file() does not properly support streams if safe_mode
+  // or open_basedir are enabled so if the move failed, try finding a real path
+  // and retry the move operation.
+  if (!$result) {
+    if ($realpath = drupal_realpath($uri)) {
+      $result = move_uploaded_file($filename, $realpath);
+    }
+    else {
+      $result = move_uploaded_file($filename, $uri);
+    }
+  }
+
+  return $result;
+}
 
 /**
  * Check that a file meets the criteria specified by the validators.
diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index 68784d13a75edb61fcb33dbb134fec170e834bc9..88f9231ac8ce711cee6e21b17a52c2859e40a0ed 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -675,10 +675,6 @@ function hook_field_is_empty($item, $field) {
  * Widget hooks are typically called by the Field Attach API during the
  * creation of the field form structure with field_attach_form().
  *
- * @see hook_field_widget_info_alter()
- * @see hook_field_widget_form()
- * @see hook_field_widget_error()
- *
  * @return
  *   An array describing the widget types implemented by the module.
  *   The keys are widget type names. To avoid name clashes, widget type
@@ -704,6 +700,12 @@ function hook_field_is_empty($item, $field) {
  *       - FIELD_BEHAVIOR_DEFAULT: (default) If the widget accepts default
  *         values.
  *       - FIELD_BEHAVIOR_NONE: if the widget does not support default values.
+ *
+ * @see hook_field_widget_info_alter()
+ * @see hook_field_widget_form()
+ * @see hook_field_widget_form_alter()
+ * @see hook_field_widget_WIDGET_TYPE_form_alter()
+ * @see hook_field_widget_error()
  */
 function hook_field_widget_info() {
     return array(
@@ -783,8 +785,8 @@ function hook_field_widget_info_alter(&$info) {
  * properties from $field and $instance and set them as ad-hoc
  * $element['#custom'] properties, for later use by its element callbacks.
  *
- * @see field_widget_field()
- * @see field_widget_instance()
+ * Other modules may alter the form element provided by this function using
+ * hook_field_widget_form_alter().
  *
  * @param $form
  *   The form structure where widgets are being attached to. This might be a
@@ -826,6 +828,11 @@ function hook_field_widget_info_alter(&$info) {
  *
  * @return
  *   The form elements for a single widget for this field.
+ *
+ * @see field_widget_field()
+ * @see field_widget_instance()
+ * @see hook_field_widget_form_alter()
+ * @see hook_field_widget_WIDGET_TYPE_form_alter()
  */
 function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
   $element += array(
@@ -835,6 +842,69 @@ function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langco
   return $element;
 }
 
+/**
+ * Alter forms for field widgets provided by other modules.
+ *
+ * @param $element
+ *   The field widget form element as constructed by hook_field_widget_form().
+ * @param $form_state
+ *   An associative array containing the current state of the form.
+ * @param $context
+ *   An associative array containing the following key-value pairs, matching the
+ *   arguments received by hook_field_widget_form():
+ *   - "form": The form structure where widgets are being attached to. This
+ *     might be a full form structure, or a sub-element of a larger form.
+ *   - "field": The field structure.
+ *   - "instance": The field instance structure.
+ *   - "langcode": The language associated with $items.
+ *   - "items": Array of default values for this field.
+ *   - "delta": The order of this item in the array of subelements (0, 1, 2,
+ *     etc).
+ *
+ * @see hook_field_widget_form()
+ * @see hook_field_widget_WIDGET_TYPE_form_alter
+ */
+function hook_field_widget_form_alter(&$element, &$form_state, $context) {
+  // Add a css class to widget form elements for all fields of type mytype.
+  if ($context['field']['type'] == 'mytype') {
+    // Be sure not to overwrite existing attributes.
+    $element['#attributes']['class'][] = 'myclass';
+  }
+}
+
+/**
+ * Alter widget forms for a specific widget provided by another module.
+ *
+ * Modules can implement hook_field_widget_WIDGET_TYPE_form_alter() to modify a
+ * specific widget form, rather than using hook_field_widget_form_alter() and
+ * checking the widget type.
+ *
+ * @param $element
+ *   The field widget form element as constructed by hook_field_widget_form().
+ * @param $form_state
+ *   An associative array containing the current state of the form.
+ * @param $context
+ *   An associative array containing the following key-value pairs, matching the
+ *   arguments received by hook_field_widget_form():
+ *   - "form": The form structure where widgets are being attached to. This
+ *     might be a full form structure, or a sub-element of a larger form.
+ *   - "field": The field structure.
+ *   - "instance": The field instance structure.
+ *   - "langcode": The language associated with $items.
+ *   - "items": Array of default values for this field.
+ *   - "delta": The order of this item in the array of subelements (0, 1, 2,
+ *     etc).
+ *
+ * @see hook_field_widget_form()
+ * @see hook_field_widget_form_alter()
+ */
+function hook_field_widget_WIDGET_TYPE_form_alter(&$element, &$form_state, $context) {
+  // Code here will only act on widgets of type WIDGET_TYPE.  For example,
+  // hook_field_widget_mymodule_autocomplete_form_alter() will only act on
+  // widgets of type 'mymodule_autocomplete'.
+  $element['#autocomplete_path'] = 'mymodule/autocomplete_path';
+}
+
 /**
  * Flag a field-level validation error.
  *
diff --git a/modules/field/field.form.inc b/modules/field/field.form.inc
index 640ea75ec08ff6dc774d0c3dabe541a041602c14..79fc14a20e87c4324e6d6193984f2e395ff9c802 100644
--- a/modules/field/field.form.inc
+++ b/modules/field/field.form.inc
@@ -76,6 +76,17 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
           '#delta' => $delta,
         );
         if ($element = $function($form, $form_state, $field, $instance, $langcode, $items, $delta, $element)) {
+          // Allow modules to alter the field widget form element.
+          $context = array(
+            'form' => $form,
+            'field' => $field,
+            'instance' => $instance,
+            'langcode' => $langcode,
+            'items' => $items,
+            'delta' => $delta,
+          );
+          drupal_alter(array('field_widget_form', 'field_widget_' . $instance['widget']['type'] . '_form'), $element, $form_state, $context);
+
           // If we're processing a specific delta value for a field where the
           // field module handles multiples, set the delta in the result.
           // For fields that handle their own processing, we can't make
@@ -193,6 +204,18 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form,
             '#weight' => 100,
           );
         }
+
+        // Allow modules to alter the field widget form element.
+        $context = array(
+          'form' => $form,
+          'field' => $field,
+          'instance' => $instance,
+          'langcode' => $langcode,
+          'items' => $items,
+          'delta' => $delta,
+        );
+        drupal_alter(array('field_widget_form', 'field_widget_' . $instance['widget']['type'] . '_form'), $element, $form_state, $context);
+
         $field_elements[$delta] = $element;
       }
     }
diff --git a/modules/field/field.module b/modules/field/field.module
index 6432ce06062c7db490fdd8ba402686cf3af20dd8..30166bdeecfd4049aa73ffef37abd234dc410cf8 100644
--- a/modules/field/field.module
+++ b/modules/field/field.module
@@ -305,13 +305,6 @@ class FieldException extends Exception {}
  */
 class FieldUpdateForbiddenException extends FieldException {}
 
-/**
- * Implements hook_flush_caches().
- */
-function field_flush_caches() {
-  return array('cache_field');
-}
-
 /**
  * Implements hook_help().
  */
@@ -370,6 +363,7 @@ function field_theme() {
  * Purges some deleted Field API data, if any exists.
  */
 function field_cron() {
+  field_sync_field_status();
   $limit = variable_get('field_purge_batch_size', 10);
   field_purge_batch($limit);
 }
@@ -386,45 +380,84 @@ function field_modules_uninstalled($modules) {
 }
 
 /**
- * Implements hook_modules_enabled().
+ * Implements hook_system_info_alter().
+ *
+ * Goes through a list of all modules that provide a field type, and makes them
+ * required if there are any active fields of that type.
  */
-function field_modules_enabled($modules) {
-  foreach ($modules as $module) {
-    field_associate_fields($module);
+function field_system_info_alter(&$info, $file, $type) {
+  if ($type == 'module' && module_hook($file->name, 'field_info')) {
+    $fields = field_read_fields(array('module' => $file->name), array('include_deleted' => TRUE));
+    if ($fields) {
+      $info['required'] = TRUE;
+
+      // Provide an explanation message (only mention pending deletions if there
+      // remains no actual, non-deleted fields)
+      $non_deleted = FALSE;
+      foreach ($fields as $field) {
+        if (empty($field['deleted'])) {
+          $non_deleted = TRUE;
+          break;
+        }
+      }
+      if ($non_deleted) {
+        if (module_exists('field_ui')) {
+          $explanation = t('Field type(s) in use - see !link', array('!link' => l(t('Field list'), 'admin/reports/fields')));
+        }
+        else {
+          $explanation = t('Fields type(s) in use');
+        }
+      }
+      else {
+        $explanation = t('Fields pending deletion');
+      }
+      $info['explanation'] = $explanation;
+    }
   }
-  field_cache_clear();
 }
 
 /**
- * Implements hook_modules_disabled().
+ * Implements hook_flush_caches().
+ */
+function field_flush_caches() {
+  field_sync_field_status();
+  return array('cache_field');
+}
+
+/**
+ * Refreshes the 'active' and 'storage_active' columns for fields.
  */
-function field_modules_disabled($modules) {
-  // Track fields whose field type is being disabled.
+function field_sync_field_status() {
+  // Refresh the 'active' and 'storage_active' columns according to the current
+  // set of enabled modules.
+  $all_modules = system_rebuild_module_data();
+  $modules = array();
+  foreach ($all_modules as $module_name => $module) {
+    if ($module->status) {
+      $modules[] = $module_name;
+      field_associate_fields($module_name);
+    }
+  }
   db_update('field_config')
     ->fields(array('active' => 0))
-    ->condition('module', $modules, 'IN')
+    ->condition('module', $modules, 'NOT IN')
     ->execute();
-
-  // Track fields whose storage backend is being disabled.
   db_update('field_config')
     ->fields(array('storage_active' => 0))
-    ->condition('storage_module', $modules, 'IN')
+    ->condition('storage_module', $modules, 'NOT IN')
     ->execute();
-
-  field_cache_clear();
 }
 
 /**
  * Allows a module to update the database for fields and columns it controls.
  *
- * @param string $module
+ * @param $module
  *   The name of the module to update on.
  */
 function field_associate_fields($module) {
   // Associate field types.
-  $field_types =(array) module_invoke($module, 'field_info');
+  $field_types = (array) module_invoke($module, 'field_info');
   foreach ($field_types as $name => $field_info) {
-    watchdog('field', 'Updating field type %type with module %module.', array('%type' => $name, '%module' => $module));
     db_update('field_config')
       ->fields(array('module' => $module, 'active' => 1))
       ->condition('type', $name)
@@ -433,7 +466,6 @@ function field_associate_fields($module) {
   // Associate storage backends.
   $storage_types = (array) module_invoke($module, 'field_storage_info');
   foreach ($storage_types as $name => $storage_info) {
-    watchdog('field', 'Updating field storage %type with module %module.', array('%type' => $name, '%module' => $module));
     db_update('field_config')
       ->fields(array('storage_module' => $module, 'storage_active' => 1))
       ->condition('storage_type', $name)
diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test
index ebb1c9f9194f5ed3e14afc60a118b2ce1e62ce9c..669fc37cf44104ca07fe06a2ae6e9a5fa34f9ac2 100644
--- a/modules/field/tests/field.test
+++ b/modules/field/tests/field.test
@@ -2356,6 +2356,7 @@ class FieldCrudTestCase extends FieldTestCase {
     $this->assertTrue($field_definition <= $field, t('The field was properly read.'));
 
     module_disable($modules, FALSE);
+    drupal_flush_all_caches();
 
     $fields = field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE));
     $this->assertTrue(isset($fields[$field_name]) && $field_definition < $field, t('The field is properly read when explicitly fetching inactive fields.'));
@@ -2368,6 +2369,7 @@ class FieldCrudTestCase extends FieldTestCase {
 
       $module = array_shift($modules);
       module_enable(array($module), FALSE);
+      drupal_flush_all_caches();
     }
 
     // Check that the field is active again after all modules have been
diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc
index 9cd5ee15da7de54f2589c6698ce0ccce30a634aa..3f60085d8747d65fe15f66698af603acffeb797a 100644
--- a/modules/field_ui/field_ui.admin.inc
+++ b/modules/field_ui/field_ui.admin.inc
@@ -12,17 +12,27 @@ function field_ui_fields_list() {
   $instances = field_info_instances();
   $field_types = field_info_field_types();
   $bundles = field_info_bundles();
+
+  $modules = system_rebuild_module_data();
+
   $header = array(t('Field name'), t('Field type'), t('Used in'));
   $rows = array();
   foreach ($instances as $entity_type => $type_bundles) {
     foreach ($type_bundles as $bundle => $bundle_instances) {
       foreach ($bundle_instances as $field_name => $instance) {
         $field = field_info_field($field_name);
+
+        // Initialize the row if we encounter the field for the first time.
+        if (!isset($rows[$field_name])) {
+          $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
+          $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
+          $module_name = $field_types[$field['type']]['module'];
+          $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
+        }
+
+        // Add the current instance.
         $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
-        $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
-        $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'];
         $rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label'];
-        $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
       }
     }
   }
@@ -1717,6 +1727,14 @@ function field_ui_field_delete_form_submit($form, &$form_state) {
 
   $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
   $form_state['redirect'] = field_ui_get_destinations(array($admin_path . '/fields'));
+
+  // Fields are purged on cron. However field module prevents disabling modules
+  // when field types they provided are used in a field until it is fully
+  // purged. In the case that a field has minimal or no content, a single call
+  // to field_purge_batch() will remove it from the system. Call this with a
+  // low batch limit to avoid administrators having to wait for cron runs when
+  // removing instances that meet this criteria.
+  field_purge_batch(10);
 }
 
 /**
diff --git a/modules/forum/forum-list.tpl.php b/modules/forum/forum-list.tpl.php
index bc0935f888234303ebc034fa2dc6ba88ee52b5c0..257cea947d944a61b381070f7c52166407eb0665 100644
--- a/modules/forum/forum-list.tpl.php
+++ b/modules/forum/forum-list.tpl.php
@@ -15,6 +15,8 @@
  *   FALSE if the forum can contain only topics.
  * - $forum->depth: How deep the forum is in the current hierarchy.
  * - $forum->zebra: 'even' or 'odd' string used for row class.
+ * - $forum->icon_class: 'default' or 'new' string used for forum icon class.
+ * - $forum->icon_title: Text alternative for the forum icon.
  * - $forum->name: The name of the forum.
  * - $forum->link: The URL to link to this forum.
  * - $forum->description: The description of this forum.
@@ -48,6 +50,9 @@
                * left-margin for indenting.
                */ ?>
         <?php print str_repeat('<div class="indent">', $forum->depth); ?>
+          <div class="icon forum-status-<?php print $forum->icon_class; ?>" title="<?php print $forum->icon_title; ?>">
+            <span class="element-invisible"><?php print $forum->icon_title; ?></span>
+          </div>
           <div class="name"><a href="<?php print $forum->link; ?>"><?php print $forum->name; ?></a></div>
           <?php if ($forum->description): ?>
             <div class="description"><?php print $forum->description; ?></div>
diff --git a/modules/forum/forum-rtl.css b/modules/forum/forum-rtl.css
index d31c9e7f372effc98e105a292391979a28ce300e..81dd4d39606a7a2dbc443f0fa484f4835804c18c 100644
--- a/modules/forum/forum-rtl.css
+++ b/modules/forum/forum-rtl.css
@@ -1,8 +1,7 @@
 
-#forum tr td.forum {
-  padding-left: 0.5em;
-  padding-right: 25px;
-  background-position: 98% 2px;
+#forum td.forum .icon {
+  float: right;
+  margin: 0 0 0 9px;
 }
 .forum-topic-navigation {
   padding: 1em 3em 0 0;
diff --git a/modules/forum/forum.css b/modules/forum/forum.css
index 3f3ed98481ce779676bbf7dc6a7d44964afc7fed..4a67c8bcdab26b8e7209491389684ca911389cc4 100644
--- a/modules/forum/forum.css
+++ b/modules/forum/forum.css
@@ -11,15 +11,19 @@
 #forum td.pager {
   white-space: nowrap;
 }
-#forum tr td.forum {
-  padding-left: 25px; /* LTR */
-  background-position: 2px 2px; /* LTR */
-  background-image: url(../../misc/forum-default.png);
+
+#forum td.forum .icon {
+  background-image: url(../../misc/forum-icons.png);
   background-repeat: no-repeat;
+  float: left; /* LTR */
+  height: 24px;
+  margin: 0 9px 0 0; /* LTR */
+  width: 24px;
 }
-#forum tr.new-topics td.forum {
-  background-image: url(../../misc/forum-new.png);
+#forum td.forum .forum-status-new {
+  background-position: -24px 0;
 }
+
 #forum div.indent {
   margin-left: 20px;
 }
diff --git a/modules/forum/forum.install b/modules/forum/forum.install
index b5817ab2992f53f80be7fd6ba3d8d90cc86eef22..2eebd7fba3ee2087bc06f8e152c39910222d1068 100644
--- a/modules/forum/forum.install
+++ b/modules/forum/forum.install
@@ -113,6 +113,11 @@ function forum_uninstall() {
   variable_del('forum_block_num_active');
   variable_del('forum_block_num_new');
   variable_del('node_options_forum');
+
+  field_delete_field('taxonomy_forums');
+  // Purge field data now to allow taxonomy module to be uninstalled
+  // if this is the only field remaining.
+  field_purge_batch(10);
 }
 
 /**
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index f2ac5acc51eaff5e27ff2df308957078019a0161..5bb43925bc55a9f10bb2f989053f9cb00d4b63fd 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -1064,11 +1064,15 @@ function template_preprocess_forum_list(&$variables) {
     $variables['forums'][$id]->new_url = '';
     $variables['forums'][$id]->new_topics = 0;
     $variables['forums'][$id]->old_topics = $forum->num_topics;
+    $variables['forums'][$id]->icon_class = 'default';
+    $variables['forums'][$id]->icon_title = t('No new posts');
     if ($user->uid) {
       $variables['forums'][$id]->new_topics = _forum_topics_unread($forum->tid, $user->uid);
       if ($variables['forums'][$id]->new_topics) {
         $variables['forums'][$id]->new_text = format_plural($variables['forums'][$id]->new_topics, '1 new', '@count new');
         $variables['forums'][$id]->new_url = url("forum/$forum->tid", array('fragment' => 'new'));
+        $variables['forums'][$id]->icon_class = 'new';
+        $variables['forums'][$id]->icon_title = t('New posts');
       }
       $variables['forums'][$id]->old_topics = $forum->num_topics - $variables['forums'][$id]->new_topics;
     }
diff --git a/modules/forum/forum.test b/modules/forum/forum.test
index 1dc45c6fdf61b4d13b81acd5b4ec41afdb268532..c7c3d9c1b8c2e2327273874a1ed0d55f671afe34 100644
--- a/modules/forum/forum.test
+++ b/modules/forum/forum.test
@@ -31,6 +31,7 @@ class ForumTestCase extends DrupalWebTestCase {
     // Create users.
     $this->admin_user = $this->drupalCreateUser(array(
       'access administration pages',
+      'administer modules',
       'administer blocks',
       'administer forums',
       'administer menu',
@@ -51,6 +52,30 @@ class ForumTestCase extends DrupalWebTestCase {
     $this->web_user = $this->drupalCreateUser(array());
   }
 
+  /**
+   * Tests disabling and re-enabling forum.
+   */
+  function testEnableForumField() {
+    $this->drupalLogin($this->admin_user);
+
+    // Disable the forum module.
+    $edit = array();
+    $edit['modules[Core][forum][enable]'] = FALSE;
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
+    module_list(TRUE);
+    $this->assertFalse(module_exists('forum'), t('Forum module is not enabled.'));
+
+    // Attempt to re-enable the forum module and ensure it does not try to
+    // recreate the taxonomy_forums field.
+    $edit = array();
+    $edit['modules[Core][forum][enable]'] = 'forum';
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
+    module_list(TRUE);
+    $this->assertTrue(module_exists('forum'), t('Forum module is enabled.'));
+  }
+
   /**
    * Login users, create forum nodes, and test forum functionality through the admin and user interfaces.
    */
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 01c6bcc801ecdb115b5c5849a77c8a5acab5a9f0..2737c2bd8dde405730571b4fa4d3ec96dea43559 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -594,6 +594,10 @@ function poll_update($node) {
         ->condition('nid', $node->nid)
         ->condition('chid', $key)
         ->execute();
+      db_delete('poll_choice')
+        ->condition('nid', $node->nid)
+        ->condition('chid', $choice['chid'])
+        ->execute();
     }
   }
 }
diff --git a/modules/poll/poll.test b/modules/poll/poll.test
index d6c4f4005ba5d4c0485458d50647a9439c7672da..d7648a6bad29335f094e2b63528fea191aea8f90 100644
--- a/modules/poll/poll.test
+++ b/modules/poll/poll.test
@@ -746,3 +746,39 @@ class PollExpirationTestCase extends PollTestCase {
     $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Poll has expired.'));
   }
 }
+
+class PollDeleteChoiceTestCase extends PollTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Poll choice deletion',
+      'description' => 'Test the poll choice deletion logic.',
+      'group' => 'Poll',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('poll');
+  }
+
+  function testChoiceRemoval() {
+    // Set up a poll with three choices.
+    $title = $this->randomName();
+    $choices = array('First choice', 'Second choice', 'Third choice');
+    $poll_nid = $this->pollCreate($title, $choices, FALSE);
+    $this->assertTrue($poll_nid, t('Poll for choice deletion logic test created.'));
+
+    // Edit the poll, and try to delete first poll choice.
+    $this->drupalGet("node/$poll_nid/edit");
+    $edit['choice[chid:1][chtext]'] = '';
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Click on the poll title to go to node page.
+    $this->drupalGet('poll');
+    $this->clickLink($title);
+
+    // Check the first poll choice is deleted, while the others remain.
+    $this->assertNoText('First choice', t('First choice removed.'));
+    $this->assertText('Second choice', t('Second choice remains.'));
+    $this->assertText('Third choice', t('Third choice remains.'));
+  }
+}
diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module
index 9b6178804c9087b7d5144e45a23d6f7d48fc0d87..c400eaed11423b857b50fed0c31160f7c17e416c 100644
--- a/modules/simpletest/tests/common_test.module
+++ b/modules/simpletest/tests/common_test.module
@@ -225,3 +225,16 @@ function common_test_js_and_css_querystring() {
    drupal_add_css('/' . drupal_get_path('module', 'node') . '/node-fake.css?arg1=value1&arg2=value2');
    return '';
 }
+
+/**
+ * Implements hook_cron().
+ *
+ * System module should handle if a module does not catch an exception and keep
+ * cron going.
+ *
+ * @see common_test_cron_helper()
+ *
+ */
+function common_test_cron() {
+  throw new Exception(t('Uncaught exception'));
+}
diff --git a/modules/simpletest/tests/common_test_cron_helper.info b/modules/simpletest/tests/common_test_cron_helper.info
new file mode 100644
index 0000000000000000000000000000000000000000..ce1a6326fb330068c919cb1e614f028be4aab01a
--- /dev/null
+++ b/modules/simpletest/tests/common_test_cron_helper.info
@@ -0,0 +1,6 @@
+name = "Common Test Cron Helper"
+description = "Helper module for CronRunTestCase::testCronExceptions()."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
diff --git a/modules/simpletest/tests/common_test_cron_helper.module b/modules/simpletest/tests/common_test_cron_helper.module
new file mode 100644
index 0000000000000000000000000000000000000000..94a2b2c43821ae8e8f41ff6a3a6a81fbc984868e
--- /dev/null
+++ b/modules/simpletest/tests/common_test_cron_helper.module
@@ -0,0 +1,17 @@
+<?php
+/**
+ * @file
+ * Helper module for the testCronExceptions in addition to common_test module.
+ */
+
+/**
+ * Implements hook_cron().
+ *
+ * common_test_cron() throws an exception, but the execution should reach this
+ * function as well.
+ *
+ * @see common_test_cron()
+ */
+function common_test_cron_helper_cron() {
+  variable_set('common_test_cron', 'success');
+}
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index aa769a4b9580ccccef378565a2b1df951f6e6d1e..9dffd5999b19d9534590f31368e3c7a25c493bce 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -799,7 +799,7 @@ function system_modules($form, $form_state = array()) {
     $extra['enabled'] = (bool) $module->status;
     if (!empty($module->info['required'] )) {
       $extra['disabled'] = TRUE;
-      $extra['required_by'][] = $distribution_name;
+      $extra['required_by'][] = $distribution_name . (!empty($module->info['explanation']) ? ' ('. $module->info['explanation'] .')' : '');
     }
 
     // If this module requires other modules, add them to the array.
@@ -3131,4 +3131,4 @@ function system_action_delete_orphans_post($orphaned) {
 function system_actions_remove_orphans() {
   actions_synchronize(TRUE);
   drupal_goto('admin/config/system/actions/manage');
-}
\ No newline at end of file
+}
diff --git a/modules/system/system.test b/modules/system/system.test
index 9944619ec45b5fcd80f2baa4ec40239de4ea5023..1ce8e6b7e0ed106cc7582a32d8f4e14f64f5357b 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -445,39 +445,6 @@ class ModuleDependencyTestCase extends ModuleTestCase {
 
   }
 
-  /**
-   * Tests re-enabling forum with taxonomy disabled.
-   */
-  function testEnableForumTaxonomyFieldDependency() {
-    // Enable the forum module.
-    $edit = array();
-    $edit['modules[Core][forum][enable]'] = 'forum';
-    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
-    $this->assertModules(array('forum'), TRUE);
-
-    // Disable the forum module.
-    $edit = array();
-    $edit['modules[Core][forum][enable]'] = FALSE;
-    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
-    $this->assertModules(array('forum'), FALSE);
-
-    // Disable the taxonomy module.
-    $edit = array();
-    $edit['modules[Core][taxonomy][enable]'] = FALSE;
-    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
-    $this->assertModules(array('taxonomy'), FALSE);
-
-    // Attempt to re-enable the forum module with taxonomy disabled and ensure
-    // forum does not try to recreate the taxonomy_forums field.
-    $edit = array();
-    $edit['modules[Core][forum][enable]'] = 'forum';
-    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
-    $this->assertText(t('Some required modules must be enabled'), t('Dependency required.'));
-    $this->drupalPost(NULL, NULL, t('Continue'));
-    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
-    $this->assertModules(array('taxonomy', 'forum'), TRUE);
-  }
-
   /**
    * Tests that module dependencies are enabled in the correct order via the
    * UI. Dependencies should be enabled before their dependents.
@@ -516,18 +483,18 @@ class ModuleDependencyTestCase extends ModuleTestCase {
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
     $this->assertModules(array('forum'), TRUE);
 
-    // Disable forum and taxonomy. Both should now be installed but disabled.
+    // Disable forum and comment. Both should now be installed but disabled.
     $edit = array('modules[Core][forum][enable]' => FALSE);
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
     $this->assertModules(array('forum'), FALSE);
-    $edit = array('modules[Core][taxonomy][enable]' => FALSE);
+    $edit = array('modules[Core][comment][enable]' => FALSE);
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
-    $this->assertModules(array('taxonomy'), FALSE);
+    $this->assertModules(array('comment'), FALSE);
 
     // Check that the taxonomy module cannot be uninstalled.
     $this->drupalGet('admin/modules/uninstall');
-    $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[taxonomy]"]');
-    $this->assert(count($checkbox) == 1, t('Checkbox for uninstalling the taxonomy module is disabled.'));
+    $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[comment]"]');
+    $this->assert(count($checkbox) == 1, t('Checkbox for uninstalling the comment module is disabled.'));
 
     // Uninstall the forum module, and check that taxonomy now can also be
     // uninstalled.
@@ -535,7 +502,7 @@ class ModuleDependencyTestCase extends ModuleTestCase {
     $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
     $this->drupalPost(NULL, NULL, t('Uninstall'));
     $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
-    $edit = array('uninstall[taxonomy]' => 'taxonomy');
+    $edit = array('uninstall[comment]' => 'comment');
     $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
     $this->drupalPost(NULL, NULL, t('Uninstall'));
     $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
@@ -728,6 +695,10 @@ class CronRunTestCase extends DrupalWebTestCase {
     );
   }
 
+  function setUp() {
+    parent::setUp(array('common_test', 'common_test_cron_helper'));
+  }
+
   /**
    * Test cron runs.
    */
@@ -832,6 +803,19 @@ class CronRunTestCase extends DrupalWebTestCase {
     $this->assertTrue(file_exists($perm_old->uri), t('Old permanent file was correctly ignored.'));
     $this->assertTrue(file_exists($perm_new->uri), t('New permanent file was correctly ignored.'));
   }
+
+  /**
+   * Make sure exceptions thrown on hook_cron() don't affect other modules.
+   */
+  function testCronExceptions() {
+    variable_del('common_test_cron');
+    // The common_test module throws an exception. If it isn't caught, the tests
+    // won't finish successfully.
+    // The common_test_cron_helper module sets the 'common_test_cron' variable.
+    $this->cronRun();
+    $result = variable_get('common_test_cron');
+    $this->assertEqual($result, 'success', t('Cron correctly handles exceptions thrown during hook_cron() invocations.'));
+  }
 }
 
 class AdminMetaTagTestCase extends DrupalWebTestCase {
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index aa7cc2e44a68943f66c446aa3835274301f65ffa..9a89b9c98ff63924d7d592c7408efe70cdb756d4 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -360,7 +360,6 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase {
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
     $this->field = array('field_name' => $this->field_name, 'type' => 'text', 'cardinality' => 4);
     $this->field = field_create_field($this->field);
-    $this->field_id = $this->field['id'];
     $this->instance = array(
       'field_name' => $this->field_name,
       'entity_type' => 'taxonomy_term',
@@ -370,6 +369,7 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase {
     field_create_instance($this->instance);
 
     module_disable(array('taxonomy'));
+    drupal_flush_all_caches();
     require_once DRUPAL_ROOT . '/includes/install.inc';
     drupal_uninstall_modules(array('taxonomy'));
     module_enable(array('taxonomy'));
diff --git a/modules/update/update.test b/modules/update/update.test
index e72f4c5402a71a3e1c9de1b6d79cba4a222674e9..4fb8630d76c9964eb3124605f31c99b1590cc90c 100644
--- a/modules/update/update.test
+++ b/modules/update/update.test
@@ -441,6 +441,11 @@ class UpdateTestContribCase extends UpdateTestHelper {
         'hidden' => FALSE,
       ),
     );
+    // When there are contributed modules in the site's file system, the
+    // total number of attempts made in the test may exceed the default value
+    // of update_max_fetch_attempts. Therefore this variable is set very high
+    // to avoid test failures in those cases.
+    variable_set('update_max_fetch_attempts', 99999);
     variable_set('update_test_system_info', $system_info);
     $xml_mapping = array(
       'drupal' => '0',
diff --git a/themes/bartik/css/style.css b/themes/bartik/css/style.css
index 614d32a1ed25d19335ad4809a49a86af8d48f6b0..4fb8210255b9a40940de73ab4fa7bba7418df9b5 100644
--- a/themes/bartik/css/style.css
+++ b/themes/bartik/css/style.css
@@ -1431,9 +1431,6 @@ div.password-suggestions {
 div.vertical-tabs .vertical-tabs-panes fieldset.vertical-tabs-pane {
   padding: 1em;
 }
-#forum tr td.forum {
-  padding-left: 35px;
-}
 #forum .name {
   font-size: 1.083em;
 }