Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.515
diff -u -p -r1.515 form.inc
--- includes/form.inc	18 Dec 2010 06:29:46 -0000	1.515
+++ includes/form.inc	19 Dec 2010 20:55:41 -0000
@@ -661,9 +661,14 @@ function drupal_form_submit($form_id, &$
   // Merge in default values.
   $form_state += form_state_defaults();
 
-  $form = drupal_retrieve_form($form_id, $form_state);
+  // Populate $form_state['input'] with the submitted values before retrieving
+  // the form, to be consistent with what drupal_build_form() does for
+  // non-programmatic submissions (form builder functions may expect it to be
+  // there).
   $form_state['input'] = $form_state['values'];
+
   $form_state['programmed'] = TRUE;
+  $form = drupal_retrieve_form($form_id, $form_state);
   // Programmed forms are always submitted.
   $form_state['submitted'] = TRUE;
 
Index: modules/simpletest/tests/form.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v
retrieving revision 1.76
diff -u -p -r1.76 form.test
--- modules/simpletest/tests/form.test	21 Nov 2010 10:14:25 -0000	1.76
+++ modules/simpletest/tests/form.test	19 Dec 2010 20:55:41 -0000
@@ -1192,6 +1192,15 @@ class FormsProgrammaticTestCase extends 
     $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => NULL, 2 => 2)), TRUE);
     $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => NULL, 2 => NULL)), TRUE);
 
+    // Test that a programmatic form submission can correctly click a button
+    // that limits validation errors based on user input. Since we do not
+    // submit any values for "textfield" here and the textfield is required, we
+    // only expect form validation to pass when validation is limited to a
+    // different field.
+    $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'all'), FALSE);
+    $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'textfield'), FALSE);
+    $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'field_to_validate'), TRUE);
+
     // Restore the current batch status.
     $batch = $current_batch;
   }
Index: modules/simpletest/tests/form_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form_test.module,v
retrieving revision 1.56
diff -u -p -r1.56 form_test.module
--- modules/simpletest/tests/form_test.module	27 Nov 2010 19:12:56 -0000	1.56
+++ modules/simpletest/tests/form_test.module	19 Dec 2010 20:55:42 -0000
@@ -1339,6 +1339,7 @@ function form_test_programmatic_form($fo
     '#title' => 'Textfield',
     '#type' => 'textfield',
   );
+
   $form['checkboxes'] = array(
     '#type' => 'checkboxes',
     '#options' => array(
@@ -1350,6 +1351,39 @@ function form_test_programmatic_form($fo
     '#default_value' => array(1, 2),
   );
 
+  $form['field_to_validate'] = array(
+    '#type' => 'radios',
+    '#title' => 'Field to validate (in the case of limited validation)',
+    '#description' => 'If the form is submitted by clicking the "Submit with limited validation" button, then validation can be limited based on the value of this radio button.',
+    '#options' => array(
+      'all' => 'Validate all fields',
+      'textfield' => 'Validate the "Textfield" field',
+      'field_to_validate' => 'Validate the "Field to validate" field',
+    ),
+    '#default_value' => 'all',
+  );
+
+  // The main submit button for the form.
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Submit',
+  );
+  // A secondary submit button that allows validation to be limited based on
+  // the value of the above radio selector.
+  $form['submit_limit_validation'] = array(
+    '#type' => 'submit',
+    '#value' => 'Submit with limited validation',
+    // Use the same submit handler for this button as for the form itself.
+    // (This must be set explicitly or otherwise the form API will ignore the
+    // #limit_validation_errors property.)
+    '#submit' => array('form_test_programmatic_form_submit'),
+  );
+  if (!empty($form_state['input']['field_to_validate']) && $form_state['input']['field_to_validate'] != 'all') {
+    $form['submit_limit_validation']['#limit_validation_errors'] = array(
+      array($form_state['input']['field_to_validate']),
+    );
+  }
+
   return $form;
 }
 
