Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.493
diff -u -p -r1.493 form.inc
--- includes/form.inc	16 Sep 2010 20:14:49 -0000	1.493
+++ includes/form.inc	17 Sep 2010 19:48:03 -0000
@@ -1142,6 +1142,18 @@ function _form_validate(&$elements, &$fo
             }
           }
         }
+        // Non-multiple select fields always have a value in HTML. If the user
+        // does not change the form, it will be the value of the first option.
+        // Because of this, if the field is set to #required, it will almost
+        // always pass, even if the user did not select anything. The only case
+        // when the required check fails is if the value of the first option is
+        // an empty string. To enforce this behaviour, forms without a
+        // #default_value get an additional, first "Please select" option via
+        // form_select_options() by default, which needs special treatment.
+        elseif ($elements['#type'] == 'select' && $elements['#required'] && !$elements['#multiple'] && !isset($elements['#default_value']) && $elements['#value'] === '') {
+          // Set the value to NULL to trigger #required handling below.
+          $elements['#value'] = NULL;
+        }
         elseif (!isset($options[$elements['#value']])) {
           form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.'));
           watchdog('form', 'Illegal choice %choice in %name element.', array('%choice' => $elements['#value'], '%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title']), WATCHDOG_ERROR);
@@ -1189,7 +1201,17 @@ function _form_validate(&$elements, &$fo
     // An unchecked checkbox has a #value of integer 0, different than string
     // '0', which could be a valid value.
     if (isset($elements['#needs_validation']) && $elements['#required'] && (!count($elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0) || $elements['#value'] === 0)) {
-      form_error($elements, $t('!name field is required.', array('!name' => $elements['#title'])));
+      // Although unusual and actually discouraged, a #title is not mandatory
+      // for form elements. In case the element does not have a title, we cannot
+      // set a form error message. Note that instead of setting no #title, form
+      // constructors are encouraged to set #title_display to 'hidden' instead
+      // to improve accessibility.
+      if (isset($elements['#title'])) {
+        form_error($elements, $t('!name field is required.', array('!name' => $elements['#title'])));
+      }
+      else {
+        form_error($elements);
+      }
     }
 
     // Call user-defined form level validators.
@@ -2238,6 +2260,17 @@ function _form_options_flatten($array) {
 }
 
 /**
+ * Processes a select list form element.
+ */
+function form_process_select($element) {
+  // A non-#multiple select without a #default_value has to be #required.
+  if (!$element['#multiple'] && !isset($element['#default_value'])) {
+    $element['#required'] = TRUE;
+  }
+  return $element;
+}
+
+/**
  * Returns HTML for a select form element.
  *
  * It is possible to group options together; to do this, change the format of
@@ -2278,6 +2311,16 @@ function theme_select($variables) {
  *   An HTML string of options for the select form element.
  */
 function form_select_options($element, $choices = NULL) {
+  $options = '';
+  // Add a first, always invalid default option on the top-level for required,
+  // non-multiple select lists that do not specify a #default_value. Without
+  // this additional option, the form element would always be valid, since the
+  // browser automatically selects the first available option. A #multiple
+  // select list does not get this option, since it would be illogical, user
+  // interface-wise.
+  if (!isset($choices) && $element['#required'] && !$element['#multiple'] && !isset($element['#default_value'])) {
+    $options .= '<option value="">' . check_plain(t('- Please select -')) . '</option>';
+  }
   if (!isset($choices)) {
     $choices = $element['#options'];
   }
@@ -2285,7 +2328,6 @@ function form_select_options($element, $
   // isset() fails in this situation.
   $value_valid = isset($element['#value']) || array_key_exists('#value', $element);
   $value_is_array = $value_valid && is_array($element['#value']);
-  $options = '';
   foreach ($choices as $key => $choice) {
     if (is_array($choice)) {
       $options .= '<optgroup label="' . $key . '">';
Index: includes/install.core.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/install.core.inc,v
retrieving revision 1.30
diff -u -p -r1.30 install.core.inc
--- includes/install.core.inc	14 Sep 2010 21:42:05 -0000	1.30
+++ includes/install.core.inc	17 Sep 2010 18:20:56 -0000
@@ -1719,6 +1719,7 @@ function _install_configure_form($form, 
   $form['server_settings']['site_default_country'] = array(
     '#type' => 'select',
     '#title' => t('Default country'),
+    '#required' => FALSE,
     '#default_value' => variable_get('site_default_country', ''),
     '#options' => $countries,
     '#description' => st('Select the default country for the site.'),
Index: modules/simpletest/tests/ajax_forms_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/ajax_forms_test.module,v
retrieving revision 1.7
diff -u -p -r1.7 ajax_forms_test.module
--- modules/simpletest/tests/ajax_forms_test.module	6 May 2010 05:59:31 -0000	1.7
+++ modules/simpletest/tests/ajax_forms_test.module	17 Sep 2010 18:31:22 -0000
@@ -38,7 +38,6 @@ function ajax_forms_test_menu() {
  * A basic form used to test form_state['values'] during callback.
  */
 function ajax_forms_test_simple_form($form, &$form_state) {
-  $form = array();
   $form['select'] = array(
     '#type' => 'select',
     '#options' => array(
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.961
diff -u -p -r1.961 system.module
--- modules/system/system.module	17 Sep 2010 14:53:21 -0000	1.961
+++ modules/system/system.module	17 Sep 2010 18:47:32 -0000
@@ -401,7 +401,7 @@ function system_element_info() {
     '#input' => TRUE,
     '#size' => 0,
     '#multiple' => FALSE,
-    '#process' => array('ajax_process_form'),
+    '#process' => array('form_process_select', 'ajax_process_form'),
     '#theme' => 'select',
     '#theme_wrappers' => array('form_element'),
   );
