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	16 Sep 2010 22:08:39 -0000
@@ -1142,6 +1142,14 @@ function _form_validate(&$elements, &$fo
             }
           }
         }
+        // Select fields are not required by design, but they are required in
+        // Drupal by default. Required and non-multiple select fields without a
+        // #default_value get an additional, first "<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);
@@ -2278,6 +2286,15 @@ 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 have a #default_value. By default,
+  // all select lists in Drupal are #required (TRUE), but normally, select lists
+  // are optional by design. A required and 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('<Select>')) . '</option>';
+  }
   if (!isset($choices)) {
     $choices = $element['#options'];
   }
@@ -2285,7 +2302,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: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.960
diff -u -p -r1.960 system.module
--- modules/system/system.module	11 Sep 2010 06:03:12 -0000	1.960
+++ modules/system/system.module	16 Sep 2010 21:07:02 -0000
@@ -399,6 +399,7 @@ function system_element_info() {
   );
   $types['select'] = array(
     '#input' => TRUE,
+    '#required' => TRUE,
     '#size' => 0,
     '#multiple' => FALSE,
     '#process' => array('ajax_process_form'),
