Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: BUG: "return 0 && x=abc" does not skip parameter assignment



This is because the implementation of return (and exit) pretends to perform a break, which in my opinion is bogus.

One reason I found this to be bogus was because I thought that in the following code, return would behave like break and stop the loop.

setopt +o LOCAL_LOOPS
while true; do
  () { return }
done

However, it doesn't because of this code. Furthermore, there are other places where both reflag and breaks are set. I still think that code should either set one or the other, depending on whether a function/script return or a loop break is desired. Fixing just one of these places in this patch doesn't make much sense. Here is an updated patch that reverts this change.

- Fix break/return shortcutting of &&, ||, and !

Philippe

diff --git a/Src/exec.c b/Src/exec.c
index b0794abab..b1a0652da 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1558,12 +1558,14 @@ execlist(Estate state, int dont_change_job, int exiting)
 		 * we find a sublist followed by ORNEXT.                   */
 		if (((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
 			    execsimple(state) :
-			    execpline(state, code, Z_SYNC, 0)) || breaks) {
+			    execpline(state, code, Z_SYNC, 0)) ||
+		    breaks || retflag) {
 		    state->pc = next;
 		    code = *state->pc++;
 		    next = state->pc + WC_SUBLIST_SKIP(code);
 		    while (wc_code(code) == WC_SUBLIST &&
-			   WC_SUBLIST_TYPE(code) == WC_SUBLIST_AND) {
+			   (breaks || retflag ||
+			    WC_SUBLIST_TYPE(code) == WC_SUBLIST_AND)) {
 			state->pc = next;
 			code = *state->pc++;
 			next = state->pc + WC_SUBLIST_SKIP(code);
@@ -1591,12 +1593,14 @@ execlist(Estate state, int dont_change_job, int exiting)
 		 * we find a sublist followed by ANDNEXT.              */
 		if (!(((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
 			     execsimple(state) :
-			     execpline(state, code, Z_SYNC, 0))) || breaks) {
+			     execpline(state, code, Z_SYNC, 0))) ||
+		    breaks || retflag) {
 		    state->pc = next;
 		    code = *state->pc++;
 		    next = state->pc + WC_SUBLIST_SKIP(code);
 		    while (wc_code(code) == WC_SUBLIST &&
-			   WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) {
+			   (breaks || retflag ||
+			    WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR)) {
 			state->pc = next;
 			code = *state->pc++;
 			next = state->pc + WC_SUBLIST_SKIP(code);
@@ -2036,7 +2040,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 	}
 	else
 	    unqueue_signals();
-	if ((slflags & WC_SUBLIST_NOT) && !errflag && !retflag)
+	if ((slflags & WC_SUBLIST_NOT) && !errflag && !retflag && !breaks)
 	    lastval = !lastval;
     }
     if (!pline_level)
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
index eea6ede2b..db48de8a9 100644
--- a/Test/A01grammar.ztst
+++ b/Test/A01grammar.ztst
@@ -982,38 +982,72 @@ F:its expectations.
  fn
 1:! does not affect return status of explicit return
 
+ for x in 1; do
+   ! continue
+ done
+0:! does not affect status of explicit continue
+
   msg=unset
-  for x in 1 2 3 4 5; do
+  for x in 1; do
     continue && msg=set && print Not executed
     print Not executed, neither.
   done
-  print $msg
-0:continue causes immediate continuation
->unset
+  print $?-$msg
+0:continue causes immediate continuation (immediate assign)
+>0-unset
+
+  msg=unset
+  for x in 1; do
+    continue && false || msg=set && print Not executed
+    print Not executed, neither.
+  done
+  print $?-$msg
+0:continue causes immediate continuation (assign after operator change)
+>0-unset
 
   msg=unset
   () {
-    return && msg=set && print Not executed
-    print Not executed, not nor neither.
+    return 7 || msg=set && print Not executed
+    print Not executed, neither.
   }
-  print $msg
-0:return causes immediate return
->unset
+  print $?-$msg
+0:return causes immediate return (immediate assign)
+>7-unset
 
   msg=unset
-  for x in 1 2 3 4 5; do
+  () {
+    return 7 || true && msg=set && print Not executed
+    print Not executed, neither.
+  }
+  print $?-$msg
+0:return causes immediate return (assign after operator change)
+>7-unset
+
+  $ZTST_testdir/../Src/zsh -fc '
+    msg=unset
+    () {
+      return 7 || msg=set && print Not executed
+      print Not executed, neither.
+    }
+    print $?-$msg
+  '
+0:return causes immediate return (no enclosing loops)
+>7-unset
+
+  msg=unset
+  for x in 1; do
     ! continue || msg=set && print Not executed
     print Not executed, neither.
   done
-  print $msg
+  print $?-$msg
 0:! continue causes immediate continuation
->unset
+>0-unset
 
   msg=unset
   () {
-    ! return || msg=set && print Not executed
-    print Not executed, not nor neither.
+    ! return 7 && msg=set && print Not executed
+    print Not executed, neither.
   }
-  print $msg
+  print $?-$msg
 0:! return causes immediate return
->unset
+>7-unset


Messages sorted by: Reverse Date, Date, Thread, Author