54048: consistently re-bind namerefs when returning from greater locallevel

This commit is contained in:
Philippe Altherr
2026-03-31 17:55:43 -07:00
committed by Bart Schaefer
parent 8edd5029de
commit bcae4b58e6
3 changed files with 83 additions and 31 deletions

View File

@@ -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

View File

@@ -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();

View File

@@ -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
1: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
>reached
*?*: ref1: invalid self reference
*?*: ref2: invalid self reference
typeset -A -g VAR0=(aa AA)
typeset -n -g REF0=VAR0