summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Altherr <philippe.altherr@gmail.com>2026-03-31 17:55:43 -0700
committerBart Schaefer <schaefer@zsh.org>2026-03-31 18:32:35 -0700
commitbcae4b58e6539423a5168afa0b651cfdab8b3cc3 (patch)
treebf4b49111bfcbfc4bda9901eee694466f24b8201
parent54262: track and revert hidden references in chains across locallevel scopes (diff)
downloadzsh-master.tar
zsh-master.tar.gz
zsh-master.tar.bz2
zsh-master.tar.lz
zsh-master.tar.xz
zsh-master.tar.zst
zsh-master.zip
54048: consistently re-bind namerefs when returning from greater locallevelHEADmaster
-rw-r--r--ChangeLog3
-rw-r--r--Src/params.c3
-rw-r--r--Test/K01nameref.ztst108
3 files changed, 83 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog
index 0b7f5ec6b..c3612bda8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2026-03-31 Bart Schaefer <schaefer@zsh.org>
+ * Philippe: 54048: Src/params.c, Test/K01nameref.ztst: consistently
+ re-bind named references when returning from greater locallevel
+
* Philippe: 54262: Src/params.c, Test/K01nameref.ztst: track
and revert hidden references in chains that extend across
locallevel scopes
diff --git a/Src/params.c b/Src/params.c
index 4f5454abb..461e02acf 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5905,7 +5905,8 @@ endparamscope(void)
for (Param pm; refs && (pm = (Param)getlinknode(refs));) {
if ((pm->node.flags & PM_NAMEREF) && !(pm->node.flags & PM_UNSET) &&
!(pm->node.flags & PM_UPPER) && pm->base > locallevel) {
- setscope_base(pm, locallevel);
+ pm->base = 0;
+ setscope(pm);
}
}
unqueue_signals();
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 82ccbfb89..0b4475827 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1258,6 +1258,81 @@ F:previously this could create an infinite recursion and crash
>h2: ref1=f1 ref2=f1 ref3=f1
>f1: ref1=f1 ref2=f1 ref3=f1
+ () {
+ typeset -n ref1 ref2
+ local var=l1
+ () {
+ () {
+ local var=l3
+ ref1=var
+ echo A1: ref1=$ref1 ref2=$ref2
+ }
+ ref2=var
+ # At this point, "ref1" and "ref2" refer to the same variable
+ # "var". Going forward, they should behave the same.
+ echo A2: ref1=$ref1 ref2=$ref2
+ () {
+ local var=l3
+ echo A3: ref1=$ref1 ref2=$ref2
+ }
+ echo A4: ref1=$ref1 ref2=$ref2
+ local var=l2
+ echo A5: ref1=$ref1 ref2=$ref2
+ }
+ echo A6: ref1=$ref1 ref2=$ref2
+ }
+ () {
+ typeset -n ref1 ref2
+ () {
+ () {
+ local var=l3
+ ref1=var
+ echo B1: ref1=$ref1 ref2=$ref2
+ }
+ ref2=var
+ # At this point, "ref1" and "ref2" refer to the same undefined
+ # variable "var". Going forward, they should behave the same.
+ echo B2: ref1=$ref1 ref2=$ref2
+ () {
+ () {
+ local var=l4
+ echo B3: ref1=$ref1 ref2=$ref2
+ }
+ local var=l3
+ echo B4: ref1=$ref1 ref2=$ref2
+ }
+ local var=l2
+ echo B5: ref1=$ref1 ref2=$ref2
+ () {
+ () {
+ local var=l4
+ echo B6: ref1=$ref1 ref2=$ref2
+ }
+ local var=l3
+ echo B7: ref1=$ref1 ref2=$ref2
+ }
+ echo B8: ref1=$ref1 ref2=$ref2
+ }
+ local var=l1
+ echo B9: ref1=$ref1 ref2=$ref2
+ }
+0:rebound nameref behaves the same as newly bound one
+>A1: ref1=l3 ref2=
+>A2: ref1=l1 ref2=l1
+>A3: ref1=l1 ref2=l1
+>A4: ref1=l1 ref2=l1
+>A5: ref1=l1 ref2=l1
+>A6: ref1=l1 ref2=l1
+>B1: ref1=l3 ref2=
+>B2: ref1= ref2=
+>B3: ref1=l4 ref2=l4
+>B4: ref1=l3 ref2=l3
+>B5: ref1=l2 ref2=l2
+>B6: ref1=l2 ref2=l2
+>B7: ref1=l2 ref2=l2
+>B8: ref1=l2 ref2=l2
+>B9: ref1=l1 ref2=l1
+
#
# The following two tests are linked, do not separate
#
@@ -1500,39 +1575,12 @@ F:$$[1] reference should print the first digit of $$ but prints nothing
() {
typeset ref2=foo
ref1=ref2
+ echo reached
}
- echo reached
- echo $ref1
- echo NOT REACHED
-1:expansion of incidental reference loop triggers error
->reached
-*?*: ref1: invalid self reference
-
- typeset -n ref1
- typeset -n ref2=ref1;
- () {
- typeset ref2=foo
- ref1=ref2
- }
- echo reached
- ref1=foo
- echo NOT REACHED
-1:assignment to incidental reference loop triggers error
->reached
-*?*: ref1: invalid self reference
-
- typeset -n ref1
- typeset -n ref2=ref1;
- () {
- typeset ref2=foo
- ref1=ref2
- }
- echo reached
- typeset -n ref3=ref1
echo NOT REACHED
-1:reference to incidental reference loop triggers error
+1:incidental reference loop triggers error
>reached
-*?*: ref1: invalid self reference
+*?*: ref2: invalid self reference
typeset -A -g VAR0=(aa AA)
typeset -n -g REF0=VAR0