diff options
| author | Philippe Altherr <philippe.altherr@gmail.com> | 2025-10-26 16:52:51 -0700 |
|---|---|---|
| committer | Bart Schaefer <schaefer@zsh.org> | 2025-10-26 16:52:51 -0700 |
| commit | e1fed5439c5fb844a028af3ac58d5032cc307df7 (patch) | |
| tree | 6e11cfa88243536345729caeeb38ab4c8af78adb | |
| parent | 53781: fix loading of autoload variable via a reference (diff) | |
| download | zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.gz zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.bz2 zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.lz zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.xz zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.zst zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.zip | |
53782: Src/params.c, Test/K01nameref.ztst: changes to nameref base level:
- avoid changing base on assignment;
- omit base level for up-scope references
- do not follow reference chains for base level of new references
| -rw-r--r-- | ChangeLog | 11 | ||||
| -rw-r--r-- | Src/params.c | 90 | ||||
| -rw-r--r-- | Test/K01nameref.ztst | 53 |
3 files changed, 103 insertions, 51 deletions
@@ -1,8 +1,15 @@ 2025-10-26 Bart Schaefer <schaefer@zsh.org> - * Philippe: 53732: avoid tail-call exec in always block + * Philippe: 53732: Src/loop.c, Test/A01grammar.ztst: avoid tail-call + exec in always block - * Philippe: 53781: fix loading of autoload variable via a reference + * Philippe: 53781: Src/params.c, Test/B02typeset.ztst, + Test/K01nameref.ztst: fix load of autoload variable via a reference + + * Philippe: 53782: Src/params.c, Test/K01nameref.ztst: changes to + handling of nameref base level: avoid changing base on assignment; + omit base level for up-scope references; do not follow reference + chains when computing base level of new references 2025-10-24 Oliver Kiddle <opk@zsh.org> diff --git a/Src/params.c b/Src/params.c index 70042a417..6945e73e9 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2239,10 +2239,10 @@ fetchvalue(Value v, char **pptr, int bracks, int flags) } Param p1 = (Param)gethashnode2(paramtab, ref); if (p1) { - int scope = ((pm->node.flags & PM_NAMEREF) ? - ((pm->node.flags & PM_UPPER) ? -(pm->base) : - pm->base) : locallevel); - pm = upscope(p1, scope); + if (pm->node.flags & PM_UPPER) + pm = upscope_upper(p1, pm->level - 1); + else + pm = upscope(p1, pm->base); pm = (Param)loadparamnode(paramtab, pm, ref); } if (!(p1 && pm) || @@ -3324,7 +3324,11 @@ assignsparam(char *s, char *val, int flags) } } + if (v->pm->node.flags & PM_NAMEREF) + v->pm->node.flags |= PM_NEWREF; assignstrvalue(v, val, flags); + if (v->pm->node.flags & PM_NAMEREF) + v->pm->node.flags &= ~PM_NEWREF; unqueue_signals(); return v->pm; } @@ -6314,12 +6318,13 @@ resolve_nameref(Param pm, const Asgment stop) } else if ((hn = gethashnode2(realparamtab, seek))) { if (pm) { if (!(stop && (stop->flags & (PM_LOCAL)))) { - int scope = ((pm->node.flags & PM_NAMEREF) ? - ((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); + if ((pm->node.flags & PM_NAMEREF) && + (pm->node.flags & PM_UPPER)) + hn = (HashNode)upscope_upper((Param)hn, pm->level - 1); + else + hn = (HashNode)upscope((Param)hn, + (pm->node.flags & PM_NAMEREF) ? + (pm->base) : ((Param)hn)->level); } hn = loadparamnode(paramtab, (Param)hn, seek); /* user can't tag a nameref, safe for loop detection */ @@ -6374,12 +6379,37 @@ setscope(Param pm) char *t = refname ? itype_end(refname, INAMESPC, 0) : NULL; int q = queue_signal_level(); + /* Compute pm->width */ /* Temporarily change nameref to array parameter itself */ if (t && *t == '[') *t = 0; else t = 0; - stop.name = ""; + if (t) { + pm->width = t - refname; + *t = '['; + refname = dupstrpfx(refname, pm->width); + } + + /* Compute pm->base */ + if (!(pm->node.flags & PM_UPPER) && refname && + (basepm = (Param)gethashnode2(realparamtab, refname)) && + (basepm = (Param)loadparamnode(realparamtab, basepm, refname)) && + (!(basepm->node.flags & PM_NEWREF) || (basepm = basepm->old))) { + pm->base = basepm->level; + } + if (pm->base > pm->level) { + if (EMULATION(EMULATE_KSH)) { + zerr("%s: global reference cannot refer to local variable", + pm->node.nam); + unsetparam_pm(pm, 0, 1); + } else if (isset(WARNNESTEDVAR)) + zwarn("reference %s in enclosing scope set to local variable %s", + pm->node.nam, refname); + } + + /* Check for self references */ + stop.name = pm->node.nam; stop.value.scalar = NULL; stop.flags = PM_NAMEREF; if (locallevel && !(pm->node.flags & PM_UPPER)) @@ -6387,11 +6417,6 @@ setscope(Param pm) dont_queue_signals(); /* Prevent unkillable loops */ basepm = (Param)resolve_nameref(pm, &stop); restore_queue_signals(q); - if (t) { - pm->width = t - refname; - *t = '['; - refname = dupstrpfx(refname, pm->width); - } if (basepm) { if (basepm->node.flags & PM_NAMEREF) { if (pm == basepm) { @@ -6419,27 +6444,7 @@ setscope(Param pm) break; } } - } else if (!pm->base) { - pm->base = basepm->level; - if ((pm->node.flags & PM_UPPER) && - (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, -(pm->level)))) - pm->base = basepm->level; - } - if (pm->base > pm->level) { - if (EMULATION(EMULATE_KSH)) { - zerr("%s: global reference cannot refer to local variable", - pm->node.nam); - unsetparam_pm(pm, 0, 1); - } else if (isset(WARNNESTEDVAR)) - zwarn("reference %s in enclosing scope set to local variable %s", - pm->node.nam, refname); } if (refname && upscope(pm, pm->base) == pm && strcmp(pm->node.nam, refname) == 0) { @@ -6456,13 +6461,18 @@ upscope(Param pm, int reflevel) { Param up = pm->old; while (up && up->level >= reflevel) { - if (reflevel < 0 && up->level < -(reflevel)) - break; pm = up; up = up->old; } - if (reflevel < 0 && locallevel > 0) - return pm->level == locallevel ? up : pm; + return pm; +} + +/**/ +mod_export Param +upscope_upper(Param pm, int reflevel) +{ + while (pm && pm->level > reflevel) + pm = pm->old; return pm; } diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst index 52aed0af0..b03487d03 100644 --- a/Test/K01nameref.ztst +++ b/Test/K01nameref.ztst @@ -1100,15 +1100,15 @@ 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=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 +>i:2: rs=f - ra=f - rs1=f - ra1=f +>j:1: rs=f - ra=f - rs1=f - ra1=f +>j:2: rs=f - ra=f - rs1=f - ra1=f +>i:3: rs=f - ra=f - rs1=f - ra1=f +>k:1: rs=f - ra=f - rs1=f - ra1=f +>k:2: rs=f - ra=f - rs1=f - ra1=f +>h:3: rs=f - ra=f - rs1=f - ra1=f +>k:1: rs=f - ra=f - rs1=f - ra1=f +>k:2: rs=f - ra=f - rs1=f - ra1=f >g:3: rs=f - ra=f - rs1=f - ra1=f e '' 6 @@ -1237,4 +1237,39 @@ F:previously this could create an infinite recursion and crash ?(eval):zsh/random:6: error when adding parameter `SRANDOM' ?(eval):6: autoloading module zsh/random failed to define parameter: SRANDOM + () { + typeset var1=var1 + typeset var2=var2 + typeset -n ref1=var1 + echo "ref1=$ref1"; + () { + typeset -n ref1=var2 + typeset -n ref2=ref1 + echo "ref1=$ref1"; + echo "ref2=$ref2"; + } + } +0:regression: don't follow references when computing base scope - part 1 +>ref1=var1 +>ref1=var2 +>ref2=var2 + + () { + typeset var1=var1 + typeset -n ref1=var1 + echo ref1=$ref1; + () { + typeset var2=var2 + typeset -n ref1 + typeset -n ref2=ref1 + ref1=var2 + echo ref1=$ref1; + echo ref2=$ref2; + } + } +0:regression: don't follow references when computing base scope - part 2 +>ref1=var1 +>ref1=var2 +>ref2=var2 + %clean |
