diff options
| -rw-r--r-- | ChangeLog | 6 | ||||
| -rw-r--r-- | Doc/Zsh/func.yo | 8 | ||||
| -rw-r--r-- | Src/params.c | 11 | ||||
| -rw-r--r-- | Test/K01nameref.ztst | 32 |
4 files changed, 39 insertions, 18 deletions
@@ -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 diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo index 7b71e34e9..9558b11c4 100644 --- a/Doc/Zsh/func.yo +++ b/Doc/Zsh/func.yo @@ -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. diff --git a/Src/params.c b/Src/params.c index 1a2bf62d2..fec1b2c02 100644 --- a/Src/params.c +++ b/Src/params.c @@ -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) { diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst index 30b6673e0..54f0aaf68 100644 --- a/Test/K01nameref.ztst +++ b/Test/K01nameref.ztst @@ -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 |
