Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.497
diff -u -p -r1.497 form.inc
--- includes/form.inc	27 Sep 2010 00:53:55 -0000	1.497
+++ includes/form.inc	28 Sep 2010 03:39:46 -0000
@@ -2161,7 +2161,7 @@ function form_type_password_confirm_valu
  */
 function form_type_select_value($element, $input = FALSE) {
   if ($input !== FALSE) {
-    if (isset($element['#multiple']) && $element['#multiple']) {
+    if ($element['#multiple']) {
       // If an enabled multi-select submits NULL, it means all items are
       // unselected. A disabled multi-select always submits NULL, and the
       // default value should be used.
@@ -2176,6 +2176,23 @@ function form_type_select_value($element
       return $input;
     }
   }
+  else {
+    if ($element['#multiple']) {
+      return (isset($element['#default_value']) && is_array($element['#default_value'])) ? $element['#default_value'] : array();
+    }
+    else {
+      // If there is a #default_value, then it is only valid if it is contained
+      // in #options.
+      if (isset($element['#default_value']) && isset($element['#options'][$element['#default_value']])) {
+        return $element['#default_value'];
+      }
+      // Otherwise, pre-select the empty default option value.
+      // @see form_process_select()
+      else {
+        return $element['#empty_value'];
+      }
+    }
+  }
 }
 
 /**
@@ -2309,8 +2326,8 @@ function _form_options_flatten($array) {
  *   - #required: (optional) Whether the user needs to select an option (TRUE)
  *     or not (FALSE). Defaults to TRUE.
  *   - #empty_option: (optional) The label to show for the first default option.
- *     By default, the label is automatically set to "- Please select -" for a
- *     required field and "- None -" for an optional field.
+ *     If not set, the default label is automatically set according to whether
+ *     the element is #required or not.
  *   - #empty_value: (optional) The value for the first default option, which is
  *     used to determine whether the user submitted a value or not. Defaults to
  *     '' (an empty string). To be used in case the field is optional and the
@@ -2344,21 +2361,19 @@ function form_process_select($element) {
     if (isset($element['#required']) && !$element['#required']) {
       $element['#required'] = FALSE;
       $element += array(
-        '#empty_value' => '',
         '#empty_option' => t('- None -'),
       );
       $add_empty_option = TRUE;
     }
     // Otherwise, if #required is TRUE (or not set) and there is no
-    // #default_value, then the user has to choose an option, which makes this
-    // element #required.
-    elseif (!isset($element['#default_value'])) {
+    // #default_value or the #default_value is not contained in #options, then
+    // the user has to choose an option, which makes this element #required.
+    elseif (!isset($element['#default_value']) || !isset($element['#options'][$element['#default_value']])) {
       // By only conditionally setting #required to TRUE, we additionally ensure
       // that the select element does not get a required marker if it already
       // has a value.
       $element['#required'] = TRUE;
       $element += array(
-        '#empty_value' => '',
         '#empty_option' => t('- Select -'),
       );
       $add_empty_option = TRUE;
Index: modules/block/block.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v
retrieving revision 1.88
diff -u -p -r1.88 block.admin.inc
--- modules/block/block.admin.inc	24 Sep 2010 21:36:22 -0000	1.88
+++ modules/block/block.admin.inc	28 Sep 2010 03:39:46 -0000
@@ -150,7 +150,9 @@ function block_admin_display_form($form,
     }
   }
   // Do not allow disabling the main system content block.
-  $form['blocks']['system_main']['region']['#required'] = TRUE;
+  if (isset($form['blocks']['system_main']['region'])) {
+    $form['blocks']['system_main']['region']['#required'] = TRUE;
+  }
 
   $form['actions'] = array(
     '#tree' => FALSE,
Index: modules/field/modules/options/options.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/options/options.module,v
retrieving revision 1.27
diff -u -p -r1.27 options.module
--- modules/field/modules/options/options.module	17 Aug 2010 21:48:39 -0000	1.27
+++ modules/field/modules/options/options.module	28 Sep 2010 04:15:02 -0000
@@ -87,12 +87,16 @@ function options_field_widget_form(&$for
 
   switch ($type) {
     case 'select':
+      if (!$multiple) {
+        $default_value = (!empty($default_value) ? reset($default_value) : NULL);
+      }
       $element += array(
         '#type' => 'select',
+        '#required' => $required ? NULL : FALSE,
+        '#options' => $options,
         '#default_value' => $default_value,
         // Do not display a 'multiple' select box if there is only one option.
         '#multiple' => $multiple && count($options) > 1,
-        '#options' => $options,
       );
       break;
 
@@ -138,9 +142,6 @@ function options_field_widget_form(&$for
  * Form element validation handler for options element.
  */
 function options_field_widget_validate($element, &$form_state) {
-  if ($element['#required'] && $element['#value'] == '_none') {
-    form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
-  }
   // Transpose selections from field => delta to delta => field, turning
   // multiple selected options into multiple parent elements.
   $items = _options_form_to_storage($element);
@@ -152,6 +153,7 @@ function options_field_widget_validate($
  */
 function _options_properties($type, $multiple, $required, $has_value) {
   $base = array(
+    'type' => $type,
     'zero_placeholder' => FALSE,
     'filter_xss' => FALSE,
     'strip_tags' => FALSE,
@@ -168,23 +170,6 @@ function _options_properties($type, $mul
         'strip_tags' => TRUE,
         'optgroups' => TRUE,
       );
-      if ($multiple) {
-        // Multiple select: add a 'none' option for non-required fields.
-        if (!$required) {
-          $properties['empty_option'] = 'option_none';
-        }
-      }
-      else {
-        // Single select: add a 'none' option for non-required fields,
-        // and a 'select a value' option for required fields that do not come
-        // with a value selected.
-        if (!$required) {
-          $properties['empty_option'] = 'option_none';
-        }
-        else if (!$has_value) {
-          $properties['empty_option'] = 'option_select';
-        }
-      }
       break;
 
     case 'buttons':
@@ -224,7 +209,9 @@ function _options_get_options($field, $i
     $options = options_array_flatten($options);
   }
 
-  if ($properties['empty_option']) {
+  // Add an empty option, except for select lists, which are already handled by
+  // Form API.
+  if ($properties['empty_option'] && $properties['type'] != 'select') {
     $label = theme('options_none', array('instance' => $instance, 'option' => $properties['empty_option']));
     $options = array('_none' => $label) + $options;
   }
Index: modules/forum/forum.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.admin.inc,v
retrieving revision 1.36
diff -u -p -r1.36 forum.admin.inc
--- modules/forum/forum.admin.inc	8 Aug 2010 19:21:25 -0000	1.36
+++ modules/forum/forum.admin.inc	28 Sep 2010 03:44:03 -0000
@@ -275,15 +275,11 @@ function forum_overview($form, &$form_st
  * @param $child_type Whether the child is forum or container
  */
 function _forum_parent_select($tid, $title, $child_type) {
-
   $parents = taxonomy_get_parents($tid);
   if ($parents) {
     $parent = array_shift($parents);
     $parent = $parent->tid;
   }
-  else {
-    $parent = 0;
-  }
 
   $vid = variable_get('forum_nav_vocabulary', '');
   $children = taxonomy_get_tree($vid, $tid);
@@ -295,7 +291,7 @@ function _forum_parent_select($tid, $tit
   $exclude[] = $tid;
 
   $tree = taxonomy_get_tree($vid);
-  $options[0] = '<' . t('root') . '>';
+  $options = array();
   if ($tree) {
     foreach ($tree as $term) {
       if (!in_array($term->tid, $exclude)) {
@@ -310,5 +306,12 @@ function _forum_parent_select($tid, $tit
     $description = t('Forums may be placed at the top (root) level, or inside another container or forum.');
   }
 
-  return array('#type' => 'select', '#title' => $title, '#default_value' => $parent, '#options' => $options, '#description' => $description, '#required' => TRUE);
+  return array(
+    '#type' => 'select',
+    '#title' => $title,
+    '#default_value' => isset($parent) ? $parent : NULL,
+    '#options' => $options,
+    '#empty_option' => t('- Root -'),
+    '#description' => $description,
+  );
 }
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.577
diff -u -p -r1.577 forum.module
--- modules/forum/forum.module	27 Sep 2010 02:59:31 -0000	1.577
+++ modules/forum/forum.module	28 Sep 2010 03:45:08 -0000
@@ -635,7 +635,12 @@ function forum_block_info() {
  * Implements hook_block_configure().
  */
 function forum_block_configure($delta = '') {
-  $form['forum_block_num_' . $delta] = array('#type' => 'select', '#title' => t('Number of topics'), '#default_value' => variable_get('forum_block_num_' . $delta, '5'), '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)));
+  $form['forum_block_num_' . $delta] = array(
+    '#type' => 'select',
+    '#title' => t('Number of topics'),
+    '#default_value' => variable_get('forum_block_num_' . $delta, '5'),
+    '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)),
+  );
   return $form;
 }
 
Index: modules/menu/menu.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.admin.inc,v
retrieving revision 1.85
diff -u -p -r1.85 menu.admin.inc
--- modules/menu/menu.admin.inc	24 Sep 2010 21:36:22 -0000	1.85
+++ modules/menu/menu.admin.inc	28 Sep 2010 03:39:46 -0000
@@ -679,7 +679,6 @@ function menu_configure() {
 
   $menu_options = menu_get_menus();
 
-  $main = variable_get('menu_main_links_source', 'main-menu');
   $form['menu_main_links_source'] = array(
     '#type' => 'select',
     '#title' => t('Source for the Main links'),
@@ -688,7 +687,7 @@ function menu_configure() {
     '#empty_option' => t('No Main links'),
     '#options' => $menu_options,
     '#tree' => FALSE,
-    '#description' => t('Select what should be displayed as the Main links (typically at the top of the page).'),
+    '#description' => t('Typically shown at the top of the page.'),
   );
 
   $form['menu_secondary_links_source'] = array(
@@ -699,7 +698,7 @@ function menu_configure() {
     '#empty_option' => t('No Secondary links'),
     '#options' => $menu_options,
     '#tree' => FALSE,
-    '#description' => t("Select the source for the Secondary links. An advanced option allows you to use the same source for both Main links (currently %main) and Secondary links: if your source menu has two levels of hierarchy, the top level menu links will appear in the Main links, and the children of the active link will appear in the Secondary links." , array('%main' => $main_options[$main])),
+    '#description' => t('Typically shown to complement the Main links near the top of the page. Use the same source as Main links to show the child links of the active Main link.'),
   );
 
   return system_settings_form($form);
Index: modules/simpletest/tests/form.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v
retrieving revision 1.70
diff -u -p -r1.70 form.test
--- modules/simpletest/tests/form.test	28 Sep 2010 02:30:32 -0000	1.70
+++ modules/simpletest/tests/form.test	28 Sep 2010 03:39:46 -0000
@@ -158,14 +158,60 @@ class FormsTestCase extends DrupalWebTes
   function testSelect() {
     $form = $form_state = array();
     $form = form_test_select($form, $form_state);
-    $error = '!name field is required.';
     $this->drupalGet('form-test/select');
 
+    // Verify that the expected options are selected by default.
+    $expected_defaults = array(
+      'select' => 'one',
+      'empty_value' => 'one',
+      'empty_value_one' => 'one',
+      'invalid_default' => '',
+      'invalid_default_optional' => '',
+      'no_default' => '',
+      'no_default_optional' => '',
+      'no_default_empty_option' => '',
+      'no_default_empty_option_optional' => '',
+      'no_default_empty_value' => 0,
+      'no_default_empty_value_one' => 'one',
+      'no_default_empty_value_optional' => 0,
+      'multiple[]' => 'two',
+      'multiple_no_default[]' => NULL,
+      'multiple_no_default_required[]' => NULL,
+    );
+    foreach ($expected_defaults as $key => $value) {
+      // assertFieldByXPath() automatically uses the first available select
+      // option if no option has the "selected" attribute, so we cannot pass
+      // $value here and instead have to retrieve the selected option's value
+      // manually.
+      if (isset($value)) {
+        $xpath = $this->buildXPathQuery('//select[@name=:name]/option[@selected and @value=:value]', array(
+          ':name' => $key,
+          ':value' => $value,
+        ));
+        $this->assertFieldByXPath($xpath, NULL, t('@key: Pre-selected option @value found.', array(
+          '@key' => $key,
+          '@value' => var_export($value, TRUE),
+        )));
+      }
+      else {
+        $xpath = $this->buildXPathQuery('//select[@name=:name]/option[@selected]', array(
+          ':name' => $key,
+        ));
+        $this->assertNoFieldByXPath($xpath, NULL, t('@key: No pre-selected option found.', array(
+          '@key' => $key,
+        )));
+      }
+    }
+
     // Posting without any values should throw validation errors.
+    $error = '!name field is required.';
     $this->drupalPost(NULL, array(), 'Submit');
+    $this->assertNoText(t('An illegal choice has been detected. Please contact the site administrator.'));
     $this->assertNoText(t($error, array('!name' => $form['select']['#title'])));
     $this->assertNoText(t($error, array('!name' => $form['empty_value']['#title'])));
     $this->assertNoText(t($error, array('!name' => $form['empty_value_one']['#title'])));
+    $this->assertText(t($error, array('!name' => $form['invalid_default']['#title'])));
+    $this->assertNoText(t($error, array('!name' => $form['invalid_default_optional']['#title'])));
     $this->assertText(t($error, array('!name' => $form['no_default']['#title'])));
     $this->assertNoText(t($error, array('!name' => $form['no_default_optional']['#title'])));
     $this->assertText(t($error, array('!name' => $form['no_default_empty_option']['#title'])));
@@ -179,6 +225,7 @@ class FormsTestCase extends DrupalWebTes
 
     // Post values for required fields.
     $edit = array(
+      'invalid_default' => 'three',
       'no_default' => 'three',
       'no_default_empty_option' => 'three',
       'no_default_empty_value' => 'three',
@@ -186,6 +233,7 @@ class FormsTestCase extends DrupalWebTes
       'multiple_no_default_required[]' => 'three',
     );
     $this->drupalPost(NULL, $edit, 'Submit');
+    $this->assertNoText(t('An illegal choice has been detected. Please contact the site administrator.'));
     $values = drupal_json_decode($this->drupalGetContent());
 
     // Verify expected values.
@@ -193,6 +241,8 @@ class FormsTestCase extends DrupalWebTes
       'select' => 'one',
       'empty_value' => 'one',
       'empty_value_one' => 'one',
+      'invalid_default' => 'three',
+      'invalid_default_optional' => '',
       'no_default' => 'three',
       'no_default_optional' => '',
       'no_default_empty_option' => 'three',
Index: modules/simpletest/tests/form_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form_test.module,v
retrieving revision 1.50
diff -u -p -r1.50 form_test.module
--- modules/simpletest/tests/form_test.module	27 Sep 2010 00:53:56 -0000	1.50
+++ modules/simpletest/tests/form_test.module	28 Sep 2010 03:39:46 -0000
@@ -800,6 +800,18 @@ function form_test_select($form, &$form_
     '#empty_value' => 'one',
   );
 
+  $form['invalid_default'] = $base + array(
+    '#title' => 'Invalid #default_value',
+    '#default_value' => 'invalid',
+    '#description' => 'Should result in #empty_value, since #default_value is not within #options.',
+  );
+  $form['invalid_default_optional'] = $base + array(
+    '#title' => 'Invalid #default_value, not #required',
+    '#required' => FALSE,
+    '#default_value' => 'invalid',
+    '#description' => 'Should result in #empty_value, since #default_value is not within #options.',
+  );
+
   $form['no_default'] = $base + array(
     '#title' => 'No #default_value',
   );
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.966
diff -u -p -r1.966 system.module
--- modules/system/system.module	28 Sep 2010 02:30:32 -0000	1.966
+++ modules/system/system.module	28 Sep 2010 03:39:46 -0000
@@ -404,6 +404,7 @@ function system_element_info() {
     // preemptively sets #required to FALSE for all elements.
     // @see form_process_select()
     '#required' => NULL,
+    '#empty_value' => '',
     '#multiple' => FALSE,
     '#process' => array('form_process_select', 'ajax_process_form'),
     '#theme' => 'select',
Index: modules/trigger/trigger.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/trigger/trigger.admin.inc,v
retrieving revision 1.28
diff -u -p -r1.28 trigger.admin.inc
--- modules/trigger/trigger.admin.inc	24 Sep 2010 21:36:22 -0000	1.28
+++ modules/trigger/trigger.admin.inc	28 Sep 2010 03:39:46 -0000
@@ -180,6 +180,7 @@ function trigger_assign_form($form, $for
     $form[$hook]['parent']['aid'] = array(
       '#type' => 'select',
       '#options' => $options,
+      '#empty_option' => t('- Choose an action -'),
     );
     $form[$hook]['parent']['submit'] = array(
       '#type' => 'submit',
