diff options
| author | Philippe Altherr <philippe.altherr@gmail.com> | 2026-08-23 15:18:45 -0700 |
|---|---|---|
| committer | Bart Schaefer <schaefer@zsh.org> | 2026-08-23 15:18:45 -0700 |
| commit | fdc46ea6592f5c3e54c9c9dea5052768166a7a18 (patch) | |
| tree | e72fe87e831f7a39c367c82a6a46a6e741c330f6 | |
| parent | unposted: ChangeLog for previous eight commits (diff) | |
| download | zsh-fdc46ea6592f5c3e54c9c9dea5052768166a7a18.tar zsh-fdc46ea6592f5c3e54c9c9dea5052768166a7a18.tar.gz zsh-fdc46ea6592f5c3e54c9c9dea5052768166a7a18.tar.bz2 zsh-fdc46ea6592f5c3e54c9c9dea5052768166a7a18.tar.lz zsh-fdc46ea6592f5c3e54c9c9dea5052768166a7a18.tar.xz zsh-fdc46ea6592f5c3e54c9c9dea5052768166a7a18.tar.zst zsh-fdc46ea6592f5c3e54c9c9dea5052768166a7a18.zip | |
55109: remove obsolete nameref-specific code from typeset_single
Test changes here are for extra coverage, previous tests still pass
| -rw-r--r-- | Src/builtin.c | 60 | ||||
| -rw-r--r-- | Test/B02typeset.ztst | 91 | ||||
| -rw-r--r-- | Test/K01nameref.ztst | 30 | ||||
| -rw-r--r-- | Test/V10private.ztst | 135 |
4 files changed, 217 insertions, 99 deletions
diff --git a/Src/builtin.c b/Src/builtin.c index 4d47227ab..64a27511f 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2105,22 +2105,22 @@ typeset_single(char *cname, char *pname, Param pm, int func, } tc = 1; if (OPT_MINUS(ops,'p')) - usepm = (on & pm->node.flags); + usepm = !!(on & pm->node.flags); else if (OPT_PLUS(ops,'p')) - usepm = (off & pm->node.flags); + usepm = !!(off & pm->node.flags); else usepm = 0; } else if (usepm || newspecial != NS_NONE) { int chflags = ((off & pm->node.flags) | (on & ~pm->node.flags)) & (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED| - PM_ARRAY|PM_TIED|PM_AUTOLOAD); + PM_ARRAY|PM_NAMEREF|PM_TIED|PM_AUTOLOAD); /* keep the parameter if just switching between floating types */ if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT))) { if (OPT_MINUS(ops,'p')) - usepm = (on & pm->node.flags); + usepm = !!(on & pm->node.flags); else if (OPT_PLUS(ops,'p')) - usepm = (off & pm->node.flags); + usepm = !!(off & pm->node.flags); else usepm = 0; } @@ -2232,6 +2232,7 @@ typeset_single(char *cname, char *pname, Param pm, int func, * ii. we are creating a new local parameter */ if (usepm) { + int flags = (on & PM_NAMEREF) ? ASSPM_NONAMEREF : 0; if (OPT_MINUS(ops,'p') && on && !((on & pm->node.flags) || ((on & PM_LOCAL) && pm->level))) return NULL; @@ -2326,10 +2327,10 @@ typeset_single(char *cname, char *pname, Param pm, int func, DPUTS(!tdp, "BUG: no join character to update"); } if (asg->value.scalar && - !(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0))) + !(pm = assignsparam(pname, ztrdup(asg->value.scalar), flags))) return NULL; } else if (asg->flags & ASG_ARRAY) { - int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0; + flags |= (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0; if (!(pm = assignaparam(pname, asg->value.array ? zlinklist2array(asg->value.array, 1) : mkarray(NULL), flags))) @@ -2360,6 +2361,9 @@ typeset_single(char *cname, char *pname, Param pm, int func, on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->node.flags; /* ...but turn off existing readonly so we can delete it */ pm->node.flags &= ~PM_READONLY; + /* Hack to force getsparam below to use the reference's own value */ + if (off & PM_NAMEREF) + pm->node.flags &= ~PM_NAMEREF; /* * If we're just changing the type, we should keep the * variable at the current level of localness. @@ -2373,6 +2377,12 @@ typeset_single(char *cname, char *pname, Param pm, int func, * implications.) */ if (!ASG_VALUEP(asg) && !((pm->node.flags|on) & (PM_ARRAY|PM_HASHED))) { + /* + * Relying on pname is fundamentally wrong. If the original pm was + * a reference, the resolved pname may refer to a hidden parameter. + * In that case, getsparam wrongly returns the value of the hiding + * parameter. + */ asg->value.scalar = dupstring(getsparam(pname)); asg->flags = 0; } @@ -3117,42 +3127,6 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) continue; } - if (on & PM_NAMEREF) { - if (asg->value.scalar && - ((pm = (Param)paramtab->getnode(paramtab, asg->value.scalar)) && - (pm->node.flags & PM_NAMEREF))) { - if (pm->node.flags & PM_SPECIAL) { - zwarnnam(name, "%s: invalid reference", pm->node.nam); - returnval = 1; - continue; - } - } - if (hn) { - /* namerefs always start over fresh */ - if (((Param)hn)->level >= locallevel || - (!(on & PM_LOCAL) && ((Param)hn)->level < locallevel)) { - Param oldpm = (Param)hn; - if (!asg->value.scalar && - PM_TYPE(oldpm->node.flags) == PM_SCALAR && - oldpm->u.str) - asg->value.scalar = dupstring(oldpm->u.str); - /* Defer read-only error to typeset_single() */ - if (!(hn->flags & PM_READONLY)) { - unsetparam_pm(oldpm, 0, 1); - hn = NULL; - } - } - /* Passing a NULL pm to typeset_single() makes the - * nameref read-only before assignment, which breaks - * typeset -rn ref=var - * so this is special-cased to permit that action - * like assign-at-create for other parameter types. - */ - if (hn && !(hn->flags & PM_READONLY)) - hn = NULL; - } - } - if (!typeset_single(name, asg->name, (Param)hn, func, on, off, roff, asg, NULL, ops, 0)) diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst index 6f2deab53..6bc53c68a 100644 --- a/Test/B02typeset.ztst +++ b/Test/B02typeset.ztst @@ -1240,6 +1240,97 @@ F:This is a bug, the non -h variable should not hide the autoload variable >z= >v= + zmodload -u zsh/random + () { { typeset -g -i SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -g -a SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -g -n SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } } + echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*} +0:Global parameter can't change type of autoloaded parameter +>(anon):typeset: SRANDOM: can't change type of autoloaded parameter +>(anon):typeset: SRANDOM: can't change type of autoloaded parameter +>(anon):typeset: SRANDOM: can't change type of autoloaded parameter +>z=SRANDOM (zsh/random) + + zmodload -u zsh/random + () { { typeset SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -i SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -a SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -n SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } } + echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*} +0:Local non -h parameter can hide autoloaded parameter +>z=SRANDOM (zsh/random) + + () { { typeset -g +i EUID 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -g -i HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -g -a HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } } + ( () { { typeset -g -n HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } } ) + typeset -p EUID HOME +0q:Global parameter can't change type of special parameter +>(anon):typeset: EUID: can't change type of a special parameter +>(anon):typeset: HOME: can't change type of a special parameter +>(anon):typeset: HOME: can't change type of a special parameter +>(anon):typeset: HOME: can't change type of a special parameter +>typeset -g -i10 EUID=$EUID +>export HOME=$HOME + + () { { typeset +i EUID 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -i HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -a HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } } + () { { typeset -n HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } } + typeset -p EUID HOME +0q:Local non -h parameter can't hide special parameter +>(anon):typeset: EUID: can't change type of a special parameter +>(anon):typeset: HOME: can't change type of a special parameter +>(anon):typeset: HOME: can't change type of a special parameter +>(anon):typeset: HOME: can't change type of a special parameter +>typeset -g -i10 EUID=$EUID +>export HOME=$HOME + + () { typeset -h +i EUID 2>&1; typeset -p EUID } + () { typeset -h -i HOME 2>&1; typeset -p HOME } + () { typeset -h -a HOME 2>&1; typeset -p HOME } + () { typeset -h -n HOME 2>&1; typeset -p HOME } + typeset -p EUID HOME +0q:Local -h parameter can hide special parameter +>typeset -h EUID='' +>typeset -ih HOME=0 +>typeset -ah HOME=( ) +>typeset -hn HOME='' +>typeset -g -i10 EUID=$EUID +>export HOME=$HOME + + check() { + echo "Testing \"local $1 $2=${3}<N>\"" + { local $1 -r $2=${3}1 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 } + { local -r $2=${3}2 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 } + { local $1 $2=${3}3 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 } + { local $1 -r $2=${3}4 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 } + { local $1 +r $2=${3}5 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 } + } + check "" str s + check -i int 1 + check -n ref v +0:Non +r parameter definition can't change/replace readonly parameter +>Testing "local str=s<N>" +>typeset -r str=s1 +>check:3: read-only variable: str +>check:4: read-only variable: str +>check:5: read-only variable: str +>typeset str=s5 +>Testing "local -i int=1<N>" +>typeset -ir int=11 +>check:3: read-only variable: int +>check:4: read-only variable: int +>check:5: read-only variable: int +>typeset -i int=15 +>Testing "local -n ref=v<N>" +>typeset -rn ref=v1 +>typeset -rn ref=v1 +F:"typeset -r ref=v2" succeeds because it dereferences "ref" and assigns "v1" with "v2" +>check:local:4: ref: read-only reference +>check:local:5: ref: read-only reference +>typeset -n ref=v5 + () { typeset -F f1=nan f2=inf f3=-inf typeset -p f1 f2 f3 diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst index 342edf5a4..a0706ec0f 100644 --- a/Test/K01nameref.ztst +++ b/Test/K01nameref.ztst @@ -1107,32 +1107,30 @@ F:Checking for a bug in zmodload that affects later tests unset -n ref typeset -rn ref=RO typeset -p ref - (typeset -n ref=RW) + (typeset -n ref=RW 2>&1 && typeset -p ref) print status: $? expected: 1 typeset +r -n ref typeset -p ref typeset -r +n ref typeset -p ref - (typeset -rn ref) - print status: $? expected: 1 - typeset +r -n ref=RW # Assignment occurs after type change, - typeset -p ref RO # so RO=RW here. Potentially confusing. - typeset -r -n ref=RX # No type change, so referent changes ... - typeset -p ref RO # ... and previous refererent does not. - typeset +rn ref=RW # Here ref=RW, again type changed first. + (typeset -rn ref 2>&1 && typeset -p ref) + print status: $? expected: 0 + typeset +r -n ref=RW + typeset -p ref + typeset -r -n ref=RX + typeset -p ref + typeset +rn ref=RW typeset -p ref 0:add and remove readonly attribute with references >typeset -rn ref=RO -*?*: ref: read-only reference +>(eval):typeset:4: ref: read-only reference >status: 1 expected: 1 >typeset -n ref=RO >typeset -r ref=RO -*?*: ref: read-only variable ->status: 1 expected: 1 ->typeset -n ref=RO ->typeset -g RO=RW +>typeset -rn ref=RO +>status: 0 expected: 0 +>typeset -n ref=RW >typeset -rn ref=RX ->typeset -g RO=RW >typeset ref=RW () { @@ -2362,13 +2360,13 @@ F:converting from association/array to string should work here too show '${refX}' ${(q!)refU} ${(q!)refN} ${(q!)refS} show '${var}' ${var} echo - typeset -n refU refN="" refS=var + unset -n refU; typeset -n refU refN="" refS=var show '${refX:-ccc}' ${(q!)refU:-ccc} ${(q!)refN:-ccc} ${(q!)refS:-ccc} show '${refX:=ccc}' ${(q!)refU:=ccc} ${(q!)refN:=ccc} ${(q!)refS:=ccc} show '${refX}' ${(q!)refU} ${(q!)refN} ${(q!)refS} show '${var}' ${var} echo - typeset -n refU refN="" refS=var + unset -n refU; typeset -n refU refN="" refS=var show '${refX::=ddd}' ${(q!)refU::=ddd} ${(q!)refN::=ddd} ${(q!)refS::=ddd} show '${refX}' ${(q!)refU} ${(q!)refN} ${(q!)refS} show '${var}' ${var} diff --git a/Test/V10private.ztst b/Test/V10private.ztst index 256844be1..f3ad7b6b9 100644 --- a/Test/V10private.ztst +++ b/Test/V10private.ztst @@ -304,39 +304,44 @@ F:future revision will create a global with this assignment typeset top=TOP () { local -P -n test=top - print $top + print $test + test=top + print $test () { print UP: $test } } + print $top 0:nameref can be declared private >TOP +>top >UP: +>top () { typeset -a ary local -P -n ref=ary { - (){ - ref=XX # Should be an error - typeset -p ary ref + () { + ref=XX 2>&1 # Should be an error + echo NOT REACHED } } always { TRY_BLOCK_ERROR=0 typeset -p ary ref } } - typeset -p ary + typeset -p ary 2>&1 1:assignment to private nameref in wrong scope, part 1 +>(anon):1: ref: can't modify read-only parameter >typeset -a ary >typeset -hn ref=ary -*?*ref: can't modify read-only parameter -*?*no such variable: ary +>(eval):typeset:14: no such variable: ary () { typeset -a ary local -P -n ref=ary { (){ - typeset ref=XX # Should create a local + typeset ref=XX 2>&1 # Should create a local typeset -p ary ref } } always { @@ -344,53 +349,89 @@ F:future revision will create a global with this assignment typeset -p ary ref } } - typeset -p ary + typeset -p ary 2>&1 1:assignment to private nameref in wrong scope, part 2 >typeset -g -a ary >typeset ref=XX >typeset -a ary >typeset -hn ref=ary -*?*no such variable: ary +>(eval):typeset:14: no such variable: ary () { + typeset val=LOCAL typeset -n ptr1=ptr2 private -n ptr2 # TYPESET_TO_UNSET makes this not a "placeholder" typeset -p ptr1 ptr2 - typeset val=LOCAL () { - ptr1=val # Test dies here as ptr2 is private and unset - typeset -n - printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" + ptr1=val 2>&1 # Test dies here as ptr2 is private + echo NOT REACHED } - typeset -p ptr1 ptr2 + echo NOT REACHED } - typeset -p ptr2 + echo NOT REACHED 1:up-reference for private namerefs, end unset and not in scope F:See K01nameref.ztst up-reference part 5 F:Here ptr1 finds private ptr2 by scope mismatch >typeset -n ptr1=ptr2 >typeset -hn ptr2 -?(anon):1: read-only variable: ptr2 +>(anon):1: read-only variable: ptr2 () { + typeset val=LOCAL typeset -n ptr1=ptr2 private -n ptr2= # Assignment makes this a placeholder, not unset typeset -p ptr1 ptr2 + () { + ptr1=val 2>&1 # Test dies here as ptr2 is private + echo NOT REACHED + } + echo NOT REACHED + } + echo NOT REACHED +1:up-reference for private namerefs, end is placeholder and not in scope +F:See K01nameref.ztst up-reference part 5 +F:Here ptr1 finds private ptr2 by scope mismatch +>typeset -n ptr1=ptr2 +>typeset -hn ptr2='' +>(anon):1: ptr1: can't modify read-only parameter + + () { typeset val=LOCAL + typeset -n ptr1=ptr2 + private -n ptr2=val # Assignment makes this a reference to existing val + typeset -p ptr1 ptr2 () { - ptr1=val # Test dies here as ptr2 is private and uninitialized - typeset -n - printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" + ptr1=val 2>&1 # Test dies here as ptr2 is private + echo NOT REACHED } + echo NOT REACHED + } + echo NOT REACHED +1:up-reference for private namerefs, end refers existing variable and not in scope +F:See K01nameref.ztst up-reference part 5 +F:Here ptr1 finds private ptr2 by scope mismatch +>typeset -n ptr1=ptr2 +>typeset -hn ptr2=val +>(anon):1: ptr1: can't modify read-only parameter + + () { + typeset val=LOCAL + typeset -n ptr1=ptr2 + private -n ptr2=foo # Assignment makes this a reference to not-yet-defined foo typeset -p ptr1 ptr2 + () { + ptr1=val 2>&1 # Test dies here as ptr2 is private + echo NOT REACHED + } + echo NOT REACHED } - typeset -p ptr2 -1:up-reference for private namerefs, end not in scope + echo NOT REACHED +1:up-reference for private namerefs, end refers not-yet-defined variable and not in scope F:See K01nameref.ztst up-reference part 5 F:Here ptr1 finds private ptr2 by scope mismatch >typeset -n ptr1=ptr2 ->typeset -hn ptr2='' -?(anon):1: ptr1: can't modify read-only parameter +>typeset -hn ptr2=foo +>(anon):1: ptr1: can't modify read-only parameter typeset ptr2 () { @@ -401,7 +442,7 @@ F:Here ptr1 finds private ptr2 by scope mismatch () { ptr1=val typeset -n - printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" + printf "print:%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" } typeset -p ptr1 ptr2 } @@ -413,24 +454,38 @@ F:Here ptr1 points to global ptr2 so assignment succeeds >typeset -hn ptr2 >ptr1=ptr2 >ptr2=val ->ptr1=val ->ptr2=val +>print:ptr1=val +>print:ptr2=val >typeset -n ptr1=ptr2 >typeset -hn ptr2 >typeset ptr2=val () { setopt localoptions errreturn + private -n ptr2=val + typeset -n ptr1=ptr2 2>&1 + ptr1=foo + typeset -p ptr1 ptr2 val + } + unset val +0:up-reference for private namerefs, end is set and in scope but private +>typeset -n ptr1=ptr2 +>typeset -hn ptr2=val +>typeset -g val=foo + + () { + setopt localoptions errreturn private -n ptr2 - typeset -n ptr1=ptr2 - echo NOT REACHED + typeset -n ptr1=ptr2 2>&1 + ptr1=val + ptr1=foo + typeset -p ptr1 ptr2 val } - typeset -p ptr1 ptr2 -1:up-reference for private namerefs, end is in scope but private -F:Should we allow "public" namerefs to private parameters? -*?*ptr2: invalid reference -*?*no such variable: ptr1 -*?*no such variable: ptr2 + unset val +0:up-reference for private namerefs, end is unset and in scope but private +>typeset -n ptr1=ptr2 +>typeset -hn ptr2=val +>typeset -g val=foo () { typeset ptr2=foo @@ -438,13 +493,13 @@ F:Should we allow "public" namerefs to private parameters? () { setopt localoptions errreturn private -n ptr2 - typeset -n ptr1=ptr2 - echo NOT REACHED + typeset -n ptr1=ptr2 2>&1 + typeset -p ptr1 ptr2 } } -1:regression test for invalid reference detection -F:Should we allow "public" namerefs to private parameters? -*?*ptr2: invalid reference +0:regression test for invalid reference detection +>typeset -n ptr1=ptr2 +>typeset -hn ptr2 () { private x=1 |
