1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-02 10:01:11 +02:00

53602: "typeset -nu" always refers to at a call level above the declaration

This commit is contained in:
Bart Schaefer 2025-05-12 21:29:16 -07:00
parent 1706805d46
commit b0fa403a3d
4 changed files with 39 additions and 18 deletions

View file

@ -1,3 +1,9 @@
2025-05-12 Bart Schaefer <schaefer@zsh.org>
* 53602: Doc/Zsh/func.yo, Src/params.c, Test/K01nameref.ztst:
Update "typeset -nu" behavior to always refer to parameters
at a call level above the declaration of the named reference.
2025-05-09 Bart Schaefer <schaefer@zsh.org>
* unposted: Src/params.c: fix bad pointer found by valgrind

View file

@ -23,9 +23,11 @@ declared in an earlier function scope.
(See noderef(Local Parameters).)
A named parameter declared with the `tt(-n)' option to any of the
`tt(typeset)' commands becomes a reference to a parameter in scope at
the time of assignment to the named reference, which may be at a
different call level than the declaring function. For this reason,
`tt(typeset)' acts as a reference to another parameter, which may
be at a different call level than the declaring function. When the
`tt(-u)' option is also given, the referenced parameter is always
found at a call level above the function where the reference is
declared, otherwise the reference scope is dynamic. For this reason,
it is good practice to declare a named reference as soon as the
referent parameter is in scope, and as early as possible in the
function if the reference is to a parameter in a calling scope.

View file

@ -5899,9 +5899,8 @@ scanendscope(HashNode hn, UNUSED(int flags))
pm = hidden;
if (pm && (pm->node.flags & PM_NAMEREF) &&
pm->base >= pm->level && pm->base >= locallevel) {
/* Should never get here for a -u reference */
pm->base = locallevel;
if (pm->level < locallevel && (pm->node.flags & PM_UPPER))
pm->node.flags &= ~PM_UPPER;
}
}
@ -6307,7 +6306,9 @@ resolve_nameref(Param pm, const Asgment stop)
if (pm) {
if (!(stop && (stop->flags & (PM_LOCAL)))) {
int scope = ((pm->node.flags & PM_NAMEREF) ?
((pm->node.flags & PM_UPPER) ? -(pm->base) :
((pm->node.flags & PM_UPPER) ?
/* pm->base == 0 means not set yet */
-(pm->base ? pm->base : pm->level) :
pm->base) : ((Param)hn)->level);
hn = (HashNode)upscope((Param)hn, scope);
}
@ -6413,14 +6414,14 @@ setscope(Param pm)
} else if (!pm->base) {
pm->base = basepm->level;
if ((pm->node.flags & PM_UPPER) &&
(basepm = upscope(basepm, -locallevel)))
(basepm = upscope(basepm, -(pm->level))))
pm->base = basepm->level;
}
} else if (pm->base < locallevel && refname &&
(basepm = (Param)getparamnode(realparamtab, refname))) {
pm->base = basepm->level;
if ((pm->node.flags & PM_UPPER) &&
(basepm = upscope(basepm, -locallevel)))
(basepm = upscope(basepm, -(pm->level))))
pm->base = basepm->level;
}
if (pm->base > pm->level) {

View file

@ -767,6 +767,18 @@ F:typeset cannot bypass a name in the local scope, even via nameref
>typeset -a foo=( alpha beta gamma )
>typeset -g foo=3
() {
# scope with no parameters
() {
local -nu upref=$1
local var=at_upref
print -- $upref
} var
}
0:up-reference part 15, non-existent parameter in outer scope
# no output expected
>
if [[ $options[typesettounset] != on ]]; then
ZTST_skip='Ignoring zmodload bug that resets TYPESET_TO_UNSET'
setopt typesettounset
@ -1088,16 +1100,16 @@ F:previously this could create an infinite recursion and crash
>h:1: rs= - ra= - rs1= - ra1=
>h:2: rs= - ra= - rs1= - ra1=
>i:1: rs= - ra= - rs1= - ra1=
>i:2: rs=h - ra=h - rs1=h - ra1=h
>j:1: rs=h - ra=h - rs1=h - ra1=h
>j:2: rs=h - ra=h - rs1=h - ra1=h
>i:3: rs=h - ra=h - rs1=h - ra1=h
>k:1: rs=h - ra=h - rs1=h - ra1=h
>k:2: rs=h - ra=h - rs1=h - ra1=h
>h:3: rs=h - ra=h - rs1=h - ra1=h
>k:1: rs=h - ra=h - rs1=h - ra1=h
>k:2: rs=h - ra=h - rs1=h - ra1=h
>g:3: rs=g - ra=g - rs1=g - ra1=g
>i:2: rs=g - ra=g - rs1=g - ra1=g
>j:1: rs=g - ra=g - rs1=g - ra1=g
>j:2: rs=g - ra=g - rs1=g - ra1=g
>i:3: rs=g - ra=g - rs1=g - ra1=g
>k:1: rs=g - ra=g - rs1=g - ra1=g
>k:2: rs=g - ra=g - rs1=g - ra1=g
>h:3: rs=g - ra=g - rs1=g - ra1=g
>k:1: rs=g - ra=g - rs1=g - ra1=g
>k:2: rs=g - ra=g - rs1=g - ra1=g
>g:3: rs=f - ra=f - rs1=f - ra1=f
e '' 6
0:assignment at different scope than declaration, '' 6