hush: fix "set -e; false || x=1; echo OK"

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/ash_test/ash-misc/assignment5.right b/shell/ash_test/ash-misc/assignment5.right
new file mode 100644
index 0000000..a91554c
--- /dev/null
+++ b/shell/ash_test/ash-misc/assignment5.right
@@ -0,0 +1,5 @@
+Zero1:0
+Zero2:0
+Zero3:0
+Zero4:0 x:1 y:1
+Three:3 x:1 y:1
diff --git a/shell/ash_test/ash-misc/assignment5.tests b/shell/ash_test/ash-misc/assignment5.tests
new file mode 100755
index 0000000..0b81042
--- /dev/null
+++ b/shell/ash_test/ash-misc/assignment5.tests
@@ -0,0 +1,9 @@
+true;  a=1; echo Zero1:$?
+false; a=1; echo Zero2:$?
+false || a=1; echo Zero3:$?
+
+false || x=$? y=`echo $?`; echo Zero4:$? x:$x y:$y
+false || x=$? y=`echo $?; exit 3`; echo Three:$? x:$x y:$y
+
+#ash sets z=1 instead of z=3. disabled for now
+#false || x=$? y=`echo $?; exit 3` z=`echo $?`; echo x:$x y:$y z:$z
diff --git a/shell/hush.c b/shell/hush.c
index 184d720..b64993f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -894,8 +894,9 @@
 # define G_flag_return_in_progress 0
 #endif
 	smallint exiting; /* used to prevent EXIT trap recursion */
-	/* These four support $?, $#, and $1 */
+	/* These support $?, $#, and $1 */
 	smalluint last_exitcode;
+	smalluint expand_exitcode;
 	smalluint last_bg_pid_exitcode;
 #if ENABLE_HUSH_SET
 	/* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
@@ -6209,6 +6210,7 @@
 			 * and $IFS-split */
 			debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
 			G.last_exitcode = process_command_subs(&subst_result, arg);
+			G.expand_exitcode = G.last_exitcode;
 			debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data);
 			val = subst_result.data;
 			goto store_val;
@@ -8245,9 +8247,11 @@
 #endif
 
 		if (argv[command->assignment_cnt] == NULL) {
-			/* Assignments, but no command */
-			/* Ensure redirects take effect (that is, create files).
-			 * Try "a=t >file" */
+			/* Assignments, but no command.
+			 * Ensure redirects take effect (that is, create files).
+			 * Try "a=t >file"
+			 */
+			G.expand_exitcode = 0;
 #if 0 /* A few cases in testsuite fail with this code. FIXME */
 			rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, &squirrel, /*argv_expanded:*/ NULL);
 			/* Set shell variables */
@@ -8265,7 +8269,7 @@
 			 * if evaluating assignment value set $?, retain it.
 			 * Try "false; q=`exit 2`; echo $?" - should print 2: */
 			if (rcode == 0)
-				rcode = G.last_exitcode;
+				rcode = G.expand_exitcode;
 			/* Exit, _skipping_ variable restoring code: */
 			goto clean_up_and_ret0;
 
@@ -8292,9 +8296,13 @@
 				bb_putchar_stderr('\n');
 			/* Redirect error sets $? to 1. Otherwise,
 			 * if evaluating assignment value set $?, retain it.
-			 * Try "false; q=`exit 2`; echo $?" - should print 2: */
+			 * Else, clear $?:
+			 *  false; q=`exit 2`; echo $? - should print 2
+			 *  false; x=1; echo $? - should print 0
+			 * Because of the 2nd case, we can't just use G.last_exitcode.
+			 */
 			if (rcode == 0)
-				rcode = G.last_exitcode;
+				rcode = G.expand_exitcode;
 			IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
 			debug_leave();
 			debug_printf_exec("run_pipe: return %d\n", rcode);
diff --git a/shell/hush_test/hush-misc/assignment5.right b/shell/hush_test/hush-misc/assignment5.right
new file mode 100644
index 0000000..a91554c
--- /dev/null
+++ b/shell/hush_test/hush-misc/assignment5.right
@@ -0,0 +1,5 @@
+Zero1:0
+Zero2:0
+Zero3:0
+Zero4:0 x:1 y:1
+Three:3 x:1 y:1
diff --git a/shell/hush_test/hush-misc/assignment5.tests b/shell/hush_test/hush-misc/assignment5.tests
new file mode 100755
index 0000000..0b81042
--- /dev/null
+++ b/shell/hush_test/hush-misc/assignment5.tests
@@ -0,0 +1,9 @@
+true;  a=1; echo Zero1:$?
+false; a=1; echo Zero2:$?
+false || a=1; echo Zero3:$?
+
+false || x=$? y=`echo $?`; echo Zero4:$? x:$x y:$y
+false || x=$? y=`echo $?; exit 3`; echo Three:$? x:$x y:$y
+
+#ash sets z=1 instead of z=3. disabled for now
+#false || x=$? y=`echo $?; exit 3` z=`echo $?`; echo x:$x y:$y z:$z